This Emacs configuration prioritizes speed and a distraction-free writing and coding experience, drawing inspiration from projects like DOOM Emacs, crafted-emacs, and others. It leverages a literate programming approach using Org mode, enabling clear documentation and easy configuration management. Here are some notable features:
- Literate Configuration: The entire configuration is written in Org mode, making it self-documenting and easy to navigate. This file,
emacs.org
, is the single source of truth for all settings. The Org mode source code blocks are tangled to generate the actual Emacs Lisp files loaded by Emacs, for enhanced usability and easier debugging, as suggested by Protesilaos. - Optimized Startup: Various techniques are employed to minimize startup time, including deferring package loading with use-package, optimized garbage collection settings, and disabling non-essential services during initialization.
- Minimal UI: The interface is streamlined by default, hiding the menu bar, tool bar, and scroll bar to maximize screen real estate.
- Straight.el for Package Management: Straight.el is used for package management, offering a more modern and robust alternative to the built-in package.el.
- Extensive Completion Framework: A powerful completion framework is provided using Corfu, Cape, Orderless, and Vertico, offering intelligent and context-aware completion suggestions. This framework is enhanced with Marginalia to provide additional context in the minibuffer, Embark for actions on completion candidates, and Consult for enhanced minibuffer completion commands.
- Project and Workspace Management: Project.el (built-in), auto-tab-groups, and tab-bar (built-in) are used for seamless project and workspace management, allowing for efficient organization and navigation between projects. These features are further enhanced by Project-x, which provides additional enhancements to project management.
- Integrated Development Environment (IDE) Features: The configuration includes powerful IDE-like features such as Eglot for Language Server Protocol integration, boosted by Eglot-booster for improved performance. Dape is used for debugging, and Flymake (built-in) provides on-the-fly syntax checking.
- Org Mode Power User Setup: A comprehensive Org mode setup is provided, including features for task management, note-taking, literate programming, presentations, and more. Org-modern provides a visually appealing modern theme, while Org-appear enhances the visibility of hidden elements. Ox-pandoc enables exporting Org documents using Pandoc, and Org-noter provides document annotation capabilities.
- Modal Editing with Meow: Meow introduces modal editing to Emacs, similar to Vim, for efficient text manipulation and navigation. The modal experience is further enhanced by which-key, providing a helpful popup of available keybindings.
- Installation
- References
- Notes
- Configuration
- Prerequisites:
*
- Nerd Fonts: The configuration uses Nerd Fonts for icons. You can download and install a Nerd Font patched version of your preferred font from nerd fonts.
- Command Line Utilities: Ensure you have the following command line utilities installed:
- Clone the Repository:
git clone https://github.com/MArpogaus/emacs.d ~/.emacs.d
- Install Packages:
Start Emacs and it will automatically install the required packages via Straight.el.
- Configure Emacs:
- Open the
emacs.org
file in Emacs. - Customize any settings in the source code blocks as needed.
- After making changes, press
C-c C-v t
to tangle the Org mode file and generate the Emacs Lisp files.
- Open the
- Enjoy!
- Bad Emacs defaults
- .emacs.d · GitHub
- emacs-literate-starter/emacs.org at master · gilbertw1/emacs-literate-starter…
- GitHub - doomemacs/doomemacs: An Emacs framework for the stubborn martian hacker
- GitHub - rougier/dotemacs: Litterate configuration for GNU Emacs
- GitHub - SystemCrafters/crafted-emacs: A sensible base Emacs configuration.
- GitHub - terlar/emacs-config: Emacs configuration
- GitHub - zoliky/dotemacs: My GNU Emacs configuration.
- GNU Emacs configuration | Protesilaos Stavrou
- joe-adams/hydrogen: Hydrogen is a very small framework that aims to make Emac…
- minimal-emacs.d/early-init.el at main · jamescherti/minimal-emacs.d · GitHub
- Pandenstein - Emacs literate configuration
- The 6 Emacs Settings Every User Should Consider - System Crafters
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
Library Headers (GNU Emacs Lisp Reference Manual)
echo ";;; $file_name --- Emacs configuration file -*- no-byte-compile: t; 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:"
<<header(file_name="early-init.el")>>
The following optimizations have been inspired by:
- https://gist.github.com/axyz/76871b404df376271b521212fba8a621
- https://github.com/alexluigit/dirvish/blob/main/docs/.emacs.d.example/early-init.el
- https://github.com/jamescherti/minimal-emacs.d/blob/main/early-init.el
- https://github.com/mnewt/dotemacs/blob/master/early-init.el
- https://github.com/nilcons/emacs-use-package-fast#a-trick-less-gc-during-startup
;; 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.
(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 (* 16 1024 1024))))
;; 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)
;; 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)
;; remove "for information about gnu emacs..." message at startup
(advice-add #'display-startup-echo-area-message :override #'ignore)
;; suppress the vanilla startup screen completely. we've disabled it with
;; `inhibit-startup-screen', but it would still initialize anyway.
(advice-add #'display-startup-screen :override #'ignore)
;; never show the hello file
(defalias #'view-hello-file #'ignore)
;; Disable warnings from the legacy advice API. They aren't useful.
(setq ad-redefinition-action 'accept)
;; Ignore warnings about "existing variables being aliased".
(setq warning-suppress-types '((defvaralias) (lexical-binding)))
;; 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)
;; In noninteractive sessions, prioritize non-byte-compiled source files to
;; prevent the use of stale byte-code. Otherwise, it saves us a little IO time
;; to skip the mtime checks on every *.elc file.
(setq load-prefer-newer t)
;; Ensure JIT compilation is enabled for improved performance by
;; native-compiling loaded .elc files asynchronously
(setq native-comp-jit-compilation t)
;; Disable certain byte compiler warnings to cut down on the noise.
(setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
;; Ensure that quitting only occurs once Emacs finishes native compiling,
;; preventing incomplete or leftover compilation files in `/tmp`.
(setq native-comp-async-query-on-exit t)
(setq confirm-kill-processes t)
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)
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)
;;disable checking (for speedup).
(setq straight-check-for-modifications nil)
;; straight.el bootstrap code
(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))
(provide 'early-init)
;;; early-init.el ends here
init.el
, is responsible for defining essential configurations and variables used in submodules.
<<header(file_name="init.el")>>
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))
;; HACK: https://github.com/radian-software/straight.el/issues/1146
(setq straight-built-in-pseudo-packages '(emacs nadvice python image-mode project flymake xref))
;; 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)
;; 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
jka-compr-verbose t
warning-minimum-level :warning
byte-compile-warnings t
byte-compile-verbose t
native-comp-warning-on-missing-source t
debug-on-error t))
Use no-littering to automatically set common paths to the new user-emacs-directory ~/.cache/emacs
..
(use-package no-littering
:demand t
:init
(setq emacs-config-directory 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
user-emacs-directory (expand-file-name "~/.cache/emacs/"))
:config
;; store backup and auto-save files in =no-littering-var-directory=
(no-littering-theme-backups))
(use-package emacs
:straight nil
:custom
;; Startup
;; Emacs does a lot of things at startup and here, we disable pretty much everything.
(inhibit-splash-screen t) ; disable startup screens and messages
(inhibit-startup-buffer-menu t) ; Disable display of buffer list when more than 2 files are loaded
(inhibit-startup-echo-area-message t) ; Disable initial echo message
(inhibit-startup-message t) ; Disable startup message
(inhibit-startup-screen t) ; Disable start-up screen
(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
;; Backups
(backup-by-copying t) ; Backs up by moving the actual file
;; 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 'fundamental-mode) ; Initial mode is text
(default-major-mode 'fundamental-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
(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 'silent) ; 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
(comment-auto-fill-only-comments t) ; Use auto fill mode only in comments
(custom-buffer-done-kill t) ; Kill custom buffer when done
;; Enable window dividers
(window-divider-default-bottom-width 1)
(window-divider-default-places t)
(window-divider-default-right-width 1)
(window-divider-mode t)
: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)
:hook
;; Enable word wrapping
(((prog-mode conf-mode text-mode) . visual-line-mode)
;; Enable automatic linebreaks before `fill-column' is eceeded
((prog-mode conf-mode text-mode) . auto-fill-mode)
;; Compress kill ring when exiting emacs
(kill-emacs . unpropertize-kill-ring)))
In this section, I define some custom Lisp functions.
(use-package emacs
: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)))))
(defun simulate-key-press (key)
"Pretend that KEY was pressed.
KEY must be given in `kbd' notation.
Refference: https://emacs.stackexchange.com/a/13432"
`(lambda () (interactive)
(setq prefix-arg current-prefix-arg)
(setq unread-command-events (listify-key-sequence (read-kbd-macro ,key)))))
(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."))))))
;; Thanks doom-modeline: https://github.com/seagle0128/doom-modeline/blob/ec6bc00ac035e75ad10b52e516ea5d95cc9e0bd9/doom-modeline-core.el#L1454C8-L1454C39
(defun my/get-bar-image (height width color)
"Get a rectangular bar image with specified height, width and color."
(if (and (image-type-available-p 'pbm) (display-graphic-p))
(propertize
" " 'display
(create-image
(concat (format "P1\n%i %i\n" width height) (make-string (* width height) ?1) "\n")
'pbm t :foreground color :ascent 'center))
(propertize "|" 'face (list :foreground color
:background color))))
(define-minor-mode my/minimal-ui-mode
"Toggle automatic tab group management based on command execution."
:global t
:group 'frames
(if my/minimal-ui-mode
(progn
(setq tab-bar-show nil)
(tab-bar-mode -1)
(global-tab-line-mode -1)
(global-hide-mode-line-mode 1)
(spacious-padding-mode -1))
(progn
(setq tab-bar-show t)
(tab-bar-mode 1)
(global-tab-line-mode 1)
(global-hide-mode-line-mode -1)
(spacious-padding-mode 1)))))
We define some keymaps here used by other package declarations and fill the leader keymap with the most important bindings for basic commands. Package specific keymap definitions are kept in preface of the respective package declaration.
;; setup keymaps
(use-package emacs
:straight nil
:preface
(defvar my/leader-map (make-sparse-keymap) "key-map for leader key")
(defvar my/buffer-map (make-sparse-keymap) "key-map for buffer 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/toggle-map (make-sparse-keymap) "key-map for toggle commands")
(defvar my/open-map (make-sparse-keymap) "key-map for open commands")
(defvar my/version-control-map (make-sparse-keymap) "key-map for version control commands")
:config
;; leader keymap
(define-key my/leader-map (kbd "b") (cons "buffer" my/buffer-map))
(define-key my/leader-map (kbd "f") (cons "file" my/file-map))
(define-key my/leader-map (kbd "o") (cons "open" my/open-map))
(define-key my/leader-map (kbd "t") (cons "toggle" my/toggle-map))
(define-key my/leader-map (kbd "v") (cons "version-control" my/version-control-map))
(define-key my/leader-map (kbd "w") (cons "window" my/window-map))
(define-key my/leader-map (kbd "g") (cons "goto" goto-map))
(define-key my/leader-map (kbd "h") (cons "help" help-map))
(define-key my/leader-map (kbd "s") (cons "search" search-map))
(define-key my/leader-map (kbd "c") (cons "C-c" (simulate-key-press "C-c")))
(define-key my/leader-map (kbd "x") (cons "C-x" (simulate-key-press "C-x")))
;; Remove binding to view-echo-area-messages when clicking on inactive minibuffer
(define-key minibuffer-inactive-mode-map (kbd "<mouse-1>") nil)
;; remove keybind for suspend-frame
(global-unset-key (kbd "C-z"))
;; Don't kill windows when clicking on the mode line
(global-unset-key [mode-line mouse-2])
(global-unset-key [mode-line mouse-3])
:bind
;;ESC Cancels All
(("<escape>" . keyboard-escape-quit)
("C-<backspace>" . my/backward-kill-thing)
: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)
:map my/toggle-map
("M" . my/minimal-ui-mode)
: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)))
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/")
(require 'my-org)
<<header(file_name="my-org.el")>>
Agenda view and task management has been inspired by https://github.com/rougier/emacs-gtd
(use-package org
: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)))
: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)
(latex . 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))
:hook
(org-after-todo-state-change . my/log-todo-next-creation-date)
:bind
(:map my/toggle-map
("c" . org-capture)
:map my/open-map
("a" . org-agenda))
:config
(advice-add 'org-refile :after
(lambda (&rest _)
(my/gtd-save-org-buffers))))
(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))
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
:custom
(org-modern-fold-stars '(("▶" . "▼") ("▹" . "▿") ("▸" . "▾")))
(org-modern-star 'fold)
(org-modern-label-border 0.3)
;; Edit settings
(org-auto-align-tags nil)
(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 ─────────────────────────────────────────────────")
:hook ((org-mode . org-modern-mode)
(org-agenda-finalize . org-modern-agenda)))
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 (:inherit variable-pitch :height 2.0) org-document-title)
(org-level-1 (:inherit variable-pitch :height 1.5) org-level-1)
(org-level-2 (:inherit variable-pitch :height 1.3) org-level-2)
(org-level-3 (:inherit variable-pitch :height 1.2) org-level-3)
(org-level-4 (:inherit variable-pitch :height 1.1) org-level-4)
(org-level-5 (:inherit variable-pitch :height 1.1) org-level-5)
(org-level-6 (:inherit variable-pitch :height 1.1) org-level-6)
(org-level-7 (:inherit variable-pitch :height 1.1) org-level-7)
(org-level-8 (:inherit variable-pitch :height 1.1) org-level-8)
(org-default (:inherit variable-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 160
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)
;; Swicth to minimal ui mode
(my/minimal-ui-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)
;; Disable minimal ui mode
(my/minimal-ui-mode -1)
;; 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-fold-show-entry)
;; Show only direct subheadings of the slide but don't expand them
(org-fold-show-children))
:bind
(:map org-mode-map
("C-c p" . org-present)
: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)
org-mode exporter via pandoc.
(use-package ox-pandoc
:if (executable-find "pandoc")
:after ox
:demand t
:custom
(org-pandoc-options
'((standalone . t)
(mathjax . t)
(variable . "revealjs-url=https://revealjs.com")))
:config
(add-to-list 'org-export-backends 'pandoc))
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))
(provide 'my-org)
;;; my-org.el ends here
(require 'my-ui)
<<header(file_name="my-ui.el")>>
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-themes '((doom-one) (doom-one-light)))
:hook
(after-init . auto-dark-mode))
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)))))
(use-package doom-themes
:preface
(defun my/patch-doom-themes (&rest args)
(ignore args)
(set-face-foreground 'tab-bar (face-foreground 'tab-bar-tab)))
:init
(advice-add 'load-theme :after #'my/patch-doom-themes))
An Emacs plugin that hides (or masks) the current buffer’s mode-line.
(use-package hide-mode-line
:hook
((completion-list-mode . hide-mode-line-mode)
(Man-mode . hide-mode-line-mode)
(symbols-outline-mode . hide-mode-line-mode)))
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))
(use-package mood-line
:config
(setq my/modeline-height 30)
:custom
;; Use pretty Fira Code-compatible glyphs
(mood-line-glyph-alist mood-line-glyphs-fira-code)
(mood-line-format
(mood-line-defformat
:left
(((my/get-bar-image my/modeline-height 2 nil) . " ")
((mood-line-segment-modal) . " ")
((mood-line-segment-anzu) . " ")
((mood-line-segment-multiple-cursors) . " ")
)
:right
(((mood-line-segment-process) . " ")
((mood-line-segment-buffer-status) . " ")
;; ((mood-line-segment-misc-info) . " ")))
((mood-line-segment-major-mode) . " ")
((mood-line-segment-vc) . " ")
((mood-line-segment-checker) . " "))))
(mood-line-segment-modal-meow-state-alist
`((normal ,(nerd-icons-mdicon "nf-md-alpha_m_circle") . font-lock-variable-name-face)
(insert ,(nerd-icons-mdicon "nf-md-alpha_i_circle") . font-lock-string-face)
(keypad ,(nerd-icons-mdicon "nf-md-alpha_k_circle") . font-lock-keyword-face)
(beacon ,(nerd-icons-mdicon "nf-md-alpha_b_circle") . font-lock-type-face)
(motion ,(nerd-icons-mdicon "nf-md-alpha_m_circle") . font-lock-constant-face)))
:hook
(after-init . mood-line-mode))
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")
: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))
(use-package tab-bar
:straight nil
:custom
(tab-bar-history-limit 100)
:preface
(defvar my/workspace-map (make-sparse-keymap) "key-map for workspace commands")
:config
;; 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)
:config
(define-key my/leader-map (kbd "W") (cons "workspace" my/workspace-map))
:bind
(([remap winner-undo] . tab-bar-history-back)
([remap winner-undo] . tab-bar-history-forward)
:map my/toggle-map
("t" . tab-bar-mode)
: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))
:hook
((after-init . tab-bar-history-mode)
(after-init . tab-bar-mode)))
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:
- https://github.com/benleis1/emacs-init/blob/main/tab-config.md#tab2-close-tab
- https://andreyor.st/posts/2020-05-07-making-emacs-tabs-work-like-in-atom/
(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
imenu-list-major-mode ediff-meta-mode ediff-mode symbols-outline-mode flymake-diagnostics-buffer-mode
dired-mode dirvish-directory-view-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 (my/get-bar-image 20 2 nil)
" "
(nerd-icons-icon-for-file name)
(format " %s " name))))
(defun my/tab-line-get-buffer (tab)
"Return the buffer represented by TAB."
(if (bufferp tab) tab (cdr (assq 'buffer tab))))
(defun my/tab-line-windows-with-buffer (buffer)
"Return a list of windows displaying BUFFER across all frames."
(seq-filter (lambda (window)
(eq buffer (window-buffer window)))
(window-list-1 nil nil t)))
(defun my/tab-line-close-or-bury-buffer (buffer)
"Close or bury BUFFER based on its presence in other windows."
(let ((other-windows (my/tab-line-windows-with-buffer buffer)))
(if (> (length other-windows) 1)
(progn
(message "Burying buffer %s" buffer)
(bury-buffer))
(progn
(message "Closing buffer %s" buffer)
(kill-buffer buffer)))))
(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 (my/tab-line-get-buffer tab)))
(with-selected-window window
(let ((tab-list (tab-line-tabs-window-buffers)))
(my/tab-line-close-or-bury-buffer buffer)
(unless (cdr tab-list)
(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))
(use-package time
:straight nil
:custom
(display-time-default-load-average nil)
(display-time-24hr-format t)
(display-time-day-and-date t)
:preface
(defun my/toggle-display-time-mode (&rest args)
(ignore args)
(display-time-mode 'toggle))
:init
(advice-add 'toggle-frame-fullscreen
:after #'my/toggle-display-time-mode))
(provide 'my-ui)
;;; my-ui.el ends here
(require 'my-ux)
<<header(file_name="my-ux.el")>>
Automatically compile outdated Emacs Lisp libraries.
(use-package auto-compile
:custom
(auto-compile-display-buffer nil)
(auto-compile-mode-line-counter t)
:init
(auto-compile-on-load-mode)
:hook
(emacs-lisp-mode . auto-compile-on-save-mode))
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))
(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
(inferior-python-mode . comint-mime-setup))
Replace selected text when typing
(use-package delsel
:straight nil
:hook
((prog-mode conf-mode text-mode) . delete-selection-mode))
Automatically add closing parentheses, quotes, etc.
(use-package elec-pair
:straight nil
:hook
((prog-mode conf-mode) . electric-pair-mode))
Keybindings and optimizations for text-scale-mode. https://github.com/karthink/.emacs.d/blob/4ab4829fde086cb665cba00ee5c6a42d167e14eb/init.el#L4278C1-L4303C64 https://karthinks.com/software/scaling-latex-previews-in-emacs/
(use-package face-remap
:straight nil
:preface
(defvar my/buffer-scale-map (make-sparse-keymap) "key-map for buffer text scale commands")
(defun my/text-scale-adjust-latex-previews ()
"Adjust the size of latex preview fragments when changing the
buffer's text scale."
(pcase major-mode
((or 'latex-mode (guard 'org-auctex-mode))
(dolist (ov (overlays-in (point-min) (point-max)))
(if (eq (overlay-get ov 'category)
'preview-overlay)
(my/zoom-latex-preview ov))))
('org-mode
(dolist (ov (overlays-in (point-min) (point-max)))
(if (eq (overlay-get ov 'org-overlay-type)
'org-latex-overlay)
(my/zoom-latex-preview ov))))))
(defun my/zoom-latex-preview (ov)
(overlay-put
ov 'display
(cons 'image
(plist-put
(cdr (overlay-get ov 'display))
:scale (+ 1.0 (* 0.25 text-scale-mode-amount))))))
:init
(define-key my/buffer-map (kbd "z") (cons "scale" my/buffer-scale-map))
:bind
(:repeat-map my/buffer-scale-map
("+" . text-scale-increase)
("-" . text-scale-decrease)
("=" . text-scale-adjust))
:hook
(text-scale-mode . my/text-scale-adjust-latex-previews))
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-width-fraction 0)
(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)))
(use-package multiple-cursors
:preface
(defvar my/mc-map (make-sparse-keymap) "key-map for multiple cursor commands")
:init
(define-key my/leader-map (kbd "m") (cons "mc" my/mc-map))
:bind
(("C-S-<mouse-1>" . mc/add-cursor-on-click)
:map mc/keymap
("<escape>" . mc/keyboard-quit)
:repeat-map my/mc-map
("n" . mc/mark-next-like-this)
("p" . mc/mark-previous-like-this)
:exit
("a" . mc/mark-all-like-this)
("m" . mc/edit-lines)))
Outline-mode helps to fold and transform headers. Org-mode itself uses outline-mode for its headlines.
(use-package outline
:straight nil
:preface
(defvar my/outline-repeat-map (make-sparse-keymap) "key-map for outline-mode commands")
(defun my/outline-mode-hook nil
(when (not (eq major-mode 'org-mode))
(reveal-mode 1)))
:init
(define-key my/leader-map (kbd "TAB") (cons "outline" my/outline-repeat-map))
:config
(define-key my/outline-repeat-map (kbd "e") (cons "edit" outline-editing-repeat-map))
(define-key my/outline-repeat-map (kbd "n") (cons "navigate" outline-navigation-repeat-map))
:bind
(:repeat-map my/outline-repeat-map
("SPC" . outline-mark-subtree)
("TAB" . outline-cycle)
("S-<tab>" . outline-cycle-buffer)
("<backtab>" . outline-cycle-buffer)
("a" . outline-show-all))
:hook
(((text-mode prog-mode conf-mode) . outline-minor-mode)
(outline-minor-mode . my/outline-mode-hook)))
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))
(use-package popper
:bind
(:map my/toggle-map
("p" . popper-toggle)
("P" . popper-toggle-type))
:custom
;; Define popup buffers
(popper-reference-buffers
'("\\*Messages\\*"
"Output\\*$"
"\\*Async Shell Command\\*"
"\\*Process List\\*"
help-mode
helpful-mode
compilation-mode
"^\\*.*eshell.*\\*$" eshell-mode ;eshell as a popup
"^\\*.*shell.*\\*$" shell-mode ;shell as a popup
"^\\*.*term.*\\*$" term-mode ;term as a popup
"^\\*.*vterm.*\\*$" vterm-mode ;vterm as a popup
"^\\*Flymake diagnostics for .*\\*" flymake-diagnostics-buffer-mode
))
;; grouping popups by project
(popper-mode-line nil)
:preface
(defun my/popper-toggle-advice (&rest _)
(with-current-buffer (current-buffer)
(tab-line-mode (if (eq popper-popup-status 'raised) 1 -1))))
(defun my/popper-display-function (buffer &optional alist)
(popper-select-popup-at-bottom buffer alist)
(with-current-buffer buffer
(tab-line-mode -1)))
:config
(with-eval-after-load 'project
(setq popper-group-function #'popper-group-by-project))
(setq popper-display-function #'my/popper-display-function)
(advice-add #'popper-toggle-type :after #'my/popper-toggle-advice)
:hook
((after-init . popper-mode)
(after-init . popper-echo-mode)))
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))
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-mode
(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)))
(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))
Record cursor position from one session to the other
(use-package saveplace
:straight nil
:hook
(after-init . save-place-mode))
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)))
(provide 'my-ux)
;;; my-ux.el ends here
(require 'my-denote)
<<header(file_name="my-denote.el")>>
Simple note taking and file naming.
(use-package denote
:custom
;; Configure the directory where your notes will be stored.
(denote-directory (expand-file-name "denote/" org-directory))
;; If you want a controlled vocabulary of keywords, specify them here.
(denote-known-keywords '("ENERGY" "STATS" "CS" "AI"))
;; If you want Denote to infer keywords from your note titles, set this to t.
(denote-infer-keywords t)
;; If you want to sort keywords alphabetically, set this to t.
(denote-sort-keywords t)
;; Specify a regular expression to exclude directories from being searched for notes.
(denote-excluded-directories-regexp nil)
;; Configure the date format used in note file names.
(denote-date-format nil)
;; Disable confirmation prompts when renaming files. Use with caution!
(denote-rename-confirmations nil)
;; When displaying backlinks, don't show the surrounding context.
(denote-backlinks-show-context nil)
;; Configure the format used for renaming Denote buffers.
(denote-rename-buffer-format "[D] %t%b")
;; String to indicate that a buffer has backlinks.
(denote-buffer-has-backlinks-string " (<--->)")
;; Define templates for notes
(denote-templates
'((minutes . "minutes")
(plain . nil)))
:preface
(defvar my/denote-map (make-sparse-keymap) "key-map for denote commands")
:init
(define-key my/leader-map (kbd "n") (cons "denote" my/denote-map))
:bind
(:map global-map
:map my/denote-map
("n" . denote)
("N" . denote-type)
("r" . denote-rename-file)
("R" . denote-rename-file-using-front-matter)
("i" . denote-link)
("I" . denote-add-links)
("b" . denote-backlinks)
;; :map org-mode-map
;; ("l" . denote-org-extras-dblock-insert-links)
;; ("b" . denote-org-extras-dblock-insert-links)
:map dired-mode-map
("i" . denote-link-dired-marked-notes)
("r" . denote-dired-rename-marked-files)
("k" . denote-dired-rename-marked-files-with-keywords)
("f" . denote-dired-rename-marked-files-using-front-matter))
:config
(add-hook 'context-menu-functions #'denote-context-menu)
:hook
((text-mode . denote-fontify-links-mode-maybe)
(dired-mode . denote-dired-mode)
(after-init . denote-rename-buffer-mode)))
(use-package denote-menu
:after denote
:bind
(:map my/denote-map
("m" . list-denotes)))
(use-package citar-denote
:after denote citar
:custom
(citar-denote-template 'biblio)
(citar-denote-subdir "bib_notes")
:config
(add-to-list 'denote-templates
`(biblio . ,(concat
"#+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")))
:init
(citar-denote-mode))
(use-package consult-denote
:after denote consult
:bind
(:map my/denote-map
("f" . consult-denote-find)
("g" . consult-denote-grep))
:config
(consult-denote-mode 1))
(provide 'my-denote)
;;; my-denote.el ends here
(require 'my-tools)
<<header(file_name="my-tools.el")>>
(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 mood-line
: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))
(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)
(dirvish-mode-line-height my/modeline-height)
(dirvish-header-line-height my/modeline-height)
: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'
(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)))
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)))
(use-package flyspell
:if (not (executable-find "enchant-2"))
: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)))
(use-package ispell
:straight nil
:after flyspell
:if (executable-find "hunspell")
: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"))
Enchanted Spell Checker.
(use-package jinx
:if (executable-find "enchant-2")
:custom
(jinx-languages "en_US de_DE")
:hook (emacs-startup . global-jinx-mode)
:bind (("M-$" . jinx-correct)
("C-M-$" . jinx-languages)))
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)))
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 start.
(use-package server
:straight nil
:config
(unless (server-running-p)
(server-start)))
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"))
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)))
(provide 'my-tools)
;;; my-tools.el ends here
(require 'my-completion)
<<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
:init
(define-key my/leader-map (kbd ".") (cons "completion" 'cape-prefix-map))
;; 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
:after nerd-icons
: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 denote-directory "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}\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 2) ;; Complete with less prefix keys
(corfu-quit-at-boundary 'separator) ;; Never quit at completion boundary
(corfu-preview-current nil) ;; Disable current candidate preview
(corfu-preselect 'directory) ;; Preselect the fisrt canidate exept for directories select the prompt
:preface
;; 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
;; Free the RET key for less intrusive behavior.
(keymap-unset corfu-map "RET")
(when (featurep 'straight)
(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)
:bind
(("C-SPC" . completion-at-point)
:map corfu-map
("C-SPC" . corfu-insert)
("<tab>" . corfu-next)
("TAB" . corfu-next)
("<backtab>" . corfu-previous)
("SPC" . corfu-insert-separator)
("<escape>" . corfu-quit))
: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))
(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
:straight (:host github :repo "svaante/lsp-snippet")
:demand t
: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
:after nerd-icons
: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
:custom
(completion-styles '(orderless basic))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles basic 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 (expand-file-name "templates.eld" emacs-config-directory))
:bind (("M-+" . tempel-expand) ;; Alternative tempel-expand
("M-*" . tempel-insert)
:map tempel-map
("C-SPC" . tempel-next)
("S-C-SPC" . 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 (featurep 'straight)
(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
("<return>" . vertico-directory-enter))
:hook
((minibuffer-setup . cursor-intangible-mode)
(after-init . vertico-mode)))
(provide 'my-completion)
;;; my-completion.el ends here
(require 'my-vc)
<<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-log-buffer-file magit-log-all)
:preface
(defun my/project-magit-status ()
(interactive)
(defvar vterm-buffer-name)
(let* ((project-directory (project-root (project-current t))))
(magit-status-setup-buffer project-directory)))
:init
(with-eval-after-load 'project
(add-to-list 'project-switch-commands
'(?v "Version Control" my/project-magit-status) t))
: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)
:map project-prefix-map
("v" . my/project-magit-status)))
Show source files’ TODOs (and FIXMEs, etc) in Magit status buffer.
(use-package magit-todos
:after magit
:init (magit-todos-mode))
(provide 'my-vc)
;;; my-vc.el ends here
(require 'my-project)
<<header(file_name="my-project.el")>>
(use-package project
:straight nil
:autoload project-prefix-map
:bind
(:map my/leader-map
("SPC" . project-list-buffers))
:custom
(project-vc-extra-root-markers '(".project"))
(project-switch-commands '((project-find-file "Find file")
(project-find-regexp "Find regexp")
(project-find-dir "Find directory")
;; (project-vc-dir "VC-Dir")
;; (project-eshell "Eshell")
))
:init
(define-key my/leader-map (kbd "p") (cons "project" project-prefix-map)))
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
("S" . project-x-window-state-save)
("l" . 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))
Tab group based workflow isolation.
(use-package auto-tab-groups
:straight (:host github :repo "MArpogaus/auto-tab-groups")
:after tab-bar mood-line project nerd-icons
:custom
;; the following functions trigger the creation of a new tab assigned to group with the name of the given string, or returned by a provided function
(auto-tab-groups-create-commands
'(((denote-create-note denote-menu-list-notes consult-denote-find consult-denote-grep) . "denote")
((custom-buffer-create-internal) . "customize")
((dirvish dirvish-fd) . "dirvish")))
(auto-tab-groups-close-commands
'((dirvish-quit "dirvish" :ignore-result t)
(Custom-buffer-done "customize" :ignore-result t)))
;; height of tabs
(auto-tab-groups-eyecandy-tab-height my/modeline-height)
;; Assign Icons to tab groups
(auto-tab-groups-eyecandy-icons
'(("HOME" . (:style "suc" :icon "custom-emacs"))
("dirvish" . (:style "suc" :icon "custom-folder_oct"))
("denote" . (:style "md" :icon "notebook_edit"))
("customize" . (:style "cod" :icon "settings"))
("^\\[P\\] *" . (:style "oct" :icon "repo"))
("^\\[T\\] *" . (:style "cod" :icon "remote"))))
;; Remove prefix from project groups
(auto-tab-groups-eyecandy-tab-bar-group-name-format-function
(lambda (tab-group-name)
(if (string-match "^\\[.\\] *" tab-group-name)
(substring tab-group-name (match-end 0))
tab-group-name)))
:bind
(:map my/workspace-map
("w" . auto-tab-groups-new-group))
:init
;; automatically assign projects to groups
(auto-tab-groups-project-mode)
;; Enable modern tabs style
(auto-tab-groups-eyecandy-mode)
;; Enable automatic tab group management based on the rules defined above
(auto-tab-groups-mode)
:hook
;; HACK: Re-nable eyecandy mode after tab-bar-mode has been disabled
(tab-bar-mode . auto-tab-groups-eyecandy-mode))
(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)))
(provide 'my-project)
;;; my-project.el ends here
(require 'my-programming)
<<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))
;; Setup speed keys
(let ((map code-cells-mode-map))
(define-key map "n" (code-cells-speed-key 'code-cells-forward-cell))
(define-key map "p" (code-cells-speed-key 'code-cells-backward-cell))
(define-key map "e" (code-cells-speed-key 'code-cells-eval))
(define-key map (kbd "TAB") (code-cells-speed-key 'outline-cycle)))
:bind
(:map code-cells-mode-map
("M-S-<down>" . outline-move-subtree-down)
("M-S-<right>" . outline-demote)
("M-S-<left>" . outline-promote)
("M-S-<up>" . outline-move-subtree-up)
("M-<return>" . outline-insert-heading)
("C-S-<tab>" . outline-cycle-buffer)
("C-<backtab>" . outline-cycle-buffer)
("C-S-<return>" . my/code-cells-eval))
:hook
(python-base-mode . code-cells-mode-maybe))
Structured Editing and Navigation in Emacs.
(use-package combobulate
:straight (:host github :repo "mickeynp/combobulate" :nonrecursive t)
:custom
;; Disable combobulate key prefix
(combobulate-key-prefix nil)
:config
(define-key my/open-map (kbd "c") (cons "combobulate" combobulate-options-key-map))
:bind
(:map combobulate-key-map
("S-<left>" . combobulate-navigate-previous)
("S-<right>" . combobulate-navigate-next)
("S-<down>" . combobulate-navigate-down)
("S-<up>" . combobulate-navigate-up)
("M-<left>" . combobulate-navigate-logical-previous)
("M-<right>" . combobulate-navigate-logical-next)
("M-<down>" . combobulate-drag-down)
("M-<up>" . combobulate-drag-up))
:hook
((prog-mode yaml-ts-mode) . combobulate-mode))
Debug Adapter Protocol for Emacs.
(use-package dape
:preface
(defvar my/debug-map (make-sparse-keymap) "key-map for debug commands")
:init
(define-key my/leader-map (kbd "d") (cons "debug" my/debug-map))
;; To use window configuration like gud (gdb-mi)
;; (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)
;; Set breakpints via fringe or margin mouse clicks
(dape-breakpoint-global-mode t)
: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))))
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
:after project
:preface
(defvar my/lsp-map (make-sparse-keymap) "key-map for lsp commands")
:init
(define-key my/leader-map (kbd "l") (cons "lsp" my/lsp-map))
: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
:straight (:host github :repo "jdtsmith/eglot-booster")
:init (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 support for direnv which operates buffer-locally.
(use-package envrc
:if (executable-find "direnv")
:demand t
:config
;; Fix problem with python promt detection
;; https://github.com/purcell/envrc#troubleshooting
(with-eval-after-load 'python
(advice-add 'python-shell-make-comint :around #'envrc-propagate-environment))
:init
;; The global mode should be enabled late in the startup sequence,
;; to prevent inference with other other global minor modes.
;; We have to use add-hook here manually until [[https://github.com/jwiegley/use-package/issues/965][#965]] is solved.
(add-hook 'after-init-hook #'envrc-global-mode 99))
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
:after project
: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)
Manage Python imports from Emacs!.
(use-package pyimport
:after conda)
Py-isort.el integrates isort into Emacs.
(use-package py-isort
:after conda)
(use-package python
:straight nil
: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-local python-shell-interpreter "ipython3"
python-shell-interpreter-args "--simple-prompt --classic"))
((executable-find "python3")
(setq-local python-shell-interpreter "python3")
(kill-local-variable 'python-shell-interpreter-args))
(t (kill-local-variable 'python-shell-interpreter)
(kill-local-variable 'python-shell-interpreter-args))))
:custom
;; Let Emacs guess Python indent silently
(python-indent-guess-indent-offset t)
(python-indent-guess-indent-offset-verbose nil)
(python-shell-dedicated 'project)
:config
(advice-add #'python-shell-calculate-command :before #'my/find-python-interpreter-advice))
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 treesit.el
.
(use-package treesit-fold
:straight (:host github :repo "emacs-tree-sitter/treesit-fold")
:preface
(defun my/treesit-fold-mode-hook ()
(keymap-local-set "<backtab>" 'treesit-fold-toggle))
:hook
(((yaml-ts-mode python-ts-mode) . treesit-fold-mode)
(treesit-fold-mode . treesit-fold-indicators-mode)
(treesit-fold-mode . my/treesit-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))
(provide 'my-programming)
;;; my-programming.el ends here
(require 'my-keybindings)
<<header(file_name="my-keybindings.el")>>
Meow is yet another modal editing mode for Emacs.
(use-package meow
:straight (:build (:not autoloads))
:demand t
:custom
;; 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
;; Apply advice to 'meow--mode-get-state'
(advice-add 'meow--mode-get-state :around #'my/meow-mode-get-state-advice)
(define-key meow-normal-state-keymap (kbd "SPC") my/leader-map)
(define-key meow-motion-state-keymap (kbd "SPC") 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
("?" . 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)
(which-key-compute-remaps t)
(which-key-prefix-prefix " ")
(which-key-separator " ")
:config
(which-key-setup-minibuffer)
:hook
(meow-mode . which-key-mode))
(provide 'my-keybindings)
;;; my-keybindings.el ends here
(provide 'init)
;;; init.el ends here