Skip to content

A simple template that can be used to get started with an efficient literate Emacs configuration

Notifications You must be signed in to change notification settings

MArpogaus/emacs.d

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Emacs Literate Configuration

Configuration

Table of Contents

References

This Emacs literate configuration has been inspired by the following projects:

Notes

Add git url to pkg headlines

for p in $(grep -P '^\*\*\*\* ([a-z\-])*$' emacs.org | cut -d ' ' -f 2); do
    url=$(git -C ~/.emacs.d/straight/repos/*$p* remote get-url origin)
    if [ $? -eq 0 ]; then
        sed "s|\*\*\*\* $p|**** [[$url][$p]]|" -i emacs.org
    fi;
done

Common Header for Emacs Libraries

Library Headers (GNU Emacs Lisp Reference Manual)

echo ";;; $file_name --- Emacs configuration file  -*- lexical-binding: t; -*-
;; Copyright (C) 2023-$(date +%Y) Marcel Arpogaus

;; Author: Marcel Arpogaus
;; Created: $(date -I)
;; Keywords: configuration
;; Homepage: https://github.com/MArpogaus/emacs.d/

;; This file is not part of GNU Emacs.

;;; Commentary:

;; This file has been generated from emacs.org file. DO NOT EDIT.

;;; Code:"

Early Emacs Initialization

:header-args+: :tangle early-init.elThis file serves as the initial configuration file for Emacs and aims to establish fundamental settings before Emacs generates the initial frame. It should only consist of code that is independent of any package.

Conventional Library Header

<<header(file_name="early-init.el")>>

Configure Byte Compile

;; If an `.el' file is newer than its corresponding `.elc', load the `.el'.
(setq load-prefer-newer t)

;; Disable certain byte compiler warnings to cut down on the noise.
(setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))

Optimize Startup Time

We’re going to increase the gc-cons-threshold to a very high number to decrease the load time and add a hook to measure Emacs startup time.

The following optimisatzion have been inspired by:

(setq gc-cons-threshold most-positive-fixnum
      gc-cons-percentage 0.6)
;; Let's lower our GC thresholds back down to a sane level.
(add-hook 'after-init-hook (lambda ()
                             ;; restore after startup
                             (setq gc-cons-threshold (* 2 1000 1000)
                                   gc-cons-percentage 0.1)))

;; Profile emacs startup
(add-hook 'emacs-startup-hook
          (lambda ()
            (message "*** Emacs loaded in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract after-init-time before-init-time)))
                     gcs-done)))

;; Resizing the Emacs frame can be a terribly expensive part of changing the
;; font. By inhibiting this, we easily halve startup times with fonts that are
;; larger than the system default.
(setq frame-inhibit-implied-resize t
      frame-resize-pixelwise t)

;; Ignore X resources; its settings would be redundant with the other settings
;; in this file and can conflict with later config (particularly where the
;; cursor color is concerned).
(advice-add #'x-apply-session-resources :override #'ignore)

;; Unset `file-name-handler-alist' too (temporarily). Every file opened and
;; loaded by Emacs will run through this list to check for a proper handler for
;; the file, but during startup, it won’t need any of them.
(defvar file-name-handler-alist-old file-name-handler-alist)
(setq file-name-handler-alist nil)
(add-hook 'emacs-startup-hook
          (lambda ()
            (setq file-name-handler-alist file-name-handler-alist-old)))

;; Remove irreleant command line options for faster startup
(setq command-line-x-option-alist nil)

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

DOOM runtime optimizations

The following optimizations have been taken from here.

;; PERF: A second, case-insensitive pass over `auto-mode-alist' is time wasted.
(setq auto-mode-case-fold nil)

;; PERF: Disable bidirectional text scanning for a modest performance boost.
;;   I've set this to `nil' in the past, but the `bidi-display-reordering's docs
;;   say that is an undefined state and suggest this to be just as good:
(setq-default bidi-display-reordering 'left-to-right
              bidi-paragraph-direction 'left-to-right)

;; PERF: Disabling BPA makes redisplay faster, but might produce incorrect
;;   reordering of bidirectional text with embedded parentheses (and other
;;   bracket characters whose 'paired-bracket' Unicode property is non-nil).
(setq bidi-inhibit-bpa t)  ; Emacs 27+ only

;; Reduce rendering/line scan work for Emacs by not rendering cursors or regions
;; in non-focused windows.
(setq-default cursor-in-non-selected-windows nil)
(setq highlight-nonselected-windows nil)

;; Don't ping things that look like domain names.
(setq ffap-machine-p-known 'reject)

;; Emacs "updates" its ui more often than it needs to, so slow it down slightly
(setq idle-update-delay 1.0)  ; default is 0.5

;; Font compacting can be terribly expensive, especially for rendering icon
;; fonts on Windows. Whether disabling it has a notable affect on Linux and Mac
;; hasn't been determined, but do it anyway, just in case. This increases memory
;; usage, however!
(setq inhibit-compacting-font-caches t)

;; PGTK builds only: this timeout adds latency to frame operations, like
;; `make-frame-invisible', which are frequently called without a guard because
;; it's inexpensive in non-PGTK builds. Lowering the timeout from the default
;; 0.1 should make childframes and packages that manipulate them (like `lsp-ui',
;; `company-box', and `posframe') feel much snappier. See emacs-lsp/lsp-ui#613.
(when (boundp 'pgtk-wait-for-event-timeout)
  (setq pgtk-wait-for-event-timeout 0.001))

;; Introduced in Emacs HEAD (b2f8c9f), this inhibits fontification while
;; receiving input, which should help a little with scrolling performance.
(setq redisplay-skip-fontification-on-input t)

Configure Straight

This section provides the bootstrap code for straight.el, a package manager for Emacs. The code includes optimization for startup time, disables file modification checking for performance, and loads the straight.el bootstrap file, which contains essential functionality.

;; prevent package.el loading packages prior to their init-file loading.
(setq package-quickstart nil
      package-enable-at-startup nil)

;; straight.el bootstrap code
;;disable checking (for speedup).
(setq straight-check-for-modifications nil)

;; cache the autoloads of all used packages in a single file
(setq straight-cache-autoloads t)

;; Enable straight use-package integration
(setq straight-use-package-by-default t
      use-package-always-defer t)

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 6))
  (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))

Conventional Library Footer

(provide 'early-init)
;;; early-init.el ends here

Emacs Initialization

:header-args+: :tangle init.elThe main initialization file, init.el, is responsible for defining essential configurations and variables used in submodules.

Conventional Header

<<header(file_name="init.el")>>

Package Management

Lets install and configure use-package and use straight as the underlying package manager. We also load bind-key here which is used by use-package for keybindings.

(when (< emacs-major-version 29)
  (straight-use-package 'use-package)
  (use-package bind-key))

;; make use-package more verbose when ´‘--debug-init´ is passed
;; https://www.gnu.org/software/emacs/manual/html_node/use-package/Troubleshooting.html
(when init-file-debug
  (setq use-package-verbose t
        use-package-expand-minimally nil
        use-package-compute-statistics t
        debug-on-error t))

Benchmark startup

(use-package benchmark-init
  :demand t
  ;; To disable collection of benchmark data after init is done.
  :config
  (add-hook 'after-init-hook #'benchmark-init/deactivate 99))

Personal Information

Let’s set some variables with basic user information.

(setq user-full-name "Marcel Arpogaus"
      user-mail-address "znepry.necbtnhf@tznvy.pbz")

Paths

Use no-littering to automatically set common paths to the new user-emacs-directory ~/.cache/emacs..

(use-package no-littering
  :demand t
  :init
  (setq org-directory (expand-file-name "Notes/org/" (getenv "HOME"))
        org-cite-global-bibliography (file-expand-wildcards (expand-file-name "bib/*.bib" org-directory))
        org-brain-path (expand-file-name "brain/" org-directory)
        my/templates-path (expand-file-name "templates.eld" user-emacs-directory)
        ;; Since init.el will be generated from this file, we save customization in a dedicated file.
        custom-file (expand-file-name "custom.el" user-emacs-directory))

  ;; Change the user-emacs-directory to keep unwanted things out of ~/.emacs.d
  (setq user-emacs-directory (expand-file-name "~/.cache/emacs/"))

  :config
  ;; store backup and auto-save files in =no-littering-var-directory=
  (no-littering-theme-backups))

Better Defaults

(use-package emacs
  :straight nil
  :preface
  (defun my/backward-kill-thing ()
    "Delete sexp, symbol, word or whitespace backward depending on the context at point."
    (interactive)
    (let ((bounds (seq-some #'bounds-of-thing-at-point '(sexp symbol word))))
      (cond
       ;; If there are bounds and point is within them, kill the region
       ((and bounds (< (car bounds) (point)))
        (kill-region (car bounds) (point)))

       ;; If there's whitespace before point, delete it
       ((thing-at-point-looking-at "\\([ \n]+\\)")
        (if (< (match-beginning 1) (point))
            (kill-region (match-beginning 1) (point))
          (kill-backward-chars 1)))

       ;; If none of the above, delete one character backward
       (t
        (kill-backward-chars 1)))))
  :bind
  ("C-<backspace>" . my/backward-kill-thing)
  :custom
  ;; Startup
  ;; Emacs does a lot of things at startup and here, we disable pretty much everything.
  (inhibit-startup-screen t)                           ; Disable start-up screen
  (inhibit-startup-message t)                          ; Disable startup message
  (inhibit-startup-echo-area-message t)                ; Disable initial echo message
  (initial-scratch-message "")                         ; Empty the initial *scratch* buffer

  ;; Encoding
  ;; We tell emacs to use UTF-8 encoding as much as possible.
  (set-default-coding-systems 'utf-8)                  ; Default to utf-8 encoding
  (prefer-coding-system       'utf-8)                  ; Add utf-8 at the front for automatic detection.
  (set-terminal-coding-system 'utf-8)                  ; Set coding system of terminal output
  (set-keyboard-coding-system 'utf-8)                  ; Set coding system for keyboard input on TERMINAL
  (set-language-environment "English")                 ; Set up multilingual environment

  ;; Recovery
  ;; If Emacs or the computer crashes, you can recover the files you were editing at the time of the crash from their auto-save files. To do this, start Emacs again and type the command ~M-x recover-session~. Here, we parameterize how files are saved in the background.
  (auto-save-default t)                                ; Auto-save every buffer that visits a file
  (auto-save-timeout 10)                               ; Number of seconds between auto-save
  (auto-save-interval 200)                             ; Number of keystrokes between auto-saves

  ;; Dialogs
  ;; use simple text prompts
  (use-dialog-box nil)                                 ; Don't pop up UI dialogs when prompting
  (use-file-dialog nil)                                ; Don't use UI dialogs for file search
  (use-short-answers t)                                ; Replace yes/no prompts with y/n
  (confirm-nonexistent-file-or-buffer nil)             ; Ok to visit non existent files

  ;; Mouse
  ;; Mouse behavior can be finely controlled using mouse-avoidance-mode.
  (context-menu-mode (display-graphic-p))              ; Enable context menu on right click
  (mouse-yank-at-point t)                              ; Yank at point rather than pointer
  (xterm-mouse-mode (not (display-graphic-p)))         ; Mouse active in tty mode.

  ;; Scroll
  ;; Smoother scrolling.
  (auto-window-vscroll nil)                            ; Disable automatic adjusting of =window-vscroll=
  (fast-but-imprecise-scrolling t)                     ; More performant rapid scrolling over unfontified region
  (hscroll-margin 1)                                   ; Reduce margin triggering automatic horizontal scrolling
  (hscroll-step 1)                                     ; Slower horizontal scrolling
  (mouse-wheel-scroll-amount '(1 ((shift) . hscroll))) ; Reduce vertical scroll speed
  (mouse-wheel-scroll-amount-horizontal 2)             ; Reduce horizontal scroll speed
  (pixel-scroll-precision-interpolate-mice nil)        ; Disable interpolation (causes wired jumps)
  (pixel-scroll-precision-mode (display-graphic-p))    ; Enable pixel-wise scrolling
  (pixel-scroll-precision-use-momentum t)              ; Enable momentum for scrolling lagre buffers
  (scroll-conservatively 101)                          ; Avoid recentering when scrolling far
  (scroll-preserve-screen-position t)                  ; Don't move point when scrolling

  ;; Cursor
  ;; We set the appearance of the cursor: horizontal line, 2 pixels thick, no blinking
  (cursor-type '(hbar . 2))                            ; Underline-shaped cursor
  (cursor-intangible-mode t)                           ; Enforce cursor intangibility
  (x-stretch-cursor nil)                               ; Don't stretch cursor to the glyph width
  (blink-cursor-mode nil)                              ; Still cursor

  ;; Typography
  (fill-column 80)                                     ; Default line width
  (sentence-end-double-space nil)                      ; Use a single space after dots
  (truncate-string-ellipsis "")                       ; Nicer ellipsis

  ;; Default mode
  ;; Default & initial mode is text.
  (initial-major-mode 'text-mode)                      ; Initial mode is text
  (default-major-mode 'text-mode)                      ; Default mode is text

  ;; Tabulations
  ;; No tabulation, ever.
  (indent-tabs-mode nil)                               ; Stop using tabs to indent

  ;; Performance
  ;; https://github.com/alexluigit/dirvish/blob/main/docs/.emacs.d.example/early-init.el
  (fast-but-imprecise-scrolling t)                     ; More performant rapid scrolling over unfontified regions
  (frame-inhibit-implied-resize t)                     ; Inhibit frame resizing for performance
  (read-process-output-max (* 1024 1024))              ; Increase how much is read from processes in a single chunk.
  (select-active-regions 'only)                        ; Emacs hangs when large selections contain mixed line endings.

  ;; Miscellaneous
  (native-comp-async-report-warnings-errors nil)       ; disable native compiler warnings
  (fringes-outside-margins t)                          ; DOOM: add some space between fringe it and buffer.
  (window-resize-pixelwise t)                          ; Resize windows pixelwise
  (frame-resize-pixelwise t)                           ; Resize frame pixelwise
  (windmove-mode nil)                                  ; Diasble windmove mode
  :preface
  ;; History
  ;; Remove text properties for kill ring entries (see https://emacs.stackexchange.com/questions/4187). This saves a lot of time when loading it.
  (defun unpropertize-kill-ring ()
    (setq kill-ring (mapcar 'substring-no-properties kill-ring)))
  :init
  (modify-all-frames-parameters '((width . 200)
                                  (height . 50)))
  :config
  ;; Load customization File
  (load custom-file 'noerror 'nomessage)

  ;; Remove binding to view-echo-area-messages when clicking on inactive minibuffer
  (define-key minibuffer-inactive-mode-map (kbd "<mouse-1>") nil t)
  :bind
  ;;ESC Cancels All
  (("<escape>" . keyboard-escape-quit))
  :hook
  ;; Enable word wrapping
  (((prog-mode conf-mode text-mode) . visual-line-mode)
   (kill-emacs . unpropertize-kill-ring)))

Keymaps

This section initializes various keymaps used for different purposes.

;; setup keymaps
(use-package emacs
  :straight nil
  :preface
  (defvar my/leader-map (make-sparse-keymap) "key-map for leader key")
  (defvar my/version-control-map (make-sparse-keymap) "key-map for version control commands")
  (defvar my/completion-map (make-sparse-keymap) "key-map for completion commands")
  (defvar my/buffer-map (make-sparse-keymap) "key-map for buffer commands")
  (defvar my/buffer-scale-map (make-sparse-keymap) "key-map for buffer text scale commands")
  (defvar my/window-map (make-sparse-keymap) "key-map for window commands")
  (defvar my/file-map (make-sparse-keymap) "key-map for file commands")
  (defvar my/workspace-map (make-sparse-keymap) "key-map for workspace commands")
  (defvar my/toggle-map (make-sparse-keymap) "key-map for toggle commands")
  (defvar my/open-map (make-sparse-keymap) "key-map for open commands")
  (defvar my/lsp-map (make-sparse-keymap) "key-map for lsp commands")
  (defvar my/debug-map (make-sparse-keymap) "key-map for debug commands")
  :config
  ;; remove keybind for suspend-frame
  (global-unset-key (kbd "C-z"))

  ;; buffer keymap
  (define-key my/buffer-map "z" (cons "scale" my/buffer-scale-map))
  ;;    (define-key my/leader-map "x" (cons "C-x" ctl-x-map))

  ;; leader keymap
  (define-key my/leader-map "." (cons "completion" my/completion-map))
  (define-key my/leader-map "b" (cons "buffer" my/buffer-map))
  (define-key my/leader-map "d" (cons "debug" my/debug-map))
  (define-key my/leader-map "f" (cons "file" my/file-map))
  (define-key my/leader-map "g" (cons "goto" goto-map))
  (define-key my/leader-map "h" (cons "help" help-map))
  (define-key my/leader-map "l" (cons "lsp" my/lsp-map))
  (define-key my/leader-map "o" (cons "open" my/open-map))
  (define-key my/leader-map "p" (cons "project" project-prefix-map))
  (define-key my/leader-map "s" (cons "search" search-map))
  (define-key my/leader-map "t" (cons "toggle" my/toggle-map))
  (define-key my/leader-map "v" (cons "version-control" my/version-control-map))
  (define-key my/leader-map "w" (cons "window" my/window-map))

  ;; version-control and project keymaps
  (define-key project-prefix-map "w" (cons "workspace" my/workspace-map))
  :bind
  (:map my/buffer-map
        ("e" . eval-buffer)
        ("k" . kill-this-buffer)
        ("K" . kill-buffer)
        ("c" . clone-buffer)
        ("r" . revert-buffer)
        ("e" . eval-buffer)
        ("s" . save-buffer)
        :map my/file-map
        ("f" . find-file)
        ("F" . find-file-other-window)
        ("d" . find-dired)
        ("c" . copy-file)
        ("f" . find-file)
        ("d" . delete-file)
        ("r" . rename-file)
        ("w" . write-file)
        :map my/open-map
        ("F" . make-frame)
        ("i" . ielm)
        ("e" . eshell)
        ("t" . term)
        ("s" . scratch-buffer)
        :repeat-map my/buffer-scale-map
        ("+" . text-scale-increase)
        ("-" . text-scale-decrease)
        ("=" . text-scale-adjust)
        :repeat-map my/window-map
        ("n" . next-window-any-frame)
        ("p" . previous-window-any-frame)
        ("k" . delete-window)
        ("K" . kill-buffer-and-window)
        ("+" . enlarge-window)
        ("-" . shrink-window)
        ("*" . enlarge-window-horizontally)
        ("" . shrink-window-horizontally)
        ("r" . split-window-right)
        ("b" . split-window-below)
        ("v" . split-window-vertically)
        ("h" . split-window-horizontally)
        ("m" . delete-other-windows)
        ("m" . delete-other-windows)
        ("M" . delete-other-windows-vertically)
        :exit
        ("=" . balance-windows)))

Custom Lisp Functions

In this section, I define some custom Lisp functions.

(use-package emacs
  :preface
  (defun my/extract-username-repo ()
    "Extract the username and repository name from a GitHub repository link at point."
    (interactive)
    (save-excursion
      (org-back-to-heading)
      (let* ((element (org-element-at-point))
             (headline (org-element-property :raw-value element))
             (url (save-match-data
                    (string-match org-bracket-link-regexp headline)
                    (match-string 1 headline))))
        (if (and url (string-match "github.com/\\([[:alnum:]\.\-]+\\)/\\([[:alnum:]\.\-]+\\)\\(\.git\\)" url))
            (list (match-string 1 url) (match-string 2 url))
          (error "No GitHub link found at point.")))))

  (defun my/insert-github-repo-description ()
    "Retrieve and insert the short description of a GitHub repository at point."
    (interactive)
    (let* ((repo-info (my/extract-username-repo))
           (username (car repo-info))
           (repo (cadr repo-info)))
      (message (format "Inserting description for GitHub Repository. User: %s, Repo: %s" username repo))
      (let* ((url (format "https://api.github.com/repos/%s/%s" username repo))
             (response (with-current-buffer (url-retrieve-synchronously url)
                         (prog1 (buffer-substring-no-properties (point-min) (point-max))
                           (kill-buffer)))))
        (string-match "\r?\n\r?\n" response)
        (setq response (substring response (match-end 0)))
        (let* ((json (json-read-from-string response))
               (description (cdr (assoc 'description json))))
          (if description
              (progn
                (setq description (string-trim description))
                (setq description (concat (capitalize (substring description 0 1))
                                          (substring description 1)))
                (unless (string-suffix-p "." description)
                  (setq description (concat description ".")))
                (insert description))
            (error "No description, website, or topics provided."))))))
  ;; (cl-defun create-org-entry-for-package (recipe)
  ;;   (interactive (list (straight-get-recipe nil nil)))
  ;;   (straight--with-plist recipe
  ;;       (package local-repo type)
  ;;     (message-box type)
  ;;     (if (eq type 'git)
  ;;         (straight-vc-git--destructure recipe
  ;;             (package local-repo branch nonrecursive depth
  ;;                      remote upstream-remote
  ;;                      host upstream-host
  ;;                      protocol upstream-protocol
  ;;                      repo upstream-repo fork-repo)
  ;;           (message upstream-remote)
  ;;           (let ((parent-headline-level (org-outline-level)))
  ;;             (save-excursion
  ;;               (org-insert-heading (1+ parent-headline-level))
  ;;               (insert (format "*** [[%s][%s]]\n" upstream-remote package))
  ;;               ;; (insert (format "%s\n" description))
  ;;               (insert (format "#+begin_src emacs-lisp\n(use-package %s\n  :demand t\n  :after (eglot consult))\n#+end_src\n" package))
  ;;               (org-edit-src-code)))
  ;;           )
  ;;       )))
  )

Configure Packages

We save the following package declaration into separate files in the modules directory. To load the we have to add this directory to the load-path.

(add-to-list 'load-path "~/.emacs.d/lisp/")

UI

:header-args+: :tangle lisp/my-ui.el
(require 'my-ui)

Conventional Header

<<header(file_name="my-ui.el")>>

Make org-brain-visualize-mode look a bit nicer.

(use-package ascii-art-to-unicode
  :after org-brain
  :preface
  (defface aa2u-face '((t . nil))
    "Face for aa2u box drawing characters")
  (defun aa2u-org-brain-buffer ()
    (let ((inhibit-read-only t))
      (make-local-variable 'face-remapping-alist)
      (add-to-list 'face-remapping-alist
                   '(aa2u-face . org-brain-wires))
      (ignore-errors (aa2u (point-min) (point-max)))))
  :config
  (advice-add #'aa2u-1c :filter-return
              (lambda (str) (propertize str 'face 'aa2u-face)))
  :hook
  (org-brain-after-visualize . aa2u-org-brain-buffer))

Auto-Dark-Emacs is an auto changer between 2 themes, dark/light, following MacOS, Linux or Windows Dark Mode settings.

(use-package auto-dark
  :custom
  (auto-dark-dark-theme 'modus-vivendi)
  (auto-dark-light-theme 'modus-operandi)
  :hook
  (after-init . auto-dark-mode))

display-line-numbers

Enable line numbers for some modes

(use-package display-line-numbers
  :straight nil
  :hook
  (((prog-mode conf-mode text-mode) . display-line-numbers-mode)
   ;; disable for org mode
   (org-mode . (lambda () (display-line-numbers-mode 0)))))

A fancy and fast mode-line inspired by minimalism design.

(use-package doom-modeline
  :custom
  ;; If non-nil, cause imenu to see `doom-modeline' declarations.
  ;; This is done by adjusting `lisp-imenu-generic-expression' to
  ;; include support for finding `doom-modeline-def-*' forms.
  ;; Must be set before loading doom-modeline.
  (doom-modeline-support-imenu t)

  ;; How tall the mode-line should be. It's only respected in GUI.
  ;; If the actual char height is larger, it respects the actual height.
  (doom-modeline-height 20)

  ;; display the real names, please put this into your init file.
  (find-file-visit-truename t)

  ;; Determines the style used by `doom-modeline-buffer-file-name'.
  ;;
  ;; Given ~/Projects/FOSS/emacs/lisp/comint.el
  ;;   auto => emacs/l/comint.el (in a project) or comint.el
  ;;   truncate-upto-project => ~/P/F/emacs/lisp/comint.el
  ;;   truncate-from-project => ~/Projects/FOSS/emacs/l/comint.el
  ;;   truncate-with-project => emacs/l/comint.el
  ;;   truncate-except-project => ~/P/F/emacs/l/comint.el
  ;;   truncate-upto-root => ~/P/F/e/lisp/comint.el
  ;;   truncate-all => ~/P/F/e/l/comint.el
  ;;   truncate-nil => ~/Projects/FOSS/emacs/lisp/comint.el
  ;;   relative-from-project => emacs/lisp/comint.el
  ;;   relative-to-project => lisp/comint.el
  ;;   file-name => comint.el
  ;;   buffer-name => comint.el<2> (uniquify buffer name)
  ;;
  ;; If you are experiencing the laggy issue, especially while editing remote files
  ;; with tramp, please try `file-name' style.
  ;; Please refer to https://github.com/bbatsov/projectile/issues/657.
  (doom-modeline-buffer-file-name-style 'relative-to-project)

  ;; Whether display icons in the mode-line.
  ;; While using the server mode in GUI, should set the value explicitly.
  (doom-modeline-icon t)

  ;; If non-nil, only display one number for checker information if applicable.
  ;; (doom-modeline-checker-simple-format nil)

  ;; Don't display offset percentage
  (doom-modeline-percent-position nil)
  :hook
  ((after-init . doom-modeline-mode)
   ;; filesize in modeline
   (doom-modeline-mode . size-indication-mode)
   ;; cursor column in modeline)
   (doom-modeline-mode . column-number-mode)))

An Emacs plugin that hides (or masks) the current buffer’s mode-line.

(use-package hide-mode-line
  :hook
  (((completion-list-mode-hook Man-mode-hook) . hide-mode-line-mode)
   (comint-mode . hide-mode-line-mode)
   (diff-mode . hide-mode-line-mode)
   (eshell-mode  . hide-mode-line-mode)
   (magit-status-mode . hide-mode-line-mode)
   (org-brain-visualize-mode . hide-mode-line-mode)
   (pdf-view-mode  . hide-mode-line-mode)
   (shell-mode  . hide-mode-line-mode)
   (special-mode . hide-mode-line-mode)
   (symbols-outline-mode . hide-mode-line-mode)
   (term-mode  . hide-mode-line-mode)
   (vterm-mode . hide-mode-line-mode)))

hl-line

Highlighting of the current line (native mode)

(use-package hl-line
  :straight nil
  :hook
  ((prog-mode org-mode) . global-hl-line-mode))

Highlight TODO keywords.

(use-package hl-todo
  :preface
  (defun my/hl-todo-register-flymake-report-fn ()
    (add-hook #'flymake-diagnostic-functions #'hl-todo-flymake))
  :hook
  (((prog-mode conf-mode LaTeX-mode) . hl-todo-mode)
   (flymake-mode . my/hl-todo-register-flymake-report-fn)))

Fast, configurable indentation guide-bars for Emacs.

(use-package indent-bars
  :straight (:host github :repo "jdtsmith/indent-bars")
  :custom
  (indent-bars-treesit-support t)
  (indent-bars-treesit-ignore-blank-lines-types '("module"))
  (indent-bars-treesit-wrap '((python
                               argument_list parameters list list_comprehension dictionary
                               dictionary_comprehension parenthesized_expression subscript)))
  (indent-bars-treesit-scope '((python
                                function_definition class_definition for_statement
                                if_statement with_statement while_statement)))
  (indent-bars-color-by-depth nil)
  (indent-bars-highlight-current-depth '(:face default :blend 0.4))
  (indent-bars-pad-frac 0.1)
  (indent-bars-pattern ".")
  (indent-bars-width-frac 0.2)
  :hook
  ((python-base-mode yaml-ts-mode emacs-lisp-mode) . indent-bars-mode))

Display typographical ligatures in Emacs.

(use-package ligature
  :if (display-graphic-p)
  :config
  ;; set Fira as default font
  (set-frame-font "FiraCode Nerd Font-10" nil t)
  :preface
  (defun my/setup-ligatures ()
    ;; Enable the "www" ligature in every possible major mode
    (ligature-set-ligatures 't '("www"))
    ;; Enable traditional ligature support in eww-mode, if the
    ;; `variable-pitch' face supports it
    (ligature-set-ligatures '(eww-mode org-mode) '("ff" "fi" "ffi"))
    ;; Enable all Cascadia and Fira Code ligatures in programming modes
    (ligature-set-ligatures '(prog-mode org-mode)
                            '(;; == === ==== => =| =>>=>=|=>==>> ==< =/=//=// =~
                              ;; =:= =!=
                              ("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "="))))
                              ;; ;; ;;;
                              (";" (rx (+ ";")))
                              ;; && &&&
                              ("&" (rx (+ "&")))
                              ;; !! !!! !. !: !!. != !== !~
                              ("!" (rx (+ (or "=" "!" "\." ":" "~"))))
                              ;; ?? ??? ?:  ?=  ?.
                              ("?" (rx (or ":" "=" "\." (+ "?"))))
                              ;; %% %%%
                              ("%" (rx (+ "%")))
                              ;; |> ||> |||> ||||> |] |} || ||| |-> ||-||
                              ;; |->>-||-<<-| |- |== ||=||
                              ;; |==>>==<<==<=>==//==/=!==:===>
                              ("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]"
                                              "-" "=" ))))
                              ;; \\ \\\ \/
                              ("\\" (rx (or "/" (+ "\\"))))
                              ;; ++ +++ ++++ +>
                              ("+" (rx (or ">" (+ "+"))))
                              ;; :: ::: :::: :> :< := :// ::=
                              (":" (rx (or ">" "<" "=" "//" ":=" (+ ":"))))
                              ;; // /// //// /\ /* /> /===:===!=//===>>==>==/
                              ("/" (rx (+ (or ">"  "<" "|" "/" "\\" "\*" ":" "!"
                                              "="))))
                              ;; .. ... .... .= .- .? ..= ..<
                              ("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\."))))
                              ;; -- --- ---- -~ -> ->> -| -|->-->>->--<<-|
                              ("-" (rx (+ (or ">" "<" "|" "~" "-"))))
                              ;; *> */ *)  ** *** ****
                              ("*" (rx (or ">" "/" ")" (+ "*"))))
                              ;; www wwww
                              ("w" (rx (+ "w")))
                              ;; <> <!-- <|> <: <~ <~> <~~ <+ <* <$ </  <+> <*>
                              ;; <$> </> <|  <||  <||| <|||| <- <-| <-<<-|-> <->>
                              ;; <<-> <= <=> <<==<<==>=|=>==/==//=!==:=>
                              ;; << <<< <<<<
                              ("<" (rx (+ (or "\+" "\*" "\$" "<" ">" ":" "~"  "!"
                                              "-"  "/" "|" "="))))
                              ;; >: >- >>- >--|-> >>-|-> >= >== >>== >=|=:=>>
                              ;; >> >>> >>>>
                              (">" (rx (+ (or ">" "<" "|" "/" ":" "=" "-"))))
                              ;; #: #= #! #( #? #[ #{ #_ #_( ## ### #####
                              ("#" (rx (or ":" "=" "!" "(" "\?" "\[" "{" "_(" "_"
                                           (+ "#"))))
                              ;; ~~ ~~~ ~=  ~-  ~@ ~> ~~>
                              ("~" (rx (or ">" "=" "-" "@" "~>" (+ "~"))))
                              ;; __ ___ ____ _|_ __|____|_
                              ("_" (rx (+ (or "_" "|"))))
                              ;; Fira code: 0xFF 0x12
                              ("0" (rx (and "x" (+ (in "A-F" "a-f" "0-9")))))
                              ;; Fira code:
                              "Fl"  "Tl"  "fi"  "fj"  "fl"  "ft"
                              ;; The few not covered by the regexps.
                              "{|"  "[|"  "]#"  "(*"  "}#"  "$>"  "^="))
    ;; Enables ligature checks globally in all buffers. You can also do it
    ;; per mode with `ligature-mode'.
    (global-ligature-mode))
  :hook
  (after-init . my/setup-ligatures))

Accessible themes for GNU Emacs, conforming with the highest standard for colour contrast between background and foreground values (WCAG AAA) https://protesilaos.com/emacs/modus-themes

(use-package modus-themes
  :bind
  (:map my/toggle-map
        ("t" . modus-themes-toggle))
  :custom
  ;; Add all your customizations prior to loading the themes
  (modus-themes-italic-constructs t)
  (modus-themes-bold-constructs nil))

A Library for Nerd Font icons. Required for modline icons.

(use-package nerd-icons)

display LaTeX compilation information in the mode line

(use-package procress
  :straight (:host github :repo "haji-ali/procress")
  :after doom-modeline
  :commands procress-auctex-mode
  :hook
  (LaTeX-mode . procress-auctex-mode)
  :config
  (procress-load-default-svg-images))

Increase the padding/spacing of GNU Emacs frames and windows.

(use-package spacious-padding
  :custom
  (spacious-padding-widths '(
                             :internal-border-width 10
                             :header-line-width 0
                             :mode-line-width 4
                             :tab-bar-width 4
                             :tab-line-width 2
                             :tab-width 2
                             :right-divider-width 10
                             ;; :scroll-bar-width 2
                             :fringe-width 8
                             ))
  (spacious-padding-subtle-mode-line t)
  :hook
  (after-init . spacious-padding-mode))

tab-bar

(use-package tab-bar
  :straight nil
  :bind
  (([remap winner-undo] . tab-bar-history-back)
   ([remap winner-undo] . tab-bar-history-forward)
   :repeat-map my/window-map
   ("u" . tab-bar-history-back)
   ("i" . tab-bar-history-forward)
   :repeat-map my/workspace-map
   ("p" . tab-previous)
   ("n" . tab-next)
   ("P" . tab-bar-move-tab-backward)
   ("N". tab-bar-move-tab)
   :exit
   ("k" . tab-close-group))
  :custom
  (tab-bar-format '(tab-bar-format-tabs-groups
                    my/tab-bar-format-new
                    tab-bar-format-align-right
                    tab-bar-format-global
                    tab-bar-format-menu-bar))
  (tab-bar-separator "")
  (tab-bar-auto-width nil)
  (tab-bar-close-button-show t)
  (tab-bar-new-tab-choice "*scratch*")
  (tab-bar-history-limit 100)
  :preface
  (defun my/tab-bar-format-new ()
    "Button to add a new tab."
    `((add-tab menu-item ,tab-bar-new-button project-switch-project
               :help "New")))

  (defun my/tab-bar-tab-group-format-function (tab i &optional current-p)
    (let*((tab-group-name (funcall tab-bar-tab-group-function tab))
          (tab-group-face (if current-p 'tab-bar-tab-group-current 'tab-bar-tab-group-inactive))
          (color (face-attribute (if current-p
                                     'mode-line-emphasis
                                   'tab-bar-tab-group-inactive) :foreground))
          (group-sep (propertize " " 'face (list :height (if current-p 0.4 0.2)
                                                 :foreground color
                                                 :background color)))
          (group-icon (cond
                       ((equal tab-group-name "HOME") "")
                       (t ""))))
      (concat
       group-sep
       (propertize
        (concat
         " "
         group-icon
         " "
         (funcall tab-bar-tab-group-function tab)
         " ")
        'face tab-group-face))))

  (defun my/tab-bar-tab-name-format-function (tab i)
    (let ((current-p (eq (car tab) 'current-tab)))
      (propertize
       (concat (if current-p "" " ")
               (if tab-bar-tab-hints (format "%d " i) "")
               (alist-get 'name tab)
               (if (and tab-bar-close-button-show current-p)
                   tab-bar-close-button " "))
       'face (list :inherit 'tab-bar-tab :weight (if current-p 'bold 'normal)))))

  (defun my/create-home-tab-group (&optional frame)
    (let ((tab-group-name (funcall tab-bar-tab-group-function (tab-bar--current-tab))))
      (when frame (select-frame frame))
      (tab-group (if tab-group-name tab-group-name "HOME"))))

  :config
  (require 'icons)
  (define-icon tab-bar-new nil
    '(
      ;; (emoji "➕")
      (symbol "" :face tab-bar-tab-inactive)
      (text " + "))
    "Icon for creating a new tab."
    :version "29.1"
    :help-echo "New tab")
  (define-icon tab-bar-close nil
    '(
      ;; (emoji " ❌")
      (symbol " 󰅖 ") ;; "ⓧ"
      (text " x "))
    "Icon for closing the clicked tab."
    :version "29.1"
    :help-echo "Click to close tab")
  (define-icon tab-bar-menu-bar nil
    '(;; (emoji "🍔")
      (symbol " 󰍜 " :face tab-bar-tab-inactive)
      (text "Menu" :face tab-bar-tab-inactive))
    "Icon for the menu bar."
    :version "29.1"
    :help-echo "Menu bar")

  (setq tab-bar-tab-group-format-function #'my/tab-bar-tab-group-format-function
        tab-bar-tab-name-format-function #'my/tab-bar-tab-name-format-function)

  (add-hook 'after-make-frame-functions 'my/create-home-tab-group)
  (my/create-home-tab-group)

  ;; Prevent accidental tab switches when scrolling the buffer
  (define-key tab-bar-map (kbd "<wheel-down>") nil t)
  (define-key tab-bar-map (kbd "<wheel-up>") nil t)
  :hook
  ((after-init . tab-bar-history-mode)
   (after-init . tab-bar-mode)))

tab-line

Configure the build in tab-line-mode to display and switch between windows buffers via tabs.

Some customizations are made to prettify the look of tabs using nerd-icons and make the close button behave as known from other editors.

References:

(use-package tab-line
  :straight nil
  :custom
  (tab-line-new-tab-choice nil)
  (tab-line-new-button-show nil)
  (tab-line-tab-name-function #'my/tab-line-tab-name-function)
  (tab-line-close-tab-function #'my/tab-line-close-tab-function)
  (tab-line-exclude-modes '(completion-list-mode
                            doc-view-mode imenu-list-major-mode ediff-meta-mode ediff-mode symbols-outline-mode dired-mode
                            dape-info-scope-mode dape-info-stack-mode dape-info-watch-mode dape-info-parent-mode
                            dape-info-modules-mode dape-info-sources-mode dape-info-threads-mode dape-info-breakpoints-mode))
  (tab-line-close-button-show 'selected)
  (tab-line-separator "")
  :bind
  (:map my/toggle-map
        ("T" . global-tab-line-mode))
  :preface
  (defun my/tab-line-tab-name-function (buffer &optional _buffers)
    (let ((name (buffer-name buffer)))
      (concat " "
              (nerd-icons-icon-for-file name)
              (format " %s " name))))

  (defun my/tab-line-close-tab-function (tab)
    "Close the selected tab.
    If the tab is presented in another window, close the tab by using the `bury-buffer` function.
    If the tab is unique to all existing windows, kill the buffer with the `kill-buffer` function.
    Lastly, if no tabs are left in the window, it is deleted with the `delete-window` function."
    (interactive (list (current-buffer)))
    (let ((window (selected-window))
          (buffer (if (bufferp tab) tab (cdr (assq 'buffer tab)))))
      (with-selected-window window
        (let ((tab-list (tab-line-tabs-window-buffers))
              (buffer-list (flatten-list
                            (seq-reduce (lambda (list window)
                                          (select-window window t)
                                          (cons (tab-line-tabs-window-buffers) list))
                                        (window-list) nil))))
          (select-window window)
          (if (> (seq-count (lambda (b) (eq b buffer)) buffer-list) 1)
              (progn
                (message "Burry tab %s of buffer %s" tab buffer)
                (bury-buffer))
            (progn
              (message "Closing tab %s of buffer %s" tab buffer)
              (kill-buffer buffer)))
          (unless (cdr tab-list)
            (progn
              (message "Closing window")
              (ignore-errors (delete-window window))))))))
  :config
  (setq tab-line-close-button
        (propertize "󰅖 "
                    'keymap tab-line-tab-close-map
                    'mouse-face 'tab-line-close-highlight
                    'help-echo "Click to close tab"))
  :hook
  (after-init . global-tab-line-mode))

Library Footer

(provide 'my-ui)
;;; my-ui.el ends here

UX

:header-args+: :tangle lisp/my-ux.el
(require 'my-ux)

Conventional Header

<<header(file_name="my-ux.el")>>

autorevert

Revert buffers when the underlying file has changed

(use-package autorevert
  :straight nil
  :custom
  ;; Revert Dired and other buffers
  (global-auto-revert-non-file-buffers t)
  :hook
  (after-init . global-auto-revert-mode))

bookmark

(use-package bookmark
  :straight nil
  :custom
  (bookmark-save-flag 1))

Mirror of the comint-mime package from GNU ELPA, current as of 2024-01-18. Provides a mechanism for REPLs (or comint buffers, in Emacs parlance) to display graphics and other types of special content.

(use-package comint-mime
  :hook
  ((shell-mode . comint-mime-setup)
   (inferior-python-mode . comint-mime-setup)))

delsel

Replace selected text when typing

(use-package delsel
  :straight nil
  :hook
  ((prog-mode conf-mode text-mode) . delete-selection-mode))

elec-pair

Automatically add closing parentheses, quotes, etc.

(use-package elec-pair
  :straight nil
  :hook
  ((prog-mode conf-mode) . electric-pair-mode))

When working with many windows at the same time, each window has a size that is not convenient for editing.

(use-package golden-ratio
  :custom
  (golden-ratio-exclude-modes '(speedbar-mode vundo-mode dired-mode symbols-outline-mode))
  (golden-ratio-exclude-buffer-regexp '(" ?\\*MINIMAP\\*" " ?\\*Outline\\*"))
  ;; (golden-ratio-auto-scale t)
  :config
  (add-to-list 'golden-ratio-inhibit-functions
               (lambda ()
                 (and which-key--buffer
                      (window-live-p (get-buffer-window which-key--buffer)))))
  :bind
  (:map my/toggle-map
        ("g" . golden-ratio-mode)))

Sidebar showing a “mini-map” of a buffer.

(use-package minimap
  :custom
  (minimap-window-location 'right)
  (minimap-hide-fringes t)
  (minimap-minimum-width 25)
  (minimap-major-modes '(prog-mode conf-mode))
  :config
  (with-eval-after-load 'golden-ratio
    (add-to-list 'golden-ratio-inhibit-functions
                 (lambda ()
                   (and minimap-buffer-name
                        (window-live-p (get-buffer-window minimap-buffer-name)))))
    (add-to-list 'golden-ratio-exclude-buffer-names `(,minimap-buffer-name)))
  :bind
  (:map my/toggle-map
        ("m" . minimap-mode)))

paren

Paren mode for highlighting matcing paranthesis

(use-package paren
  :straight nil
  :custom
  (show-paren-style 'parenthesis)
  (show-paren-when-point-in-periphery t)
  (show-paren-when-point-inside-paren nil)
  :hook
  (prog-mode . show-paren-mode))

recentf

50 Recents files with some exclusion (regex patterns).

(use-package recentf
  :straight nil
  :custom
  (recentf-keep '(file-remote-p file-readable-p))
  (recentf-max-menu-items 10)
  (recentf-max-saved-items 100)
  :config
  (add-to-list 'recentf-exclude
               (recentf-expand-file-name no-littering-var-directory))
  (add-to-list 'recentf-exclude
               (recentf-expand-file-name no-littering-etc-directory))
  :bind
  (:map my/open-map
        ("r" . recentf-open))
  :hook
  (after-init . recentf-mode))

repeat

Enable repeat maps

(use-package repeat
  :straight nil
  :preface
  ;; https://karthinks.com/software/it-bears-repeating/#adding-repeat-mode-support-to-keymaps
  (defun my/repeatize-keymap (keymap)
    "Add `repeat-mode' support to a KEYMAP."
    (map-keymap
     (lambda (_key cmd)
       (when (symbolp cmd)
         (put cmd 'repeat-map keymap)))
     (symbol-value keymap)))
  :config
  (with-eval-after-load 'smerge
    (my/repeatize-keymap 'smerge-basic-map))
  :hook
  (after-init . repeat-mode))

Rotate the layout of emacs.

(use-package rotate
  :bind
  (:repeat-map my/window-map
               ("R" . rotate-layout)
               ("W" . rotate-window)))

savehist

(use-package savehist
  :straight nil
  :custom
  (kill-ring-max 500)
  (history-length 500)
  (savehist-additional-variables
   '(kill-ring
     command-history
     set-variable-value-history
     custom-variable-history
     query-replace-history
     read-expression-history
     minibuffer-history
     read-char-history
     face-name-history
     bookmark-history
     file-name-history))
  ;; No duplicates in history
  (history-delete-duplicates t)
  :config
  (put 'minibuffer-history         'history-length 500)
  (put 'file-name-history          'history-length 500)
  (put 'set-variable-value-history 'history-length 250)
  (put 'custom-variable-history    'history-length 250)
  (put 'query-replace-history      'history-length 250)
  (put 'read-expression-history    'history-length 250)
  (put 'read-char-history          'history-length 250)
  (put 'face-name-history          'history-length 250)
  (put 'bookmark-history           'history-length 250)
  :hook
  ;;Start history mode.
  (after-init . savehist-mode))

saveplace

Record cursor position from one session to the other

(use-package saveplace
  :straight nil
  :hook
  (after-init . save-place-mode))

time-stamp

Automatically update file timestamps when file is saved

(use-package time-stamp
  :straight nil
  :custom
  (time-stamp-active t)
  (time-stamp-format "%04Y-%02m-%02d %02H:%02M:%02S (%U)")
  :hook
  (before-save . time-stamp))

Distraction-free writing for Emacs.

(use-package writeroom-mode
  :bind (:map my/toggle-map ("z" . writeroom-mode)))

Library Footer

(provide 'my-ux)
;;; my-ux.el ends here

Org

:header-args+: :tangle lisp/my-org.el
(require 'my-org)

Conventional Header

<<header(file_name="my-org.el")>>

Agenda view and task management has been inspired by https://github.com/rougier/emacs-gtd

(use-package org
  :custom
  (org-ellipsis "")
  (org-src-fontify-natively t)
  (org-fontify-quote-and-verse-blocks t)
  (org-src-tab-acts-natively t)
  (org-edit-src-content-indentation 2)
  (org-hide-block-startup nil)
  (org-src-preserve-indentation nil)
  ;; Return or left-click with mouse follows link
  (org-return-follows-link t)
  (org-mouse-1-follows-link t)
  ;; Display links as the description provided
  (org-link-descriptive t)

  ;; Todo
  (org-todo-keywords
   '((sequence
      "PROJ(p)"  ; A project, which usually contains other tasks
      "TODO(t)"  ; A task that needs doing & is ready to do
      "NEXT(n)"  ; Next task in a project
      "STRT(s)"  ; A task that is in progress
      "WAIT(w)"  ; Something external is holding up this task
      "HOLD(h)"  ; This task is paused/on hold because of me
      "|"
      "DONE(d)"  ; Task successfully completed
      "KILL(k)") ; Task was cancelled, aborted or is no longer applicable
     (sequence
      "[ ](T)"   ; A task that needs doing
      "[-](S)"   ; Task is in progress
      "[?](W)"   ; Task is being held up or paused
      "|"
      "[X](D)"))) ; Task was completed
  (org-todo-keyword-faces
   '(("[-]"  . +org-todo-active)
     ("STRT" . +org-todo-active)
     ("[?]"  . +org-todo-onhold)
     ("WAIT" . +org-todo-onhold)
     ("HOLD" . +org-todo-onhold)
     ("PROJ" . +org-todo-project)))

  ;; Add timstamp to items when done
  (org-log-done 'time)

  ;; org capture
  (org-capture-templates
   `(("i" "Inbox" entry  (file "agenda/inbox.org")
      ,(concat "* TODO %?\n"
               "/Entered on/ %U"))
     ("m" "Meeting" entry  (file+headline "agenda/agenda.org" "Future")
      ,(concat "* <%<%Y-%m-%d %a %H:00>> %? :meeting:\n"))
     ("n" "Note" entry  (file "agenda/notes.org")
      ,(concat "* Note (%a)\n"
               "/Entered on/ %U\n" "\n" "%?"))))

  ;; org-agenda
  (org-agenda-files
   (mapcar 'file-truename
           (file-expand-wildcards (concat org-directory "agenda/*.org"))))
  ;; Refile and Archive
  (org-refile-use-outline-path 'file)
  (org-outline-path-complete-in-steps nil)
  (org-refile-targets `((,(expand-file-name  "agenda/agenda.org" org-directory) :maxlevel . 3)
                        (,(expand-file-name  "agenda/projects.org" org-directory) :regexp . "\\(?:\\(?:Note\\|Task\\)s\\)")
                        (,(expand-file-name  "agenda/literature.org" org-directory) :maxlevel . 2)
                        (,(expand-file-name  "agenda/scheduled.org" org-directory) :maxlevel . 2)))
  (org-agenda-custom-commands
   '(("g" "Get Things Done (GTD)"
      ((agenda ""
               ((org-agenda-span 'day)
                (org-agenda-start-day "today")
                (org-agenda-skip-function
                 '(org-agenda-skip-entry-if 'deadline))
                (org-deadline-warning-days 0)))
       (todo "PROJ"
             ((org-agenda-skip-function
               '(org-agenda-skip-subtree-if 'nottodo '("NEXT" "STRT")))
              (org-agenda-overriding-header "Active Projects:")))
       (todo "STRT"
             ((org-agenda-skip-function
               '(org-agenda-skip-entry-if 'deadline))
              (org-agenda-sorting-strategy '(priority-down category-keep effort-up))
              (org-agenda-prefix-format "  %i %-12:c [%e] ")
              (org-agenda-overriding-header "\nActive Tasks\n")
              ))  ; Exclude entries with LITERATURE category
       (todo "NEXT"
             ((org-agenda-skip-function
               '(org-agenda-skip-entry-if 'deadline))
              (org-agenda-sorting-strategy '(priority-down category-keep effort-up))
              (org-agenda-prefix-format "  %i %-12:c [%e] ")
              (org-agenda-overriding-header "\nNext Tasks\n")))
       (agenda nil
               ((org-agenda-entry-types '(:deadline))
                (org-agenda-format-date "")
                (org-deadline-warning-days 7)
                (org-agenda-skip-function
                 '(org-agenda-skip-entry-if 'notregexp "\\* NEXT"))
                (org-agenda-overriding-header "\nDeadlines")))
       (tags-todo "inbox"
                  ((org-agenda-prefix-format "  %?-12t% s")
                   (org-agenda-overriding-header "\nInbox\n")))
       (todo "HOLD|WAIT"
             ((org-agenda-skip-function
               '(org-agenda-skip-entry-if 'deadline))
              (org-agenda-sorting-strategy '(priority-down category-keep effort-up))
              (org-agenda-prefix-format "  %i %-12:c [%e] ")
              (org-agenda-overriding-header "\nPaused Tasks\n")))
       (tags "CLOSED>=\"<today>\""
             ((org-agenda-overriding-header "\nCompleted today\n"))))
      ((org-agenda-category-filter-preset '("-LITERATURE"))))
     ("l" "Literature" tags-todo "literature"
      ((org-agenda-sorting-strategy '(priority-down category-keep effort-up))
       (org-agenda-prefix-format "  %i %-12:c [%e] ")))))

  (org-babel-load-languages '((emacs-lisp . t)
                              (python . t)
                              (shell . t)))
  (org-export-backends '(md beamer odt latex icalendar html ascii))
  (org-cite-biblatex-options "hyperref=true,url=true,backend=biber,natbib=true")

  ;; Use SVGs for latex previews -> No blur when scaling
  (org-preview-latex-default-process 'dvisvgm)
  :preface
  ;; https://github.com/rougier/emacs-gtd#activating-tasks
  (defun my/log-todo-next-creation-date (&rest ignore)
    "Log NEXT creation time in the property drawer under the key 'ACTIVATED'"
    (when (and (string= (org-get-todo-state) "NEXT")
               (not (org-entry-get nil "ACTIVATED")))
      (org-entry-put nil "ACTIVATED" (format-time-string "[%Y-%m-%d]"))))
  ;; Save the corresponding buffers
  (defun my/gtd-save-org-buffers ()
    "Save `org-agenda-files' buffers without user confirmation.
            See also `org-save-all-org-buffers'"
    (interactive)
    (message "Saving org-agenda-files buffers...")
    (save-some-buffers t (lambda ()
                           (when (member (buffer-file-name) org-agenda-files)
                             t)))
    (message "Saving org-agenda-files buffers... done"))

  ;; archive all DONE tasks in subtree
  ;; https://stackoverflow.com/questions/6997387
  (defun my/org-archive-done-tasks ()
    (interactive)
    (org-map-entries
     (lambda ()
       (org-archive-subtree)
       (setq org-map-continue-from (org-element-property :begin (org-element-at-point))))
     "/DONE" 'tree))

  (defun my/text-scale-adjust-latex-previews ()
    "Adjust the size of latex preview fragments when changing the
buffer's text scale."
    (pcase major-mode
      ('latex-mode
       (dolist (ov (overlays-in (point-min) (point-max)))
         (if (eq (overlay-get ov 'category)
                 'preview-overlay)
             (my/text-scale--resize-fragment ov))))
      ('org-mode
       (dolist (ov (overlays-in (point-min) (point-max)))
         (if (eq (overlay-get ov 'org-overlay-type)
                 'org-latex-overlay)
             (my/text-scale--resize-fragment ov))))))

  ;; Scaling Latex previews
  ;; https://karthinks.com/software/scaling-latex-previews-in-emacs/
  (defun my/text-scale--resize-fragment (ov)
    (overlay-put
     ov 'display
     (cons 'image
           (plist-put
            (cdr (overlay-get ov 'display))
            :scale (+ 1.0 (* 0.25 text-scale-mode-amount))))))
  :hook
  (org-after-todo-state-change . my/log-todo-next-creation-date)
  :bind
  (:map my/leader-map
        ("c" . org-capture)
        :map my/open-map
        ("a" . org-agenda))
  :config
  (advice-add 'org-refile :after
              (lambda (&rest _)
                (my/gtd-save-org-buffers)))
  :hook
  (text-scale-mode . my/text-scale-adjust-latex-previews))

(use-package ox-latex
  :straight nil
  :after org
  :config
  ;; https://orgmode.org/manual/LaTeX-specific-export-settings.html
  (add-to-list 'org-latex-packages-alist
               '("AUTO" "babel" t ("pdflatex")))
  (add-to-list 'org-latex-packages-alist
               '("AUTO" "polyglossia" t ("xelatex" "lualatex")))
  (add-to-list 'org-latex-classes
               '("koma-article"
                 "\\documentclass{scrartcl}"
                 ("\\section{%s}" . "\\section*{%s}")
                 ("\\subsection{%s}" . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
                 ("\\paragraph{%s}" . "\\paragraph*{%s}")
                 ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
  (add-to-list 'org-latex-classes
               '("koma-letter"
                 "\\documentclass{scrlttr2}"
                 ("\\section{%s}" . "\\section*{%s}")
                 ("\\subsection{%s}" . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
                 ("\\paragraph{%s}" . "\\paragraph*{%s}")
                 ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))))

(use-package ox-beamer
  :straight nil
  :after org
  :config
  (add-to-list 'org-beamer-environments-extra
               '("onlyenv" "O" "\\begin{onlyenv}%a" "\\end{onlyenv}")))

(use-package ox-extra
  :straight nil
  :after org
  :config
  (ox-extras-activate '(ignore-headlines)))

Toggle visibility of hidden Org mode element parts upon entering and leaving an element.

test aaa babab

(use-package org-appear
  :after org
  :hook (org-mode . org-appear-mode))

A simple emacs package to allow org file tangling upon save.

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

Org-mode wiki + concept-mapping.

(use-package org-brain
  :after org org-noter
  :preface
  ;; from org brain README
  ;; Here’s a command which uses org-cliplink to add a link from the clipboard
  ;; as an org-brain resource.
  ;; It guesses the description from the URL title.
  ;; Here I’ve bound it to L in org-brain-visualize.
  (defun org-brain-cliplink-resource ()
    "Add a URL from the clipboard as an org-brain resource.
  Suggest the URL title as a description for resource."
    (interactive)
    (let ((url (org-cliplink-clipboard-content)))
      (org-brain-add-resource
       url
       (org-cliplink-retrieve-title-synchronously url)
       t)))

  (defun org-brain-open-org-noter (entry)
    "Open `org-noter' on the ENTRY.
  If run interactively, get ENTRY from context."
    (interactive (list (org-brain-entry-at-pt)))
    (org-with-point-at (org-brain-entry-marker entry)
      (org-noter)))

  (defun org-brain-insert-resource-icon (link)
    "Insert an icon, based on content of org-mode LINK."
    (insert (format "%s "
                    (cond ((string-prefix-p "brain:" link)
                           (nerd-icons-flicon "brain"))
                          ((string-prefix-p "info:" link)
                           (nerd-icons-octicon "info"))
                          ((string-prefix-p "help:" link)
                           (nerd-icons-material "help"))
                          ((string-prefix-p "http" link)
                           (nerd-icons-icon-for-url link))
                          (t
                           (nerd-icons-icon-for-file link))))))

  :config
  (add-hook 'org-brain-after-resource-button-functions #'org-brain-insert-resource-icon)
  :custom
  (org-id-track-globally t)
  (org-id-locations-file (expand-file-name "/org-id-locations" user-emacs-directory))
  (org-brain-visualize-default-choices 'all)
  (org-brain-title-max-length 24)
  (org-brain-include-file-entries t)
  (org-brain-file-entries-use-title t)
  :commands
  org-brain-visualize
  :hook
  (before-save . org-brain-ensure-ids-in-buffer))

A simple command that takes a URL from the clipboard and inserts an org-mode link with a title of a page found by the URL into the current buffer.

(use-package org-cliplink
  :after org)

This package implements a modern style for your Org buffers using font locking and text properties. The package styles headlines, keywords, tables and source blocks.

(use-package org-modern
  :hook (org-mode . org-modern-mode)
  :custom
  (org-modern-fold-stars '(("" . "") ("" . "") ("" . "")))
  (org-modern-star 'fold)
  (org-modern-label-border 0.3)

  ;; Edit settings
  (org-auto-align-tags t)
  (org-tags-column 0)
  (org-catch-invisible-edits 'show-and-error)
  (org-special-ctrl-a/e t)
  (org-insert-heading-respect-content t)

  ;; Org styling, hide markup etc.
  (org-hide-emphasis-markers t)
  (org-pretty-entities t)

  ;; Agenda styling
  (org-agenda-tags-column 0)
  (org-agenda-block-separator ?─)
  (org-agenda-time-grid
   '((daily today require-timed)
     (800 1000 1200 1400 1600 1800 2000)
     " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
   org-agenda-current-time-string
   "⭠ now ─────────────────────────────────────────────────"))

Modern block styling with org-indent.

(use-package org-modern-indent
  :straight (:host github :repo "jdtsmith/org-modern-indent")
  :hook
  (org-indent-mode . org-modern-indent-mode))

Emacs document annotator, using Org-mode.

(use-package org-noter
  :after org
  :custom
  ;; The WM can handle splits
  ;; org-noter-notes-window-location 'other-frame
  ;; Please stop opening frames
  (org-noter-always-create-frame nil)
  ;; I want to see the whole file
  (org-noter-hide-other nil)
  ;; Everything is relative to the main notes file
  ;; org-noter-notes-search-path (list bibtex-completion-notes-path)
  (org-noter-highlight-selected-text t)
  :hook
  ;; Org-noter’s purpose is to let you create notes that are kept in sync when
  ;; you scroll through the [PDF etc] document
  (org-noter-insert-heading . org-id-get-create))

Pomodoro technique for org-mode.

(use-package org-pomodoro
  :custom
  (org-pomodoro-audio-player (or (executable-find "paplay")
                                 org-pomodoro-audio-player))
  :config
  (use-package alert
    :config
    (alert-add-rule :category "org-pomodoro"
                    :style (cond (alert-growl-command
                                  'growl)
                                 (alert-notifier-command
                                  'notifier)
                                 (alert-libnotify-command
                                  'libnotify)
                                 (alert-default-style))))
  :bind
  (:map org-mode-map
        ("C-c p" . org-pomodoro)
        :map org-agenda-keymap
        ("p" . org-pomodoro)))

Ultra-minimalist presentation minor-mode for Emacs org-mode. Inspired by: https://systemcrafters.net/emacs-tips/presentations-with-org-present/

(use-package org-present
  :after org
  :preface
  (defun my/org-present-start ()
    (org-present-read-only)
    (org-display-inline-images)

    ;; Hide Property drawers
    (org-tidy-mode 1)

    ;; Tweak font sizes
    (setq-local face-remapping-alist '((header-line (:height 4.0) variable-pitch)
                                       (org-document-title (:height 2.0) org-document-title)
                                       (org-level-1 (:height 1.2) org-level-1)
                                       (org-level-2 (:height 1.1) org-level-2)
                                       (org-default (:inherit fixed-pitch) org-default)
                                       (org-table (:inherit fixed-pitch) org-table)
                                       (org-code (:inherit fixed-pitch) org-code)
                                       (org-verbatim (:inherit fixed-pitch) org-verbatim)
                                       (org-hide (:inherit fixed-pitch) org-hide)
                                       (default (:inherit variable-pitch))))

    ;; Set a blank header line string to create blank space at the top
    (setq-local header-line-format " ")

    ;; Configure fill width
    (setq-local visual-fill-column-width 80
                visual-fill-column-center-text t)

    ;; Remove org modern borders from blocks
    (setq-local org-modern-block-fringe nil)

    ;; Center the presentation and wrap lines
    (visual-fill-column-mode 1)

    ;; hide the mode line
    (hide-mode-line-mode 1)

    ;; disable fringes
    (set-fringe-mode 0)

    ;; Increase font size
    (org-present-big))
  (defun my/org-present-quit ()
    (org-present-read-write)
    (org-remove-inline-images)

    ;; Show Property drawers
    (org-tidy-untidy-buffer)
    (org-tidy-mode 0)

    ;; Reset font customizations
    (kill-local-variable 'face-remapping-alist)

    ;; Clear the header line string so that it isn't displayed
    (kill-local-variable 'header-line-format)

    ;; Configure fill width
    (kill-local-variable 'visual-fill-column-width)
    (kill-local-variable 'visual-fill-column-center-text)

    ;; Reset org modern borders from blocks
    (kill-local-variable 'org-modern-block-fringe)

    ;; Stop centering the presentation and wrap lines
    (visual-fill-column-mode 0)

    ;; Stop hiding the mode line
    (hide-mode-line-mode 0)

    ;; reset fringes to default style
    (set-fringe-mode nil)

    ;; Restore font size
    (org-present-small))
  (defun my/org-present-prepare-slide (buffer-name heading)
    ;; Show only top-level headlines
    (org-overview)

    ;; Unfold the current entry
    (org-show-entry)

    ;; Show only direct subheadings of the slide but don't expand them
    (org-show-children))
  :bind
  (:map org-present-mode-keymap
        ("q" . org-present-quit)
        ("C-<left>" . org-present-prev)
        ("C-<right>" . org-present-next))
  :config
  (define-key org-present-mode-keymap (kbd "<left>") nil t)
  (define-key org-present-mode-keymap (kbd "<right>") nil t)
  (add-hook 'org-present-after-navigate-functions 'my/org-present-prepare-slide)
  :hook
  ((org-present-mode . my/org-present-start)
   (org-present-mode-quit . my/org-present-quit)))
(use-package org-preview
  :straight (:host github :repo "karthink/org-preview")
  :hook
  (org-mode . org-preview-mode))

An Emacs minor mode to automatically tidy org-mode property drawers.

(use-package org-tidy
  :after org)

Use Org Mode links in other modes.

(use-package orglink
  :hook
  (prog-mode . orglink-mode))

Toc-org is an Emacs utility to have an up-to-date table of contents in the org files without exporting (useful primarily for readme files on GitHub).

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

Library Footer

(provide 'my-org)
;;; my-org.el ends here

Tools

:header-args+: :tangle lisp/my-tools.el
(require 'my-tools)

Conventional Header

<<header(file_name="my-tools.el")>>

dired

(use-package dired
  :straight nil
  :custom
  ;; inspired by doom
  ;; https://github.com/doomemacs/doomemacs/blob/c2818bcfaa5dc1a0139d1deff7d77bf42a08eede/modules/emacs/dired/config.el#L9C1-L25C36
  (dired-dwim-target t)  ; suggest a target for moving/copying intelligently
  (dired-hide-details-hide-symlink-targets nil)
  ;; don't prompt to revert, just do it
  (dired-auto-revert-buffer #'dired-buffer-stale-p)
  ;; Always copy/delete recursively
  (dired-recursive-copies  'always)
  (dired-recursive-deletes 'top)
  ;; Ask whether destination dirs should get created when copying/removing files.
  (dired-create-destination-dirs 'ask)
  ;; Screens are larger nowadays, we can afford slightly larger thumbnails
  (image-dired-thumb-size 150)
  (delete-by-moving-to-trash t)
  (dired-listing-switches
   "-l --almost-all --human-readable --group-directories-first --no-group")
  ;; kill all session buffers on quit
  (dirvish-reuse-session nil)
  ;; Enable mouse drag-and-drop support
  (dired-mouse-drag-files t)                   ; added in Emacs 29
  (mouse-drag-and-drop-region-cross-program t) ; added in Emacs 29
  :bind
  (:map my/open-map
        ("d" . dired)))

(use-package dired-x
  :straight nil
  :config
  ;; Make dired-omit-mode hide all "dotfiles"
  (setq dired-omit-files
        (concat dired-omit-files "\\|^\\..*$"))
  :hook
  (dired-mode . dired-omit-mode))

Extra Emacs font lock rules for a more colourful dired.

(use-package diredfl
  :hook
  ((dired-mode . diredfl-mode)
   (dirvish-directory-view-mode . diredfl-mode)))

A polished Dired with batteries included.

(use-package dirvish
  :after dired
  :custom
  (dirvish-quick-access-entries ; It's a custom option, `setq' won't work
   '(("h" "~/"                          "Home")
     ("d" "~/Downloads/"                "Downloads")
     ("t" "~/.local/share/Trash/files/" "TrashCan")))
  (dirvish-mode-line-format
   '(:left (sort symlink) :right (vc-info yank index)))
  (dirvish-attributes
   '(nerd-icons file-time file-size collapse subtree-state vc-state git-msg))
  (dirvish-subtree-state-style 'nerd)
  (dirvish-path-separators (list
                            (format "  %s " (nerd-icons-codicon "nf-cod-home"))
                            (format "  %s " (nerd-icons-codicon "nf-cod-root_folder"))
                            (format " %s " (nerd-icons-faicon "nf-fa-angle_right"))))
  ;; (dirvish-use-header-line nil)
  ;; (dirvish-use-mode-line nil)
  :preface
  (defun my/dirvish-side-hide-buffer (&rest app)
    "make dirvish-side buffer 'uninteresting' for buffer related commands"
    (apply app)
    (with-selected-window (dirvish-side--session-visible-p)
      (rename-buffer (concat " " (buffer-name)))))
  :init
  (dirvish-override-dired-mode)
  ;; (dirvish-peek-mode) ; Preview files in minibuffer
  :config
  (dirvish-side-follow-mode) ; similar to `treemacs-follow-mode'
  (with-eval-after-load 'doom-modeline
    (setq dirvish-mode-line-height doom-modeline-height)
    (setq dirvish-header-line-height
          doom-modeline-height))
  (advice-add #'dirvish-side--new :around #'my/dirvish-side-hide-buffer)
  :bind ; Bind `dirvish|dirvish-side|dirvish-dwim' as you see fit
  (("C-c f" . dirvish-fd)
   :map my/open-map
   ("D" . dirvish)
   :map my/toggle-map
   ("d" . dirvish-side)
   :map dirvish-mode-map ; Dirvish inherits `dired-mode-map'
   ("<mouse-1>" . dirvish-subtree-toggle-or-open)
   ("<mouse-2>" . dired-mouse-find-file-other-window)
   ("F" . dirvish-toggle-fullscreen)
   ("M-b" . dirvish-history-go-backward)
   ("M-e" . dirvish-emerge-menu)
   ("M-f" . dirvish-history-go-forward)
   ("M-j" . dirvish-fd-jump)
   ("M-l" . dirvish-ls-switches-menu)
   ("M-m" . dirvish-mark-menu)
   ("M-s" . dirvish-setup-menu)
   ("M-t" . dirvish-layout-toggle)
   ("N"   . dirvish-narrow)
   ("TAB" . dirvish-subtree-toggle)
   ("^"   . dirvish-history-last)
   ("a"   . dirvish-quick-access)
   ("b"   . dirvish-goto-bookmark)
   ("f"   . dirvish-file-info-menu)
   ("h"   . dirvish-history-jump) ; remapped `describe-mode'
   ("s"   . dirvish-quicksort)    ; remapped `dired-sort-toggle-or-edit'
   ("v"   . dirvish-vc-menu)      ; remapped `dired-view-file'
   ("y"   . dirvish-yank-menu)
   ("z" . dirvish-show-history)))

ediff

The ediff package is utilized to handle file differences in emacs. We will tweak the Emacs built-in ediff configuration a bit. Emacs literate configuration

(use-package ediff
  :straight nil
  :preface
  (defvar my-ediff-original-windows nil)
  (defun my/store-pre-ediff-winconfig ()
    "This function stores the current window configuration before opening ediff."
    (setq my/ediff-original-windows (current-window-configuration)))
  (defun my/restore-pre-ediff-winconfig ()
    "This function resets the original window arrangement."
    (set-window-configuration my/ediff-original-windows))
  :custom
  (ediff-window-setup-function 'ediff-setup-windows-plain)
  (ediff-split-window-function 'split-window-horizontally)
  :hook
  ((ediff-before-setup . my/store-pre-ediff-winconfig)
   (ediff-quit . my/restore-pre-ediff-winconfig)))

An Emacs web feeds client.

(use-package elfeed
  :bind
  (:map my/open-map
        ("f" . elfeed))
  :config
  (setq elfeed-feeds
        (split-string (shell-command-to-string "for d in ~/.emacs.d/straight/repos/*; do git -C $d remote get-url origin; done | grep -P '(github)' | sed 's:\\.git:/releases.atom:'"))))

Make Emacs use the $PATH set up by the user’s shell.

(use-package exec-path-from-shell
  :preface
  (defun my/copy-ssh-env ()
    (exec-path-from-shell-copy-env "SSH_AGENT_PID")
    (exec-path-from-shell-copy-env "SSH_AUTH_SOCK"))
  :hook
  ((after-init . exec-path-from-shell-initialize)
   (magit-credential . my/copy-ssh-env)))

flyspell

(use-package flyspell
  :straight nil
  :custom
  ;; Doom: https://github.com/doomemacs/doomemacs/blob/dbb48712eea6dfe16815a3e5e5746b31dab6bb2f/modules/checkers/spell/config.el#L195C11-L198C42
  (flyspell-issue-welcome-flag nil)
  ;; Significantly speeds up flyspell, which would otherwise print
  ;; messages for every word when checking the entire buffer
  (flyspell-issue-message-flag nil)
  :preface
  (defun my/restart-flyspell-mode ()
    (when flyspell-mode
      (flyspell-mode-off)
      (flyspell-mode-on)
      (flyspell-buffer)))
  :hook
  (((text-mode org-mode LaTeX-mode) . flyspell-mode)
   ((prog-mode conf-mode) . flyspell-prog-mode)
   (ispell-change-dictionary . restart-flyspell-mode)))

Distraction-free words correction with flyspell via selected interface.

(use-package flyspell-correct
  :after flyspell
  :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)
              :map flyspell-mouse-map ("RET" . flyspell-correct-at-point)
              ([mouse-1] . flyspell-correct-at-point)))

A simple LLM client for Emacs.

(use-package gptel
  :custom
  (gptel-default-mode 'org-mode)
  :bind
  (:map my/open-map
        ("g". gptel))
  :commands (gptel gptel-send)
  :config
  (gptel-make-gemini "Gemini" :key #'gptel-api-key-from-auth-source :stream t))

Helpful is an alternative to the built-in Emacs help that provides much more contextual information. It is a bit slow to load so we do need load it explicitely.

(use-package helpful
  :bind
  (([remap describe-function] . helpful-function)
   ([remap describe-symbol] . helpful-symbol)
   ([remap describe-variable] . helpful-variable)
   ([remap describe-command] . helpful-command)
   ([remap describe-key] . helpful-key)
   ("C-h K" . describe-keymap)
   :map helpful-mode-map
   ([remap revert-buffer] . helpful-update)))

ispell

(use-package ispell
  :straight nil
  :after flyspell
  :custom
  (ispell-program-name "hunspell")
  (ispell-dictionary "en_US,de_DE")
  :config
  (ispell-set-spellchecker-params)
  (ispell-hunspell-add-multi-dic "en_US,de_DE"))

Emacs support library for PDF files.

(use-package pdf-tools
  :magic ("%PDF" . pdf-view-mode)
  :functions (pdf-view-refresh-themed-buffer)
  :preface
  (defun my/pdf-tools-themed-update-advice (&rest app)
    (when pdf-view-themed-minor-mode
      (pdf-view-refresh-themed-buffer t)))
  :custom
  (pdf-view-use-scaling t)
  :config
  (pdf-tools-install :no-query)
  (advice-add #'enable-theme :after #'my/pdf-tools-themed-update-advice)
  :hook
  ((pdf-view-mode . pdf-view-themed-minor-mode)
   (pdf-view-mode . pdf-isearch-minor-mode)))

re-builder

Change re-builder syntax

;; https://www.masteringemacs.org/article/re-builder-interactive-regexp-builder
(use-package re-builder
  :straight nil
  :commands re-builder
  :custom
  (reb-re-syntax 'string))

server

Server start.

(use-package server
  :straight nil
  :config
  (unless (server-running-p)
    (server-start)))

term

Major mode for interacting with a terminal

(use-package term
  :straight nil
  :commands term
  :unless (not (file-exists-p "/bin/zsh")) ; we only use it if shell exists
  :custom
  (shell-file-name "/bin/zsh")
  (explicit-shell-file-name "/bin/zsh"))

tramp

remote file editing through ssh/scp.

(use-package tramp
  :straight nil
  :custom
  (tramp-default-method "ssh")
  (tramp-encoding-shell "/usr/bin/zsh")
  (remote-file-name-inhibit-cache nil)
  (vc-ignore-dir-regexp
   (format "%s\\|%s"
           vc-ignore-dir-regexp
           tramp-file-name-regexp))
  :config
  (add-to-list 'tramp-connection-properties
               (list (regexp-quote "/sshx:user@host:")
                     "remote-shell" "/bin/bash")))

Emacs libvterm integration.

;; https://www.reddit.com/r/emacs/comments/wu5rxi/comment/ilagtzv/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
(use-package vterm
  :bind
  (:map my/open-map
        ("v" . vterm)
        :map project-prefix-map
        ("t" . my/project-vterm)
        :map vterm-mode-map
        ("C-<escape>" . vterm-send-escape))
  :preface
  (defun my/project-vterm ()
    (interactive)
    (defvar vterm-buffer-name)
    (let* ((default-directory (project-root     (project-current t)))
           (vterm-buffer-name (project-prefixed-buffer-name "vterm"))
           (vterm-buffer (get-buffer vterm-buffer-name)))
      (if (and vterm-buffer (not current-prefix-arg))
          (pop-to-buffer vterm-buffer  (bound-and-true-p display-comint-buffer-action))
        (vterm))))
  :init
  (with-eval-after-load 'project
    (add-to-list 'project-switch-commands     '(my/project-vterm "Vterm") t)
    (add-to-list 'project-kill-buffer-conditions  '(major-mode . vterm-mode)))
  :custom
  (vterm-copy-exclude-prompt t)
  (vterm-max-scrollback 100000)
  (vterm-tramp-shells '(("ssh" "/bin/bash")
                        ("podman" "/bin/bash"))))

Vundo (visual undo) displays the undo history as a tree and lets you move in the tree to go back to previous buffer states.

(use-package vundo
  :bind
  (:map my/open-map
        ("u". vundo))
  :config
  (when (display-graphic-p)
    (setq vundo-glyph-alist vundo-unicode-symbols)))

Library Footer

(provide 'my-tools)
;;; my-tools.el ends here

Completion

:header-args+: :tangle lisp/my-completion.el
(require 'my-completion)

Conventional Header

<<header(file_name="my-completion.el")>>

Cape provides Completion At Point Extensions which can be used in combination with Corfu, Company or the default completion UI. The completion backends used by completion-at-point are so called completion-at-point-functions (Capfs).

(use-package cape
  ;; Bind dedicated completion commands
  ;; Alternative prefix keys: C-c p, M-p, M-+, ...
  :bind (:map my/completion-map
              ("p" . completion-at-point) ;; capf
              ("t" . complete-tag)        ;; etags
              ("d" . cape-dabbrev)        ;; or dabbrev-completion
              ("h" . cape-history)
              ("f" . cape-file)
              ("k" . cape-keyword)
              ("s" . cape-symbol)
              ("a" . cape-abbrev)
              ("l" . cape-line)
              ("w" . cape-dict)
              ("\\" . cape-tex)
              ("_" . cape-tex)
              ("^" . cape-tex)
              ("&" . cape-sgml)
              ("r" . cape-rfc1345))
  :init
  ;; Add `completion-at-point-functions', used by `completion-at-point'.
  ;; NOTE: The order matters!
  (add-to-list 'completion-at-point-functions #'cape-dabbrev)
  (add-to-list 'completion-at-point-functions #'cape-elisp-block)
  (add-to-list 'completion-at-point-functions #'cape-history)
  (add-to-list 'completion-at-point-functions #'cape-file)
  ;;(add-to-list 'completion-at-point-functions #'cape-keyword)
  ;;(add-to-list 'completion-at-point-functions #'cape-tex)
  ;;(add-to-list 'completion-at-point-functions #'cape-sgml)
  ;;(add-to-list 'completion-at-point-functions #'cape-rfc1345)
  ;;(add-to-list 'completion-at-point-functions #'cape-abbrev)
  ;;(add-to-list 'completion-at-point-functions #'cape-dict)
  ;;(add-to-list 'completion-at-point-functions #'cape-elisp-symbol)
  ;;(add-to-list 'completion-at-point-functions #'cape-line)

  ;; The advices are only needed on Emacs 28 and older.
  (when (< emacs-major-version 29)
    ;; Silence the pcomplete capf, no errors or messages!
    (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent)

    ;; Ensure that pcomplete does not write to the buffer
    ;; and behaves as a pure `completion-at-point-function'.
    (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify)))

Citar provides a highly-configurable completing-read front-end to browse and act on BibTeX, BibLaTeX, and CSL JSON bibliographic data, and LaTeX, markdown, and org-cite editing support.

(use-package citar
  :custom
  (org-cite-insert-processor 'citar)
  (org-cite-follow-processor 'citar)
  (org-cite-activate-processor 'citar)
  (citar-bibliography org-cite-global-bibliography)
  (citar-at-point-function 'embark-act)
  (citar-notes-paths (list (concat org-directory "brain/bib_notes/")))
  (citar-templates `((main . "${author editor:30}     ${date year issued:4}     ${title:48}")
                     (suffix . "          ${=key= id:15}    ${=type=:12}    ${tags keywords:*}")
                     (preview . "${author editor} (${year issued date}) ${title}, ${journal journaltitle publisher container-title collection-title}.\n")
                     (note . ,(concat "#+TITLE: ${title}\n"
                                      "#+AUTHOR: ${author editor}\n"
                                      "#+DATE: ${date}\n"
                                      "#+SOURCE: ${doi url}\n"
                                      "#+CUSTOM_ID: ${=key= id}\n"
                                      "#+cite_export: biblatex ieee\n"
                                      (concat "#+bibliography: " (car citar-bibliography) "\n\n")
                                      "* Notes :ignore:\n"
                                      ":PROPERTIES:\n"
                                      ":NOTER_DOCUMENT: ${file} \n"
                                      ":END:\n\n"
                                      "* Summary :childless:showchildren:export:\n"
                                      "This is a summary of [cite/t:@${=key=}].\n"
                                      "** Bibliography :ignore:\n"
                                      ))))
  (citar-symbol-separator "  ")
  :config
  (defvar citar-indicator-files-icons
    (citar-indicator-create
     :symbol (nerd-icons-faicon
              "nf-fa-file_o"
              :face 'nerd-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 (nerd-icons-octicon
              "nf-oct-link"
              :face 'nerd-icons-orange
              :v-adjust 0.01)
     :function #'citar-has-links
     :padding "  "
     :tag "has:links"))
  (defvar citar-indicator-notes-icons
    (citar-indicator-create
     :symbol (nerd-icons-mdicon
              "nf-md-pencil"
              :face 'nerd-icons-blue
              :v-adjust 0.01)
     :function #'citar-has-notes
     :padding "  "
     :tag "has:notes"))
  (defvar citar-indicator-cited-icons
    (citar-indicator-create
     :symbol (nerd-icons-faicon
              "nf-fa-circle_o"
              :face 'nerd-icons-green)
     :function #'citar-is-cited
     :padding "  "
     :tag "is:cited"))
  (setq citar-indicators
        (list citar-indicator-files-icons
              citar-indicator-links-icons
              citar-indicator-notes-icons
              citar-indicator-cited-icons))
  ;; optional: org-cite-insert is also bound to C-c C-x C-@
  ;;:bind
  ;;(:map org-mode-map :package org ("C-c b" . #'org-cite-insert))
  :hook
  ((LaTeX-mode . citar-capf-setup)
   (org-mode . citar-capf-setup)))

(use-package citar-embark
  :hook
  ((LaTeX-mode . citar-embark-mode)
   (org-mode . citar-embark-mode)))

Additional featureful completion commands.

;; Example configuration for Consult
(use-package consult
  ;; Replace bindings. Lazily loaded due by `use-package'.
  :bind (([remap Info-search] . consult-info)
         ([remap recentf-open] . consult-recent-file)
         ([remap bookmark-jump]                 . consult-bookmark)
         ([remap goto-line]                     . consult-goto-line)
         ([remap imenu]                         . consult-imenu)
         ([remap locate]                        . consult-locate)
         ([remap load-theme]                    . consult-theme)
         ([remap man]                           . consult-man)
         ([remap recentf-open-files]            . consult-recent-file)
         ([remap switch-to-buffer]              . consult-buffer)
         ([remap switch-to-buffer-other-window] . consult-buffer-other-window)
         ([remap switch-to-buffer-other-frame]  . consult-buffer-other-frame)
         ([remap yank-pop]                      . consult-yank-pop)
         ([remap project-list-buffers]          . consult-project-buffer)
         ("M-y" . consult-yank-pop)                ;; orig. yank-pop
         :map my/buffer-map
         ("b" . consult-buffer)                ;; orig. switch-to-buffer
         ("w" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
         ("f" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
         :map goto-map
         ;; M-g bindings in `goto-map'
         ("e" . consult-compile-error)
         ("f" . consult-flymake)               ;; Alternative: consult-flycheck
         ("g" . consult-goto-line)             ;; orig. goto-line
         ("o" . consult-outline)               ;; Alternative: consult-org-heading
         ("m" . consult-mark)
         ("k" . consult-global-mark)
         ("i" . consult-imenu)
         ("I" . consult-imenu-multi)
         :map search-map
         ("d" . consult-find)
         ("D" . consult-locate)
         ("g" . consult-grep)
         ("G" . consult-git-grep)
         ("r" . consult-ripgrep)
         ("l" . consult-line)
         ("L" . consult-line-multi)
         ("k" . consult-keep-lines)
         ("u" . consult-focus-lines)
         ;; Isearch integration
         ("e" . consult-isearch-history)
         :map isearch-mode-map
         ("M-e" . consult-isearch-history)         ;; orig. isearch-edit-string
         ("M-s e" . consult-isearch-history)       ;; orig. isearch-edit-string
         ("M-s l" . consult-line)                  ;; needed by consult-line to detect isearch
         ("M-s L" . consult-line-multi)            ;; needed by consult-line to detect isearch
         ;; Minibuffer history
         :map minibuffer-local-map
         ("M-s" . consult-history)                 ;; orig. next-matching-history-element
         ("M-r" . consult-history))                ;; orig. previous-matching-history-element

  :custom
  ;; Optionally configure the register formatting. This improves the register
  ;; preview for `consult-register', `consult-register-load',
  ;; `consult-register-store' and the Emacs built-ins.
  (register-preview-delay 0.5)
  (register-preview-function #'consult-register-format)

  ;; Use Consult to select xref locations with preview
  (xref-show-xrefs-function #'consult-xref)
  (xref-show-definitions-function #'consult-xref)

  ;; Optionally configure the narrowing key.
  ;; Both < and C-+ work reasonably well.
  (consult-narrow-key "<") ;; "C-+"

  :config
  ;; Optionally tweak the register preview window.
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)

  ;; Optionally configure preview. The default value
  ;; is 'any, such that any key triggers the preview.
  ;; (setq consult-preview-key 'any)
  ;; (setq consult-preview-key "M-.")
  ;; (setq consult-preview-key '("S-<down>" "S-<up>"))
  ;; For some commands and buffer sources it is useful to configure the
  ;; :preview-key on a per-command basis using the `consult-customize' macro.
  (consult-customize
   consult-theme :preview-key '(:debounce 0.2 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult--source-bookmark consult--source-file-register
   consult--source-recent-file consult--source-project-recent-file
   ;; :preview-key "M-."
   :preview-key '(:debounce 0.4 any))

  ;; Configure a different project root function.
  (with-eval-after-load 'projectile
    (autoload 'projectile-project-root "projectile")
    (setq consult-project-function (lambda (_) (projectile-project-root)))))

Searching and jumping to TODO keywords using consult.

(use-package consult-todo
  :after consult hl-todo)

Corfu is the minimalistic in-buffer completion counterpart of the Vertico minibuffer UI.

(use-package corfu
  :custom
  ;; TAB cycle if there are only few candidates
  (completion-cycle-threshold nil)

  ;; Emacs 28: Hide commands in M-x which do not apply to the current mode.
  ;; Corfu commands are hidden, since they are not supposed to be used via M-x.
  (read-extended-command-predicate
   #'command-completion-default-include-p)

  ;; Enable indentation+completion using the TAB key.
  ;; `completion-at-point' is often bound to M-TAB.
  (tab-always-indent 'complete)

  ;; Additional Customisations
  (corfu-cycle t)                  ;; Enable cycling for `corfu-next/previous'
  ;;(corfu-auto t)                   ;; Enable auto completion
  (corfu-quit-no-match 'separator) ;; Quit auto complete if there is no match
  (corfu-auto-prefix 1)            ;; Complete with less prefix keys)
  (corfu-auto-delay 0.0)           ;; No delay for completion
  (corfu-popupinfo-delay 0.5)      ;; speed up documentation popup
  (corfu-quit-at-boundary nil)     ;; Never quit at completion boundary
  (corfu-preview-current t)        ;; Disable current candidate preview
  (corfu-preselect 'directory)        ;; Preselect the prompt

  :preface
  ;; fix uneeded duble return in eshell
  (defun my/corfu-send-shell (&rest _)
    "Send completion candidate when inside comint/eshell."
    (cond
     ((and (derived-mode-p 'eshell-mode) (fboundp 'eshell-send-input))
      (eshell-send-input))
     ((and (derived-mode-p 'comint-mode)  (fboundp 'comint-send-input))
      (comint-send-input))))

  ;; Completing in the minibuffer
  (defun my/corfu-enable-always-in-minibuffer ()
    "Enable Corfu in the minibuffer if Vertico/Mct are not active."
    (unless (or (bound-and-true-p mct--active)
                (bound-and-true-p vertico--input)
                (eq (current-local-map) read-passwd-map))
      ;; (setq-local corfu-auto nil) ;; Enable/disable auto completion
      (setq-local corfu-echo-delay nil ;; Disable automatic echo and popup
                  corfu-popupinfo-delay nil)
      (corfu-mode 1)))

  ;; https://github.com/minad/corfu/wiki#same-key-used-for-both-the-separator-and-the-insertion
  (defun my/corfu-spc-handler ()
    (interactive)
    (if current-prefix-arg
        ;;we suppose that we want leave the word like that, so do a space
        (progn
          (corfu-quit)
          (insert " "))
      (if (and (= (char-before) corfu-separator)
               (or
                ;; check if space, return or nothing after
                (not (char-after))
                (= (char-after) ?\s)
                (= (char-after) ?\n)))
          (progn
            (corfu-insert)
            (insert " "))
        (corfu-insert-separator))))
  :config
  (when (fboundp 'straight-use-package)
    (add-to-list 'load-path
                 (expand-file-name "straight/build/corfu/extensions"
                                   straight-base-dir)))
  (require 'corfu-echo)
  (require 'corfu-history)
  (require 'corfu-popupinfo)
  (eldoc-add-command #'corfu-insert)

  ;; Completing in the Eshell or Shell
  (advice-add #'corfu-insert :after #'my/corfu-send-shell)
  ;; Use TAB-and-Go completion
  ;; https://github.com/minad/corfu/wiki#tab-and-go-completion
  (dolist (c (list (cons "." ".")
                   (cons "," ",")
                   (cons ":" ":")
                   (cons ")" ")")
                   (cons "}" "}")
                   (cons "]" "]")))
    (define-key corfu-map (kbd (car c)) `(lambda ()
                                           (interactive)
                                           (corfu-insert)
                                           (insert ,(cdr c)))))
  :bind
  (("C-SPC" . completion-at-point)
   :map corfu-map
   ("TAB" . corfu-next)
   ([tab] . corfu-next)
   ("S-TAB" . corfu-previous)
   ([backtab] . corfu-previous)
   ("SPC" . my/corfu-spc-handler))
  :hook
  ;; Recommended: Enable Corfu globally.
  ;; This is recommended since Dabbrev can be used globally (M-/).
  ;; See also `corfu-exclude-modes'.
  ((after-init . global-corfu-mode)
   (after-init . corfu-popupinfo-mode)
   (after-init . corfu-echo-mode)
   (after-init . corfu-history-mode)
   ;; disable auto completion for eshell, such that the completion behavior is similar to widely used shells like Bash, Zsh or Fish.
   (eshell-mode-hook . (lambda ()
                         (setq-local corfu-auto nil)
                         (corfu-mode)))
   ;; Enable minibuffer completion
   (minibuffer-setup . my/corfu-enable-always-in-minibuffer)))

(use-package corfu-terminal
  :if (not (display-graphic-p))
  :after corfu
  :hook
  (global-corfu-mode . corfu-terminal-mode))
(use-package corfu-candidate-overlay
  :straight (:type git :repo "https://code.bsdgeek.org/adam/corfu-candidate-overlay" :files (:defaults "*.el"))
  :after corfu
  :hook
  ;; enable corfu-candidate-overlay mode globally
  ;; this relies on having corfu-auto set to nil
  (global-corfu-mode . corfu-candidate-overlay-mode))

dabbrev

(use-package dabbrev
  :straight nil
  ;; Swap M-/ and C-M-/
  :bind (("M-/" . dabbrev-completion)
         ("C-M-/" . dabbrev-expand))
  ;; Other useful Dabbrev configurations.
  :custom
  (dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'")))

Embark makes it easy to choose a command to run based on what is near point, both during a minibuffer completion session (in a way familiar to Helm or Counsel users) and in normal buffers.

(use-package embark
  :after which-key
  :bind
  (("C-." . embark-act)         ;; pick some com fortable binding
   ("C-:" . embark-dwim)        ;; good alternative: M-.
   ("C-h B" . embark-bindings)  ;; alternative for `describe-bindings'
   :map vertico-map
   ("C-SPC" . embark-select))   ;; good alternative: M-.

  :custom
  ;; Optionally replace the key help with a completing-read interface
  (prefix-help-command #'embark-prefix-help-command)

  :preface
  ;; The built-in embark-verbose-indicator displays actions in a buffer along with their keybindings and the first line of their docstrings.
  ;; Users desiring a more compact display can use which-key instead with the following configuration:
  ;; ref.: https://github.com/oantolin/embark/wiki/Additional-Configuration#use-which-key-like-a-key-menu-prompt
  (defun embark-which-key-indicator ()
    "An embark indicator that displays keymaps using which-key.
  The which-key help message will show the type and value of the
  current target followed by an ellipsis if there are further
  targets."
    (lambda (&optional keymap targets prefix)
      (if (null keymap)
          (which-key--hide-popup-ignore-command)
        (which-key--show-keymap
         (if (eq (plist-get (car targets) :type) 'embark-become)
             "Become"
           (format "Act on %s '%s'%s"
                   (plist-get (car targets) :type)
                   (embark--truncate-target (plist-get (car targets) :target))
                   (if (cdr targets) "" "")))
         (if prefix
             (pcase (lookup-key keymap prefix 'accept-default)
               ((and (pred keymapp) km) km)
               (_ (key-binding prefix 'accept-default)))
           keymap)
         nil nil t (lambda (binding)
                     (not (string-suffix-p "-argument" (cdr binding))))))))

  (defun embark-hide-which-key-indicator (fn &rest args)
    "Hide the which-key indicator immediately when using
the completing-read prompter."
    (which-key--hide-popup-ignore-command)
    (let ((embark-indicators
           (remq #'embark-which-key-indicator embark-indicators)))
      (apply fn args)))

  :config
  ;; Show the Embark target at point via Eldoc.  You may adjust the Eldoc
  ;; strategy, if you want to see the documentation from multiple providers.
  (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
  ;; (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)

  ;; 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))))

  (setq embark-indicators
        '(embark-which-key-indicator
          embark-highlight-indicator
          embark-isearch-highlight-indicator))


  (advice-add #'embark-completing-read-prompter
              :around #'embark-hide-which-key-indicator))

;; Consult users will also want the embark-consult package.
(use-package embark-consult
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))
(use-package lsp-snippet-tempel
  :straight (:host github :repo "svaante/lsp-snippet")
  :after tempel eglot
  :config
  ;; Initialize lsp-snippet -> tempel in eglot
  (lsp-snippet-tempel-eglot-init))

Marginalia in the minibuffer.

(use-package marginalia
  :after vertico
  :custom
  (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
  :hook
  (vertico-mode . marginalia-mode))
(use-package nerd-icons-completion
  :after marginalia vertico
  :config
  (nerd-icons-completion-mode)
  :hook
  (marginalia-mode . nerd-icons-completion-marginalia-setup))

Icons for corfu via nerd-icons.

(use-package nerd-icons-corfu
  :preface
  (defun my/add-nerd-icons-formatter nil
    (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))
  :hook
  (corfu-mode . my/add-nerd-icons-formatter))

Emacs completion style that matches multiple regexps in any order

(use-package orderless
  :after vertico
  :preface
  ;; In combination with Orderless or other non-prefix completion styles like substring or flex,
  ;; host names and user names are not made available for completion after entering /ssh:.
  (defun basic-remote-try-completion (string table pred point)
    (and (vertico--remote-p string)
         (completion-basic-try-completion string table pred point)))
  (defun basic-remote-all-completions (string table pred point)
    (and (vertico--remote-p string)
         (completion-basic-all-completions string table pred point)))

  :config
  (add-to-list
   'completion-styles-alist
   '(basic-remote basic-remote-try-completion basic-remote-all-completions nil))

  :custom
  (completion-styles '(orderless basic))
  (completion-category-defaults nil)
  (completion-category-overrides '((file (styles basic-remote partial-completion)))))

Tempel is a tiny template package for Emacs, which uses the syntax of the Emacs Tempo library. Tempo is an ancient temple of the church of Emacs. It is 27 years old, but still in good shape since it successfully resisted change over the decades. However it may look a bit dusty here and there. Therefore we present Tempel, a new implementation of Tempo with inline expansion and integration with recent Emacs facilities. Tempel takes advantage of the standard completion-at-point-functions mechanism which is used by Emacs for in-buffer completion.

;; Configure Tempel
(use-package tempel
  :custom
  ;; Require trigger prefix before template name when completing.
  ;; (tempel-trigger-prefix ">")
  (tempel-path my/templates-path)

  :bind (("M-+" . tempel-expand) ;; Alternative tempel-expand
         ("M-*" . tempel-insert)
         :map tempel-map
         ("TAB" . tempel-next)
         ([tab] . tempel-next)
         ("S-TAB" . tempel-previous)
         ([backtab] . tempel-previous))

  :preface
  ;; Setup completion at point
  (defun my/tempel-setup-capf ()
    ;; Add the Tempel Capf to `completion-at-point-functions'.
    ;; `tempel-expand' only triggers on exact matches. Alternatively use
    ;; `tempel-complete' if you want to see all matches, but then you
    ;; should also configure `tempel-trigger-prefix', such that Tempel
    ;; does not trigger too often when you don't expect it. NOTE: We add
    ;; `tempel-expand' *before* the main programming mode Capf, such
    ;; that it will be tried first.
    (setq-local completion-at-point-functions
                (cons #'tempel-complete
                      completion-at-point-functions)))
  :hook
  ((conf-mode . my/tempel-setup-capf)
   (prog-mode . my/tempel-setup-capf)
   (text-mode . my/tempel-setup-capf))
  ;; Optionally make the Tempel templates available to Abbrev,
  ;; either locally or globally. `expand-abbrev' is bound to C-x '.
  ;; (add-hook 'prog-mode-hook #'tempel-abbrev-mode)
  ;; (global-tempel-abbrev-mode)
  )

Collection of tempel templates. The package is young and doesn’t have comprehensive coverage.

(use-package tempel-collection
  :demand t
  :after tempel)

Vertico provides a performant and minimalistic vertical completion UI based on the default completion system.

(use-package vertico
  :custom
  ;; Show more candidates
  (vertico-count 20)

  ;; Grow and shrink the Vertico minibuffer
  (vertico-resize t)

  ;; Optionally enable cycling for `vertico-next' and `vertico-previous'.
  (vertico-cycle t)

  ;; Do not allow the cursor in the minibuffer prompt
  (minibuffer-prompt-properties
   '(read-only t cursor-intangible t face minibuffer-prompt))

  ;; Emacs 28: Hide commands in M-x which do not work in the current mode.
  ;; Vertico commands are hidden in normal buffers.
  (read-extended-command-predicate
   #'command-completion-default-include-p)

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

  ;; Enable Mouse support
  (vertico-mouse-mode t)
  :preface
  ;; Add prompt indicator to `completing-read-multiple'.
  ;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
  (defun crm-indicator (args)
    (cons (format "[CRM%s] %s"
                  (replace-regexp-in-string
                   "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
                   crm-separator)
                  (car args))
          (cdr args)))
  :config
  (advice-add #'completing-read-multiple :filter-args #'crm-indicator)

  ;; from: https://github.com/SystemCrafters/crafted-emacs/blob/c9ab29592b728954d3acc11d66e76cfbfbcb6189/modules/crafted-completion.el#L43
  ;; Straight and Package bundle the vertico package differently. When
  ;; using `package.el', the extensions are built into the package and
  ;; available on the load-path. When using `straight.el', the
  ;; extensions are not built into the package, so have to add that path
  ;; to the load-path manually to enable the following require.
  (when (fboundp 'straight-use-package)
    (add-to-list 'load-path
                 (expand-file-name "straight/build/vertico/extensions"
                                   straight-base-dir)))
  (require 'vertico-directory)

  :bind
  ;; Improve directory navigation
  (:map vertico-map
        ("RET" . vertico-directory-enter))
  :hook
  ((minibuffer-setup . cursor-intangible-mode)
   (after-init . vertico-mode)))

Library Footer

(provide 'my-completion)
;;; my-completion.el ends here

Version Control

:header-args+: :tangle lisp/my-vc.el
(require 'my-vc)

Conventional Header

<<header(file_name="my-vc.el")>>

Emacs package for highlighting uncommitted changes.

(use-package diff-hl
  :custom
  ;; DOOM: https://github.com/doomemacs/doomemacs/blob/98d753e1036f76551ccaa61f5c810782cda3b48a/modules/ui/vc-gutter/config.el#L167C1-L173C41
  ;; PERF: A slightly faster algorithm for diffing.
  (vc-git-diff-switches '("--histogram"))
  ;; PERF: Slightly more conservative delay before updating the diff
  (diff-hl-flydiff-delay 0.5)  ; default: 0.3
  ;; UX: get realtime feedback in diffs after staging/unstaging hunks.
  (diff-hl-show-staged-changes nil)
  :preface
  (defun my/diff-hl-inline-popup-show-adv (orig-func &rest args)
    (setcar (nthcdr 2 args) "")
    (apply orig-func args))
  (defun my/diff-hl-fix-face-colors (&rest _)
    "Set foreground to background color for diff-hl faces"
    (seq-do (lambda (face)
              (if-let ((color (face-background face)))
                  (progn (set-face-foreground face color)
                         (set-face-background face nil))))
            '(diff-hl-insert
              diff-hl-delete
              diff-hl-change)))
  :config
  (advice-add #'diff-hl-inline-popup-show :around #'my/diff-hl-inline-popup-show-adv)
  ;; UI: minimal fringe indicators
  ;; https://github.com/dgutov/diff-hl/issues/116#issuecomment-1573253134
  (let* ((width 2)
         (bitmap (vector (1- (expt 2 width)))))
    (define-fringe-bitmap 'my/diff-hl-bitmap bitmap 1 width '(top t)))
  (setq diff-hl-fringe-bmp-function (lambda (type pos) 'my/diff-hl-bitmap))
  (my/diff-hl-fix-face-colors)
  (advice-add #'enable-theme :after #'my/diff-hl-fix-face-colors)
  (when (not (display-graphic-p))
    (diff-hl-margin-mode))
  :bind
  (:map my/version-control-map
        ("g" . diff-hl-show-hunk)
        :repeat-map diff-hl-show-hunk-map
        ("n" . diff-hl-show-hunk-next)
        ("p" . diff-hl-show-hunk-previous)
        ("r" . diff-hl-revert-hunk)
        ("S" . diff-hl-stage-current-hunk)
        :exit
        ("C" . magit-commit-create))
  :hook
  ((find-file    . diff-hl-mode)
   (vc-dir-mode  . diff-hl-dir-mode)
   (dired-mode   . diff-hl-dired-mode)
   (diff-hl-mode . diff-hl-flydiff-mode)
   (magit-pre-refresh . diff-hl-magit-pre-refresh)
   (magit-post-refresh . diff-hl-magit-post-refresh)))
(use-package git-timemachine
  :bind
  (:map my/version-control-map
        ("t" . git-timemachine)))

The magical git client. Let’s load magit only when one of the several entry pont functions we invoke regularly outside of magit is called.

(use-package magit
  :commands (magit-status magit-blame magit-log-buffer-file magit-log-all)
  :bind
  (:map my/version-control-map
        ("F"  . magit-fetch-all)
        ("P"  . magit-push-current)
        ("b"  . magit-branch)
        ("b"  . magit-branch-or-checkout)
        ("c"  . magit-commit)
        ("d"  . magit-diff-unstaged)
        ("f"  . magit-fetch)
        ("la" . magit-log-all)
        ("lc" . magit-log-current)
        ("lf" . magit-log-buffer-file)
        ("p"  . magit-pull-branch)
        ("v"  . magit-status)
        ("r"  . magit-rebase)))

Show source files’ TODOs (and FIXMEs, etc) in Magit status buffer.

(use-package magit-todos
  :after magit
  :init (magit-todos-mode))

Library Footer

(provide 'my-vc)
;;; my-vc.el ends here

Project Management

:header-args+: :tangle lisp/my-project.el
(require 'my-project)

Conventional Header

<<header(file_name="my-project.el")>>

project

(use-package project
  :straight nil
  :custom
  (project-vc-extra-root-markers '(".project")))

Enhancements to Emacs’ built in project library.

(use-package project-x
  :straight (:host github :repo "karthink/project-x")
  :after project
  :bind (:map project-prefix-map
              ("w" . project-x-window-state-save)
              ("j" . project-x-window-state-load))
  :commands project-x-try-local project-x--window-state-write
  :init
  (add-to-list 'project-switch-commands
               '(?j "Restore windows" project-x-windows) t)
  (add-hook 'project-find-functions 'project-x-try-local 90)
  (add-hook 'kill-emacs-hook 'project-x--window-state-write))

Support a “one tab group per project” workflow.

(use-package project-tab-groups
  :after tab-bar project
  :config
  (with-eval-after-load 'tab-bar-echo-area
    (push #'project-switch-project tab-bar-echo-area-trigger-display-functions)
    (tab-bar-echo-area-apply-display-tab-names-advice))
  :init
  (project-tab-groups-mode))

speedbar

(use-package speedbar
  :straight nil
  :custom
  (speedbar-frame-parameters
   '((name . "speedbar")
     (title . "speedbar")
     (minibuffer . nil)
     (border-width . 2)
     (menu-bar-lines . 0)
     (tool-bar-lines . 0)
     (unsplittable . t)
     (left-fringe . 10)))
  ;; Increase the indentation for better useability.
  (speedbar-indentation-width 3)
  ;; make speedbar update automaticaly, and dont use ugly icons(images)
  (speedbar-update-flag t)
  (speedbar-use-images nil)

  :config
  ;; list of supported file-extensions
  ;; feel free to add to this list
  (speedbar-add-supported-extension
   (list
    ;; lua and fennel(lisp that transpiles to lua)
    ".lua"
    ".fnl"
    ".fennel"
    ;; shellscript
    ".sh"
    ".bash";;is this ever used?
    ;; web languages
    ;; Hyper-Text-markup-language(html) and php
    ".php"
    ".html"
    ".htm"
    ;; ecma(java/type)-script
    ".js"
    ".json"
    ".ts"
    ;; stylasheets
    ".css"
    ".less"
    ".scss"
    ".sass"
    ;; c/c++ and makefiles
    ".c"
    ".cpp"
    ".h"
    "makefile"
    "MAKEFILE"
    "Makefile"
    ;; runs on JVM, java,kotlin etc
    ".java"
    ".kt";;this is for kotlin
    ".mvn"
    ".gradle" ".properties";; this is for gradle-projects
    ".clj";;lisp on the JVM
    ;; lisps
    ".cl"
    ".el"
    ".scm"
    ".lisp"
    ;; configuration
    ".yaml"
    ".toml"
    ;; json is already in this list
    ;; notes,markup and orgmode
    ".md"
    ".markdown"
    ".org"
    ".txt"
    "README"
    ;; Jupyter Notebooks
    ".ipynb"))

  :hook
  ((speedbar-mode . (lambda()
                      ;; Disable word wrapping in speedbar if you always enable it globally.
                      (visual-line-mode 0)
                      ;; Change speedbar's text size.  May need to alter the icon size if you change size.
                      (text-scale-adjust -1)))))

Same frame speedbar.

(use-package sr-speedbar
  :custom
  (sr-speedbar-right-side nil)
  :bind
  (:map my/toggle-map
        ("s" . sr-speedbar-toggle)))

Library Footer

(provide 'my-project)
;;; my-project.el ends here

Programming

:header-args+: :tangle lisp/my-programming.el
(require 'my-programming)

Conventional Header

<<header(file_name="my-programming.el")>>

Integrated environment for TeX

(use-package auctex
  :preface
  ;; Custom auto-compile minor mode
  (define-minor-mode my/auto-compile-mode
    "Automatically compile LaTeX files after saving."
    :lighter " LaTeX Auto Compile"
    ;; Add/remove after-save hook based on mode state
    (if my/auto-compile-mode
        (add-hook 'after-save-hook #'my/compile-latex-on-save nil t)
      (remove-hook 'after-save-hook #'my/compile-latex-on-save t)))

  ;; Function to compile LaTeX document after saving
  (defun my/compile-latex-on-save ()
    (when (eq major-mode 'LaTeX-mode)
      (TeX-command-run-all nil)))
  :custom
  ;; Use PDF Tools for pdf output
  (TeX-view-program-selection
   '(((output-dvi has-no-display-manager)
      "dvi2tty")
     ((output-dvi style-pstricks)
      "dvips and gv")
     (output-dvi "xdvi")
     (output-pdf "PDF Tools")
     (output-html "xdg-open")))

  ;; Enable auto-saving of TeX files
  (TeX-auto-save t)
  ;; Enable parsing of the current TeX file
  (TeX-parse-self t)
  ;; Disable query prompts when saving TeX files
  (TeX-save-query nil)
  ;; Ask for master document
  (TeX-master nil)
  ;; Enable PDF mode for TeX files
  (TeX-PDF-mode t)
  ;; Don't start server for inverse search (is already running)
  (TeX-source-correlate-start-server nil)
  :hook
  ;; Set up preview, math mode, inverse search, and reftex in LaTeX mode
  ((LaTeX-mode . LaTeX-preview-setup)
   (LaTeX-mode . LaTeX-math-mode)
   (LaTeX-mode . TeX-source-correlate-mode)
   (LaTeX-mode . turn-on-reftex)))

Emacs utilities for code split into cells, including Jupyter notebooks.

(use-package code-cells
  :preface
  (defun my/code-cells-eval (start end)
    (interactive (code-cells--bounds (prefix-numeric-value current-prefix-arg)
                                     'use-region
                                     'no-header))
    (code-cells-eval start end)
    (code-cells-forward-cell 1))
  :config
  (add-to-list 'code-cells-eval-region-commands '(python-base-mode . python-shell-send-region))
  :bind
  (:map code-cells-mode-map
        ("C-S-<return>" . my/code-cells-eval))
  :hook
  (python-base-mode . code-cells-mode-maybe))

Structured Editing and Navigation in Emacs.

(use-package combobulate
  :after treesit
  :custom
  ;; ;; You can customize Combobulate's key prefix here.
  ;; ;; Note that you may have to restart Emacs for this to take effect!
  (combobulate-key-prefix "C-c o")
  :config
  (define-key my/open-map "c" (cons "combobulate" combobulate-key-map))
  :bind
  (:map combobulate-key-map
        ("S-<down>"  . combobulate-navigate-down-list-maybe)
        ("S-<left>"  . combobulate-navigate-previous)
        ("S-<right>" . combobulate-navigate-next)
        ("M-<left>"  . combobulate-navigate-logical-previous)
        ("M-<right>" . combobulate-navigate-logical-next)
        ("S-<up>"    . combobulate-navigate-up-list-maybe)
        ("M-<down>"  . combobulate-drag-down)
        ("M-<up>"    . combobulate-drag-up))
  ;; Optional, but recommended.
  ;;
  ;; You can manually enable Combobulate with `M-x
  ;; combobulate-mode'.
  :hook
  ((python-ts-mode . combobulate-mode)
   (js-ts-mode . combobulate-mode)
   (css-ts-mode . combobulate-mode)
   (yaml-ts-mode . combobulate-mode)
   (typescript-ts-mode . combobulate-mode)
   (tsx-ts-mode . combobulate-mode)))

Emacs helper library (and minor mode) to work with conda environments.

(use-package conda
  :after tab-bar project python
  :custom
  ;; support for mambaforge envs
  (conda-anaconda-home "~/mambaforge/")
  (conda-env-home-directory "~/mambaforge/")
  :commands conda-env-candidates
  :preface
  (defun my/find-python-interpreter-advice (&rest _)
    "Find the Python interpreter and set `python-shell-interpreter' and `python-shell-interpreter-args' accordingly."
    (cond
     ((executable-find "ipython3")
      (setq python-shell-interpreter "ipython3"
            python-shell-interpreter-args "--simple-prompt --classic"))
     ((executable-find "python3")
      (setq python-shell-interpreter "python3"
            python-shell-interpreter-args "-i"))
     (t
      (setq python-shell-interpreter "python"
            python-shell-interpreter-args "-i"))))
  (defun my/conda-env-auto-activate-advice (&rest _)
    "Activate conda environment for project."
    (let* ((project-current (project-current))
           ;; If buffer belongs to a project use its name.
           ;; If not fall back to tab group
           (current-project-name 
            (or (and project-current (project-name project-current))
                (alist-get 'group (tab-bar--current-tab))))
           ;; Skip env activation if project is located at a remote location
           (project-remote-p
            (and project-current (file-remote-p (project-root project-current)))))
      (progn
        (message (format "%s %s" current-project-name project-remote-p))
        (cond
         ((and (bound-and-true-p conda-project-env-path)
               (not project-remote-p))
          (message (format "activating env for project: %s" conda-project-env-path))
          (conda-env-activate-for-buffer))
         ((and current-project-name
               (not project-remote-p)
               (member current-project-name (conda-env-candidates)))
          (message (format "found conda env with project name: %s" current-project-name))
          (conda-env-activate current-project-name))
         (t (conda-env-deactivate))))))
  (define-minor-mode my/global-conda-env-autoactivate-mode
    "Toggle conda-env-autoactivate mode.

This mode automatically tries to activate a conda environment for the current
buffer."
    :lighter " Conda Auto Activation"
    :group 'conda
    :global t
    ;; Forms
    (if my/global-conda-env-autoactivate-mode ;; already on, now switching off
        (progn
          (advice-add #'tab-bar-select-tab :after #'my/conda-env-auto-activate-advice)
          (advice-add #'project-switch-project :after #'my/conda-env-auto-activate-advice)
          ;; Try to activat env imediatly after switching to a project
          (my/conda-env-auto-activate-advice))
      (progn
        (advice-remove #'tab-bar-select-tab #'my/conda-env-auto-activate-advice)
        (advice-remove #'project-switch-project #'my/conda-env-auto-activate-advice)
        (conda-env-deactivate))))
  :init
  ;; enable automatic activation on project switch
  (my/global-conda-env-autoactivate-mode)
  :config
  ;; interactive shell support
  (conda-env-initialize-interactive-shells)
  ;; eshell support
  (conda-env-initialize-eshell)
  ;; Add current conda env to mode line
  (add-to-list 'global-mode-string
               '(conda-env-current-name (" 󰌠 conda: " conda-env-current-name " "))
               'append)
  ;; Add custom hook to set correct python interpreter
  (advice-add #'conda-env-activate :after #'my/find-python-interpreter-advice)
  (advice-add #'conda-env-deactivate :after #'my/find-python-interpreter-advice))

Debug Adapter Protocol for Emacs.

(use-package dape
  ;; To use window configuration like gud (gdb-mi)
  ;; :init
  ;; (setq dape-buffer-window-arrangement 'gud)
  :bind
  (("<left-fringe> <mouse-1>" . dape-mouse-breakpoint-toggle)
   :repeat-map my/debug-map
   ("d" . dape)
   ("p" . dape-pause)
   ("c" . dape-continue)
   ("n" . dape-next)
   ("s" . dape-step-in)
   ("o" . dape-step-out)
   ("r" . dape-restart)
   ("i" . dape-info)
   ("R" . dape-repl)
   ("m" . dape-read-memory)
   ("l" . dape-breakpoint-log)
   ("e" . dape-breakpoint-expression)
   ("b" . dape-breakpoint-toggle)
   ("B" . dape-breakpoint-remove-all)
   ("t" . dape-select-thread)
   ("S" . dape-select-stack)
   ("x" . dape-evaluate-expression)
   ("w" . dape-watch-dwim)
   ("D" . dape-disconnect-quit)
   :exit
   ("q" . dape-quit))
  :config
  ;; Info buffers to the right
  (setq dape-buffer-window-arrangement 'right)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-on-start-hooks 'dape-info)
  ;; (remove-hook 'dape-on-start-hooks 'dape-repl)

  ;; To display info and/or repl buffers on stopped
  ;; (add-hook 'dape-on-stopped-hooks 'dape-info)
  ;; (add-hook 'dape-on-stopped-hooks 'dape-repl)

  ;; By default dape uses gdb keybinding prefix
  ;; If you do not want to use any prefix, set it to nil.
  ;; (setq dape-key-prefix "\C-x\C-a")

  ;; Projectile users
  ;; (setq dape-cwd-fn 'projectile-project-root)

  :hook
  ;; Kill compile buffer on build success
  ;; (add-hook 'dape-compile-compile-hooks 'kill-buffer)

  ;; Save buffers on startup, useful for interpreted languages
  ((dape-on-start-hooks . (lambda () (save-some-buffers t t)))
   (prog-mode . dape-breakpoint-global-mode)))

An emacs mode for handling Dockerfiles.

(use-package docker
  :commands docker)
(use-package dockerfile-mode
  :mode "/Dockerfile\\'"
  :mode "/Containerfile\\'"
  :mode "\\.dockerfile\\'"
  :mode "\\.containerfile\\'")
(use-package tramp-container
  :straight nil
  :after docker)

A client for Language Server Protocol servers.

(use-package eglot
  :custom
  ;; Filter list of all possible completions with Orderless
  ;; https://github.com/minad/corfu/wiki#configuring-corfu-for-eglot
  (completion-category-defaults nil)
  :preface
  (defun my/eglot-capf ()
    (setq-local completion-at-point-functions
                (cons (cape-capf-super
                       #'cape-file
                       #'eglot-completion-at-point
                       #'tempel-complete)
                      completion-at-point-functions)))
  :bind
  (:map my/lsp-map
        ("l" . eglot)
        ("=" . eglot-format-buffer)
        ("R" . eglot-reconnect)
        ("f" . eglot-find-declaration)
        ("i" . eglot-find-implementation)
        ("k" . eglot-shutdown)
        ("o" . eglot-code-action-organize-imports)
        ("q" . eglot-code-action-quickfix)
        ("r". eglot-rename))
  :config
  ;; Continuously update the candidates using cape cache buster
  (advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
  :hook
  ((python-base-mode . eglot-ensure)
   (eglot-managed-mode . my/eglot-capf)))

Boost eglot using lsp-booster.

(use-package eglot-booster
  :after eglot
  :if (executable-find "emacs-lsp-booster")
  :straight (:host github :repo "jdtsmith/eglot-booster")
  :config	(eglot-booster-mode))

Configure emacs documentation support.

(use-package eldoc
  :custom
  (eldoc-documentation-strategy 'eldoc-documentation-compose-eagerly)
  :config
  (add-to-list 'display-buffer-alist
               '("^\\*eldoc for" display-buffer-at-bottom
                 (window-height . 4)))
  (eldoc-add-command-completions "paredit-")
  (eldoc-add-command-completions "combobulate-"))

Emacs Speaks Statistics: ESS.

(use-package ess
  :mode (("\\.[rR]\\'" . R-mode)
         ("\\.[rR]nw\\'" . Rnw-mode)
         ("\\.jl\\'" . julia-mode))
  :config
  (require 'ess-site))

Consistent ESS-like eval interface for various REPLs.

(use-package eval-in-repl
  :custom
  ;; Uncomment if no need to jump after evaluating current line
  ;; (eir-jump-after-eval nil)

  ;; Uncomment if you want to always split the script window into two.
  ;; This will just split the current script window into two without
  ;; disturbing other windows.
  ;; (eir-always-split-script-window t)

  ;; Uncomment if you always prefer the two-window layout.
  ;; (eir-delete-other-windows t)

  ;; Place REPL on the left of the script window when splitting.
  (eir-repl-placement 'left)
  :preface
  (defun my/setup-eir-python nil
    (require 'eval-in-repl-python)
    (local-set-key (kbd "<C-return>") 'eir-eval-in-python))
  (defun my/setup-eir-lisp nil
    (require 'eval-in-repl-ielm)
    ;; Evaluate expression in the current buffer.
    (setq-local eir-ielm-eval-in-current-buffer t)
    (local-set-key (kbd "<C-return>") 'eir-eval-in-ielm))
  :hook
  (((python-mode python-ts-mode) . my/setup-eir-python)
   ((emacs-lisp-mode lisp-interaction-mode Info-mode) . my/setup-eir-lisp)))

Universal on-the-fly syntax checker for Emacs.

(use-package flymake
  :custom
  ;; Let git gutter have left fringe, flymake can have right fringe
  (flymake-fringe-indicator-position 'right-fringe)
  :hook
  ((prog-mode conf-mode) . flymake-mode))

Auto-format source code in many languages with one command.

(use-package format-all
  ;;:hook (prog-mode . format-all-mode)
  :bind
  (:map my/toggle-map
        ("f" . format-all-buffer)))

Emacs major mode for editing Lua.

(use-package lua-mode
  :mode "\\.lua\\'")

Emacs Markdown Mode.

(use-package markdown-mode
  :mode "\\.md\\'")

Insert NumPy style docstrings in Python functions.

(use-package numpydoc
  :after python)

Py-isort.el integrates isort into Emacs.

(use-package py-isort
  :after conda)

Manage Python imports from Emacs!.

(use-package pyimport
  :after conda)

python

(use-package python
  :straight nil
  :custom
  ;; Let Emacs guess Python indent silently
  (python-indent-guess-indent-offset t)
  (python-indent-guess-indent-offset-verbose nil)
  (python-shell-dedicated 'project))

Generate Sphinx friendly docstrings for Python functions in Emacs.

(use-package sphinx-doc
  :straight (:host github :repo "eanopolsky/sphinx-doc.el" :branch "square-brackets-in-return-types")
  :hook
  (python-mode . sphinx-doc-mode))

Display symbols (functions, variables, etc) in a side window.

(use-package symbols-outline
  :bind
  (:map my/toggle-map
        ("o" . symbols-outline-show))
  :custom
  (symbols-outline-window-position 'left)
  :config
  ;; By default the ctags backend is selected
  (unless (executable-find "ctags")
    ;; Use lsp-mode or eglot as backend
    (setq symbols-outline-fetch-fn #'symbols-outline-lsp-fetch))
  (symbols-outline-follow-mode))

built-in tree-sitter integration for Emacs

(use-package treesit-auto
  :if (>= emacs-major-version 29)
  :custom
  (treesit-auto-install 'prompt)
  :hook
  (after-init . global-treesit-auto-mode))

Code-folding using tree-sitter. Using the forked version with treesit support here

(use-package ts-fold
  :straight (:host github :repo "garyo/ts-fold" :branch "andrew-sw/treesit-el-support")
  :preface
  (defun my/ts-fold-mode-hook ()
    (keymap-local-set "<backtab>" 'ts-fold-toggle))
  :hook
  (((yaml-ts-mode python-ts-mode) . ts-fold-mode)
   (ts-fold-mode . my/ts-fold-mode-hook)))

The emacs major mode for editing files in the YAML data serialization format.

(use-package yaml-mode
  :bind
  (:map yaml-mode-map ("\C-m" . newline-and-indent))
  :mode ("\\.ya?ml\\'" . yaml-ts-mode))

Library Footer

(provide 'my-programming)
;;; my-programming.el ends here

Keybindings

:header-args+: :tangle lisp/my-keybindings.el
(require 'my-keybindings)

Conventional Header

<<header(file_name="my-keybindings.el")>>

Meow is yet another modal editing mode for Emacs.

(use-package meow
  :demand t
  :custom
  (meow-keypad-start-keys . ())
  (meow-keypad-meta-prefix . nil)
  (meow-keypad-ctrl-meta-prefix . nil)
  (meow-keypad-literal-prefix . nil)
  (meow-keypad-self-insert-undefined . nil)
  ;; use system clipboard
  (meow-use-clipboard t)
  (meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)
  :preface
  ;; Here we define some helper variables and functions to mimic the bahaviour
  ;; of =meow-mode-state-list= for minor modess
  (defvar my/meow-desired-state nil
    "Buffer-local variable to specify the desired Meow state.")
  (defun my/meow-set-desired-state (state)
    "Set the buffer-local variable =my/meow-desired-state= to the specified state."
    (setq-local my/meow-desired-state state))
  (defun my/meow-mode-get-state-advice (orig-func &rest args)
    "Advice function to modify =meow--mode-get-state= based on =my/meow-desired-state=."
    (if my/meow-desired-state
        my/meow-desired-state
      (apply orig-func args)))
  (defun my/meow-git-timemachine-hook ()
    "Hook to set my/meow-desired-state to =motion= when entering git-timemachine mode."
    (my/meow-set-desired-state 'motion))
  (defun my/tab-line-mode-hook ()
    "modify behavior of meow commands when tab-line-mode is active"
    (if tab-line-mode
        (advice-add #'meow-quit :override #'my/tab-line-close-tab-function)
      (advice-remove #'meow-quit #'my/tab-line-close-tab-function)))
  :config
  (with-eval-after-load 'nerd-icons
    (setq meow-replace-state-name-list
          '((normal . "󰆾")
            (motion . "󰷢")
            (keypad . "󰌌")
            (insert . "󰏫")
            (beacon . "󰩬")))
    (setq meow-indicator-face-alist
          '((normal . meow-normal-indicator)
            (motion . nerd-icons-lred)
            (keypad . meow-normal-indicator)
            (insert . nerd-icons-lgreen)
            (beacon . nerd-icons-orange))))
  ;; Apply advice to 'meow--mode-get-state'
  (advice-add 'meow--mode-get-state :around #'my/meow-mode-get-state-advice)
  (add-to-list 'meow-keymap-alist `(leader . ,my/leader-map))
  :bind
  (:map meow-motion-state-keymap
        ("<escape>" . meow-cancel-selection)
        ("," . meow-inner-of-thing)
        ("." . meow-bounds-of-thing)
        ("b" . meow-back-word)
        ("e" . meow-next-word)
        ("f" . meow-find)
        ("o" . meow-block)
        ("q" . meow-quit)
        ("t" . meow-till)
        ("v" . meow-visit)
        ("w" . meow-mark-word)
        ("x" . meow-line)
        ("y" . meow-save)
        ("E" . meow-next-symbol)
        ("W" . meow-mark-symbol)
        ("X" . meow-goto-line)
        :map my/leader-map
        ;; ("j" . "H-j")
        ;; ("k" . "H-k")
        ;; ("x" ("C-x" . ctl-x-map))
        ;;("m" . (lambda ()(meow--execute-kbd-macro "C-c")))
        ;; Use SPC (0-9) for digit arguments.
        ("SPC" . project-list-buffers)
        ("1" . meow-digit-argument)
        ("2" . meow-digit-argument)
        ("3" . meow-digit-argument)
        ("4" . meow-digit-argument)
        ("5" . meow-digit-argument)
        ("6" . meow-digit-argument)
        ("7" . meow-digit-argument)
        ("8" . meow-digit-argument)
        ("9" . meow-digit-argument)
        ("0" . meow-digit-argument)
        ("/" . meow-keypad-describe-key)
        ("?" . meow-cheatsheet)
        :map meow-normal-state-keymap
        ("'" . repeat)
        ("," . meow-inner-of-thing)
        ("-" . negative-argument)
        ("." . meow-bounds-of-thing)
        ("0" . meow-expand-0)
        ("1" . meow-expand-1)
        ("2" . meow-expand-2)
        ("3" . meow-expand-3)
        ("4" . meow-expand-4)
        ("5" . meow-expand-5)
        ("6" . meow-expand-6)
        ("7" . meow-expand-7)
        ("8" . meow-expand-8)
        ("9" . meow-expand-9)
        (";" . meow-reverse)
        ("<escape>" . meow-cancel-selection)
        ("=" . meow-indent)
        ("A" . meow-open-below)
        ("B" . meow-back-symbol)
        ("C" . meow-comment)
        ("D" . meow-backward-delete)
        ("E" . meow-next-symbol)
        ("G" . meow-grab)
        ("H" . meow-left-expand)
        ("I" . meow-open-above)
        ("J" . meow-next-expand)
        ("K" . meow-prev-expand)
        ("L" . meow-right-expand)
        ("O" . meow-to-block)
        ("Q" . meow-goto-line)
        ("R" . undo-redo)
        ("U" . meow-undo-in-selection)
        ("W" . meow-mark-symbol)
        ("X" . meow-goto-line)
        ("Y" . meow-sync-grab)
        ("[" . meow-beginning-of-thing)
        ("]" . meow-end-of-thing)
        ("a" . meow-append)
        ("b" . meow-back-word)
        ("c" . meow-change)
        ("d" . meow-delete)
        ("e" . meow-next-word)
        ("f" . meow-find)
        ("h" . meow-left)
        ("i" . meow-insert)
        ("j" . meow-next)
        ("k" . meow-prev)
        ("l" . meow-right)
        ("m" . meow-join)
        ("n" . meow-search)
        ("o" . meow-block)
        ("p" . meow-yank)
        ("q" . meow-quit)
        ("r" . meow-replace)
        ("s" . meow-kill)
        ("t" . meow-till)
        ("u" . meow-undo)
        ("v" . meow-visit)
        ("w" . meow-mark-word)
        ("x" . meow-line)
        ("y" . meow-save)
        ("z" . meow-pop-selection))
  :hook
  ((git-timemachine-mode . my/meow-git-timemachine-hook)
   (after-init . meow-global-mode)
   (tab-line-mode . my/tab-line-mode-hook)))

The mode displays the key bindings following your currently entered incomplete command (a ;; prefix) in a popup.

(use-package which-key
  :custom
  (which-key-idle-delay 0.1)
  :hook
  (meow-mode . which-key-mode))

Library Footer

(provide 'my-keybindings)
;;; my-keybindings.el ends here

Conventional Library Footer for init.el

(provide 'init)
;;; init.el ends here

About

A simple template that can be used to get started with an efficient literate Emacs configuration

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Emacs Lisp 100.0%