Skip to content

Latest commit

 

History

History
executable file
·
3749 lines (3317 loc) · 121 KB

Emacs.org

File metadata and controls

executable file
·
3749 lines (3317 loc) · 121 KB

Emacs Configuration

Table of Contents

Package Manager

;;; init.el --- Initialization file for Emacs -*- lexical-binding:t -*-
;;; Commentary: Emacs Startup File, initialization for Emacs. DO NOT EDIT, auto tangled from Emacs.org.
;;; Code:

Load Package Manager

elpaca has been most pleasant experience thus far.

(defvar elpaca-installer-version 0.8)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
                              :ref nil :depth 1
                              :files (:defaults "elpaca-test.el" (:exclude "extensions"))
                              :build (:not elpaca--activate-package)))
(let* ((repo  (expand-file-name "elpaca/" elpaca-repos-directory))
       (build (expand-file-name "elpaca/" elpaca-builds-directory))
       (order (cdr elpaca-order))
       (default-directory repo))
  (add-to-list 'load-path (if (file-exists-p build) build repo))
  (unless (file-exists-p repo)
    (make-directory repo t)
    (when (< emacs-major-version 28) (require 'subr-x))
    (condition-case-unless-debug err
        (if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
                  ((zerop (apply #'call-process `("git" nil ,buffer t "clone"
                                                  ,@(when-let* ((depth (plist-get order :depth)))
                                                      (list (format "--depth=%d" depth) "--no-single-branch"))
                                                  ,(plist-get order :repo) ,repo))))
                  ((zerop (call-process "git" nil buffer t "checkout"
                                        (or (plist-get order :ref) "--"))))
                  (emacs (concat invocation-directory invocation-name))
                  ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
                                        "--eval" "(byte-recompile-directory \".\" 0 'force)")))
                  ((require 'elpaca))
                  ((elpaca-generate-autoloads "elpaca" repo)))
            (progn (message "%s" (buffer-string)) (kill-buffer buffer))
          (error "%s" (with-current-buffer buffer (buffer-string))))
      ((error) (warn "%s" err) (delete-directory repo 'recursive))))
  (unless (require 'elpaca-autoloads nil t)
    (require 'elpaca)
    (elpaca-generate-autoloads "elpaca" repo)
    (load "./elpaca-autoloads")))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))
;; Install use-package support
(elpaca elpaca-use-package
		;; use-package enable :ensure keyword.
		(elpaca-use-package-mode))
(setopt
 use-package-always-ensure t
 warning-minimum-level :emergency
 native-comp-jit-compilation t
 byte-compile-docstring-max-column 120
 native-compile-prune-cache t)

Install functions that aren’t dynamic detected

I’ve decided to just call these manually instaed of putting them in an install hook.

(defun run-commands-if-no-lock-file ()
  (let ((lock-file "~/.emacs.d/install_lock"))
    (unless (file-exists-p lock-file)
      (condition-case err
        (all-the-icons-install-fonts)
        (error (message "Error running all-the-icons-install-fonts: %s" err)))
      (condition-case err
        (yas-reload-all)
        (error (message "Error running yas-reload-all: %s" err)))
      (condition-case err
        (recentf-cleanup)
        (error (message "Error running recentf-cleanup: %s" err)))
      (condition-case err
        (nerd-icons-install-fonts)
        (error (message "Error running nerd-icons-install-fonts: %s" err))) ;; commented as 'nerd-icons-install-fonts' function doesn't exist.
      (write-region "" nil lock-file))))

Set Custom file

Since we are tangling init.el we need to save custom.el separately. Also makes init.el cleaner.

(setq custom-file (expand-file-name "customs.el" user-emacs-directory))
(defun sn/elpacha-hook ()
  "Settup after elpaca finishes"
  (progn
	(load custom-file 'noerror)
	(meow-global-mode 1)
	(spacious-padding-mode 1)
	;; (mapc #'disable-theme custom-enabled-themes)
	(ef-themes-select 'ef-melissa-dark)
	(let ((buffer (get-buffer " elpaca--read-file")))
	  (when buffer
		(kill-buffer buffer)))))
(add-hook 'elpaca-after-init-hook 'sn/elpacha-hook)

UI Look

Near top so that it loads early

Packages I had at one point or another for UI.

Theme

(use-package ef-themes
  :custom
  (custom-safe-themes t)
  (ef-themes-mixed-fonts t)
  (ef-themes-variable-pitch-ui t)
  (ef-themes-headings
	'((0 variable-pitch light 2.1)
	   (1 variable-pitch light 1.6)
	   (t variable-pitch 1.1)
	   (agenda-date 1.9)
	   (agenda-structure variable-pitch light 1.8)
	   (t variable-pitch)))
  :preface
  (defun my-rgb-to-hex (r g b)
	"Convert RGB to hex color format."
	(format "#%02x%02x%02x" r g b))

  (defun my-darken-color (hex-color factor)
	"Darken HEX-COLOR by factor (a float between 0 and 1)."
	(let* ((r (string-to-number (substring hex-color 1 3) 16))
			(g (string-to-number (substring hex-color 3 5) 16))
			(b (string-to-number (substring hex-color 5 7) 16))
			(r-dark (max 0 (floor (* r factor))))
			(g-dark (max 0 (floor (* g factor))))
			(b-dark (max 0 (floor (* b factor)))))
      (my-rgb-to-hex r-dark g-dark b-dark)))
  (defun my-ef-themes-mod ()
	"Tweak the style of the ef theme."
	(interactive)
    (ef-themes-with-colors
	  (let ((darker (my-darken-color bg-main 0.7)))
		(custom-set-faces
		  `(default ((,c :family "Iosevka" )))
		  `(variable-pitch ((,c :family "Iosevka Aile")))
		  `(ef-themes-key-binding ((,c :inherit (bold ef-themes-fixed-pitch) :foreground ,yellow-warmer :height 0.95)))
		  
		  `(window-divider ((,c :background ,bg-main :foreground ,bg-main)))
		  `(window-divider-first-pixel ((,c :background ,bg-main :foreground ,bg-main)))
		  `(window-divider-last-pixel ((,c :background ,bg-main :foreground ,bg-main)))
		  `(blamer-face ((,c :foreground ,fg-alt :italic t)))
		  `(tab-line              ((,c :background ,bg-dim :foreground ,bg-dim :height 1.1 :box nil)))
		  `(tab-line-tab-group    ((,c :inherit 'tab-line)))
		  `(tab-line-tab          ((,c :inherit 'tab-line :background nil  :forground nil :box nil)))
		  `(tab-line-tab-current  ((,c :height 1.1 :inherit 'tab-line-tab :background nil :box nil)))
		  `(tab-line-tab-inactive ((,c :height 1.1 :inherit 'tab-line-tab :background ,bg-dim :forground ,bg-dim :box nil)))
		  `(tab-line-tab-inactive-alternate ((,c :height 1.1 :inherit 'tab-line-tab :background ,bg-dim :forground ,bg-dim :box nil)))
		  `(tab-line-highlight ((,c :inherit nil :background nil :foreground nil :box nil)))
		  `(line-number ((,c :background ,darker)))
		  `(vertico-posframe ((,c :inherit default :background ,darker)))
		  `(vertico-posframe-border ((,c (:background ,bg-dim))))
		  `(scroll-bar ((,c :foreground ,fg-alt :background ,darker)))
		  `(mode-line ((,c :family "Iosevka Aile" :background ,bg-mode-line :foreground ,fg-main  :box (:line-width 3 :color ,darker))))
		  `(mode-line-active ((,c :background ,bg-mode-line :foreground ,fg-main  :box (:line-width 3 :color ,darker ))))
		  `(mode-line-inactive ((,c :height 120 :box (:line-width 3 :color ,darker))))
		  `(eldoc-box-border ((,c :background ,fg-alt)))
		  `(eldoc-box-body ((,c :family "Iosevka Aile" :background ,darker)))
		  ;; `(org-document-title ((,c :height 1.4)))
		  ;; `(org-modern-todo ((,c :height 1.2)))
		  ;; `(org-modern-done ((,c :height 1.2)))
		  ;; `(org-modern-tag ((,c :height 1.2)))
		  ;; `(org-modern-symbol ((,c :font "Iosevka")))
		  ))))
  (add-hook 'ef-themes-post-load-hook #'my-ef-themes-mod)
  ;; HACK: for scroll bar 
  (add-hook 'after-make-frame-functions
	(lambda (frame)
	  (progn
		(select-frame frame)
		(my-ef-themes-mod)))))

Modeline

(use-package doom-modeline
  :custom
  (doom-modeline-project-detection 'project)
  (doom-modeline-vcs-max-length 30)
  (doom-modeline-height 32)
  (doom-modeline-lsp nil)
  (doom-modeline-workspace-name nil)
  :config
  ;; Define sloth-image segment
  (defun sloth-image-segment ()
	"Return the centered sloth image segment with a specified height in pixels, with background color based on mode line state."
	(let* ((image (create-image (expand-file-name "~/.emacs.d/img/sloth-head.jpg") nil nil :height doom-modeline-height :ascent 'center))
			(current-face (if (eq (selected-window) (minibuffer-window))
							'mode-line-inactive
							'mode-line-active))) ; Choose face based on active state
      (list
		(propertize " " 'display image 'face current-face)
		))) ; Add space on the other side

  (doom-modeline-def-segment sloth-image
	(sloth-image-segment))

  ;; Define the simple line modeline with the sloth-image segment
  (doom-modeline-def-modeline 'simple-line
	'(sloth-image bar eldoc modals " " buffer-info remote-host)
	'(compilation debug check objed-state persp-name process vcs))
  (defun sn/set-modeline ()
	"Customize doom-modeline."
	(line-number-mode -1)
	(column-number-mode -1)
	(doom-modeline-set-modeline 'simple-line 'default))
  (sn/set-modeline))

General

(set-display-table-slot standard-display-table 'truncation ?\s) ;; remove the $ on wrap lines.
(global-prettify-symbols-mode t)
(setopt after-delete-frame-functions nil)

Scolling

C-v and M-v are scroll commands.

(use-package pixel-scroll
  :ensure nil
  :bind
  ([remap scroll-up-command]   . pixel-scroll-interpolate-down)
  ([remap scroll-down-command] . pixel-scroll-interpolate-up)
  :custom
  (pixel-scroll-precision-interpolate-page t)
  (pixel-scroll-precision-use-momentum t)
  (pixel-scroll-precision-large-scroll-height 10) ;; default 40
  
  :init
  (defun kb/pixel-recenter (&optional arg redisplay)
	"Similar to `recenter' but with pixel scrolling.
ARG and REDISPLAY are identical to the original function."
	;; See the links in line 6676 in window.c for
	(when-let* ((current-pixel (pixel-posn-y-at-point))
				(target-pixel (if (numberp arg)
                                  (* (line-pixel-height) arg)
								(* 0.5 (window-body-height nil t))))
				(distance-in-pixels 0)
				(pixel-scroll-precision-interpolation-total-time
				 (/ pixel-scroll-precision-interpolation-total-time 2.0)))
      (setq target-pixel
			(if (<= 0 target-pixel)
				target-pixel
              (- (window-body-height nil t) (abs target-pixel))))
      (setq distance-in-pixels (- target-pixel current-pixel))
      (condition-case err
          (pixel-scroll-precision-interpolate distance-in-pixels nil 1)
		(error nil ;; (message "[kb/pixel-recenter] %s" (error-message-string err))
		  ))
      (when redisplay (redisplay t))))

  (defun kb/pixel-scroll-up (&optional arg)
	 "(Nearly) drop-in replacement for `scroll-up'."
	 (cond
	  ((eq this-command 'scroll-up-line)
       (funcall (ad-get-orig-definition 'scroll-up) (or arg 1)))
	  (t
       (unless (eobp) ; Jittery window if trying to go down when already at bottom
		 (pixel-scroll-precision-interpolate
		  (- (* (line-pixel-height)
				(or arg (- (window-text-height) next-screen-context-lines))))
		  nil 1)))))

  (defun kb/pixel-scroll-down (&optional arg)
		 "(Nearly) drop-in replacement for `scroll-down'."
		 (cond
		  ((eq this-command 'scroll-down-line)
		   (funcall (ad-get-orig-definition 'scroll-down) (or arg 1)))
		  (t
		   (pixel-scroll-precision-interpolate
			(* (line-pixel-height)
			   (or arg (- (window-text-height) next-screen-context-lines)))
			nil 1))))

  (add-hook 'pixel-scroll-precision-mode-hook
			   (lambda ()
				 (cond
				  (pixel-scroll-precision-mode
				   (advice-add 'scroll-up :override 'kb/pixel-scroll-up)
				   (advice-add 'scroll-down :override 'kb/pixel-scroll-down)
				   (advice-add 'recenter :override 'kb/pixel-recenter))
				  (t
				   (advice-remove 'scroll-up 'kb/pixel-scroll-up)
				   (advice-remove 'scroll-down 'kb/pixel-scroll-down)
				   (advice-remove 'recenter 'kb/pixel-recenter)))))
  (pixel-scroll-precision-mode 1))

Page Break Lines render

(use-package page-break-lines
  :init (global-page-break-lines-mode))

Window Size

Change global font size easily

(use-package default-text-scale
		  :bind (("C-M-=". default-text-scale-increase)
				 ("C-M--" . default-text-scale-decrease)))

Different color Delimiters

(use-package rainbow-delimiters
  :hook ((prog-mode conf-mode) . rainbow-delimiters-mode))

Show fill column

(use-package display-fill-column-indicator
  :ensure nil
  :hook ((prog-mode conf-mode) . display-fill-column-indicator-mode))

Padding

Sometimes aesthetic right now I don’t like it when actually working but used it for a long time. maybe move to writing only.

(use-package spacious-padding
  :custom
  (spacious-padding-widths
	'( :internal-border-width 15
	   :header-line-width 4
	   :mode-line-width 2
	   :tab-width 4
	   :right-divider-width 30
	   :scroll-bar-width 8)))

Text centering

I already have a writing mode for org.

(use-package olivetti
  :hook (markdown-mode . olivetti-mode)
  :custom
  (olivetti-minimum-body-width 100)
  (olivetti-style nil))

Hide arrows on Wrapping

(setq-default fringe-indicator-alist
              (delq (assq 'continuation fringe-indicator-alist) fringe-indicator-alist))

General Settings

Slowly organizing these.

(setq-default
 fill-column 80
 blink-cursor-interval 0.4
 buffers-menu-max-size 30
 case-fold-search t
 column-number-mode t
 ediff-split-window-function 'split-window-horizontally
 ediff-window-setup-function 'ediff-setup-windows-plain
 tab-width 4
 mouse-yank-at-point t
 save-interprogram-paste-before-kill t
 set-mark-command-repeat-pop t
 tooltip-delay .4
 ring-bell-function 'ignore
 truncate-lines nil
 word-wrap t)
(setopt 
 use-dialog-box nil
 text-mode-ispell-word-completion nil)
(global-goto-address-mode t)
(with-eval-after-load 'browse-url
  (setq browse-url-browser-function #'browse-url-firefox))
(global-unset-key (kbd "M-SPC")) ;; my second C-c binding

Track Recent Files

When you perform m-x b you will see list of recent files. loaded with consult.

(use-package recentf
  :ensure nil
  :init (recentf-mode t)
  :custom
  (recentf-auto-cleanup 'never) 
  (recentf-max-saved-items 100)
  (backup-directory-alist
	`((".*" . ,temporary-file-directory)))
  :hook ((kill-emacs find-file) . (lambda ()
						(recentf-save-list)))
  :config
  (setq recentf-exclude '(
						   ".*!\\([^!]*!\\).*" ;; matches any string with more than one exclamation mark
						   "/\\.cache.*/.*"    ;; matches any string that includes a directory named .cache
						   "/tmp/.*"           ;; matches any string that includes directory named tmp
						   "/.emacs\\.d/.*"    ;; matches any string that includes directory .emacs.d
						   )))

Auto Save

;; (auto-save-file-name-transforms ;; `((“.*” ,temporary-file-directory t))) ;; (auto-save-visited-interval 30) ;; (remote-file-name-inhibit-auto-save-visited t) ;; (auto-save-visited-mode 1)

(use-package files
  :ensure nil
  :custom
  (auto-save-default nil) ;; Disable global auto-save feature
  (remote-file-name-inhibit-locks t))

Auto update file

When A file changes on disk update Emacs.

(use-package autorevert
  :ensure nil
  :custom
  (auto-revert-use-notify nil)
  (auto-revert-verbose nil)
  :init (global-auto-revert-mode 1))

TRAMP

Setting Controlmaster to nil sets precedence to my ssh config.

(use-package tramp
  :ensure nil
  :custom
  (tramp-default-method "ssh")
  (tramp-verbose 0)
  (tramp-use-connection-share nil)
  (tramp-use-ssh-controlmaster-options nil)
  :config
  (add-to-list 'backup-directory-alist
             (cons tramp-file-name-regexp nil))
  (add-to-list 'tramp-remote-path 'tramp-own-remote-path)
  (add-to-list 'tramp-connection-properties
			   (list (regexp-quote "/ssh:ag-nehrbash:")
					 "remote-shell" "/usr/bin/bash"
					 "direct-async-process" t
					 "tramp-direct-async" t))
  (add-to-list 'tramp-connection-properties
			   (list (regexp-quote "/docker:")
					 "remote-shell" "/usr/bin/bash"
					 "direct-async-process" t
					 "tramp-direct-async" t)))

Save History

(use-package savehist
  :ensure nil
  :init (savehist-mode 1)
  :config
  (setq history-length 25))

Save Place

Open files back up at same position.

(save-place-mode 1)

I-Search

Show number of matches while searching

(use-package anzu
  :bind (([remap query-replace-regexp] . anzu-query-replace-regexp)
		 ([remap query-replace] . anzu-query-replace)
		 ("C-M-w". isearch-yank-symbol))
  :custom
  (anzu-mode-lighter "")
  :config
  (defun sanityinc/isearch-exit-other-end ()
	"Exit isearch, but at the other end of the search string.
This is useful when followed by an immediate kill."
	(interactive)
	(isearch-exit)
	(goto-char isearch-other-end))
  (define-key isearch-mode-map [(control return)] 'sanityinc/isearch-exit-other-end)
  ;; Search back/forth for the symbol at point
  ;; See http://www.emacswiki.org/emacs/SearchAtPoint
  (defun isearch-yank-symbol ()
	"*Put symbol at current point into search string."
	(interactive)
	(let ((sym (thing-at-point 'symbol)))
	  (if sym
		  (progn
			(setq isearch-regexp t
				  isearch-string (concat "\\_<" (regexp-quote sym) "\\_>")
				  isearch-message (mapconcat 'isearch-text-char-description isearch-string "")
				  isearch-yank-flag t))
		(ding)))
	(isearch-search-and-update)))

Ibuffer

Might just get rid of ibuffer in favor of consult-project-buffer which is the main reason I used ibuffer.

(use-package ibuffer-project
  :bind ("C-x C-b" . ibuffer)
  :custom
  (ibuffer-show-empty-filter-groups nil)
  (ibuffer-project-use-cache t)
  :config
  (defun sn/ibuffer-preferred-filters ()
	"hides stare buffers and sorts by project."
	(setq ibuffer-filter-groups (ibuffer-project-generate-filter-groups))
	(unless (eq ibuffer-sorting-mode 'project-file-relative)
	  (ibuffer-do-sort-by-project-file-relative))
	(setq ibuffer-tmp-hide-regexps '("^\\*.*" "^ .*"))
	(ibuffer-update t))
  :hook (ibuffer . sn/ibuffer-preferred-filters))

Newline Behavior

(setq ad-redefinition-action 'accept)
(defun sanityinc/newline-at-end-of-line ()
  "Move to end of line, enter a newline, and reindent."
  (interactive)
  (move-end-of-line 1)
  (newline-and-indent))

(global-set-key (kbd "RET") 'newline-and-indent)
(global-set-key (kbd "C-<return>") 'sanityinc/newline-at-end-of-line)

(use-package display-line-numbers
  :ensure nil
  :custom
  (display-line-numbers-type 'relative)
  (display-line-numbers-width 3)
  :hook ((prog-mode web-mode conf-mode yaml-mode) . display-line-numbers-mode)
  (display-line-numbers-mode . (lambda ()
								 (face-remap-add-relative
								  'fringe :background "#281d12"))))

Expand Region

(use-package expand-region
  :bind (("M-C e" . er/expand-region)
		 ("M-C o" . er/mark-outside-pairs)))

symbol-overlay

(use-package symbol-overlay
  :hook ((prog-mode html-mode yaml-mode conf-mode) . symbol-overlay-mode)
  :config
  (define-key symbol-overlay-mode-map (kbd "M-i") 'symbol-overlay-put)
  (define-key symbol-overlay-mode-map (kbd "M-I") 'symbol-overlay-remove-all)
  (define-key symbol-overlay-mode-map (kbd "M-n") 'symbol-overlay-jump-next)
  (define-key symbol-overlay-mode-map (kbd "M-p") 'symbol-overlay-jump-prev))

kill backwards

(defun kill-back-to-indentation ()
  "Kill from point back to the first non-whitespace character on the line."
  (interactive)
  (let ((prev-pos
		 (point)))
	(back-to-indentation)
	(kill-region (point) prev-pos)))

(global-set-key (kbd "C-M-<backspace>") 'kill-back-to-indentation)

Define backward-up-sexp

(defun sanityinc/backward-up-sexp (arg)
  "Jump up to the start of the ARG'th enclosing sexp."
  (interactive "p")
  (let ((ppss (syntax-ppss)))
	(cond ((elt ppss 3)
		   (goto-char (elt ppss 8))
		   (sanityinc/backward-up-sexp (1- arg)))
		  ((backward-up-list arg)))))
(global-set-key [remap backward-up-list] 'sanityinc/backward-up-sexp) ; C-M-u, C-M-up

Multi Cursor

(use-package multiple-cursors
  :bind (("C-<" . mc/mark-previous-like-this)
		 ("C->" . mc/mark-next-like-this)
		 ("C-+" . mc/mark-next-like-this)
		 ("C-c C-<" . mc/mark-all-like-this)
		 ;; From active region to multiple cursors:
		 ("C-c m r" . set-rectangular-region-anchor)
		 ("C-c m c" . mc/edit-lines)
		 ("C-c m e" . mc/edit-ends-of-lines)
		 ("C-c m a" . mc/edit-beginnings-of-lines)))

White spaces

View and auto remove them.

(use-package whitespace-cleanup-mode
  :commands (whitespace-cleanup)
  :hook ((prog-mode text-mode conf-mode web-mode sql-mode) . sanityinc/show-trailing-whitespace)
  :config
  (push 'markdown-mode whitespace-cleanup-mode-ignore-modes)
  (defun sanityinc/show-trailing-whitespace ()
	"Enable display of trailing whitespace in this buffer."
	(setq-local show-trailing-whitespace t)
	(whitespace-cleanup-mode 1)))

Matching and Highlighting Delimiters

Was using much more complicated packages like paredit/smartparens but was not using there features.

(electric-pair-mode t)
(use-package paren ; highight matching paren
  :ensure nil
  :hook (prog-mode . show-paren-mode))

Improve window switching

Purcell’s configuration.

(use-package winner
  :ensure nil
  :bind (("C-x 2" . split-window-func-with-other-buffer-vertically)
		 ("C-x 3" . split-window-func-with-other-buffer-horizontally)
		 ("C-x 1" . sanityinc/toggle-delete-other-windows)
		 ("C-x |" . split-window-horizontally-instead)
		 ("C-x _" . split-window-vertically-instead)
		 ("<f7>" . sanityinc/split-window)
		 ("C-c <down>" . sanityinc/toggle-current-window-dedication))
  :config
  (defun split-window-func-with-other-buffer-vertically ()
	"Split this window vertically and switch to the new window."
	(interactive)
	(split-window-vertically)
	(let ((target-window (next-window)))
	  (set-window-buffer target-window (other-buffer))
	  (select-window target-window)))

  (defun split-window-func-with-other-buffer-horizontally ()
	"Split this window horizontally and switch to the new window."
	(interactive)
	(split-window-horizontally)
	(let ((target-window (next-window)))
	  (set-window-buffer target-window (other-buffer))
	  (select-window target-window)))

  (defun sanityinc/toggle-delete-other-windows ()
	"Delete other windows in frame if any, or restore previous window config."
	(interactive)
	(if (and (bound-and-true-p winner-mode)
		   (equal (selected-window) (next-window)))
		(winner-undo)
	  (delete-other-windows)))

  (defun split-window-horizontally-instead ()
	"Kill any other windows and re-split such that the current window is on the top half of the frame."
	(interactive)
	(let ((other-buffer (and (next-window) (window-buffer (next-window)))))
	  (delete-other-windows)
	  (split-window-horizontally)
	  (when other-buffer
		(set-window-buffer (next-window) other-buffer))))

  (defun split-window-vertically-instead ()
	"Kill any other windows and re-split such that the current window is on the left half of the frame."
	(interactive)
	(let ((other-buffer (and (next-window) (window-buffer (next-window)))))
	  (delete-other-windows)
	  (split-window-vertically)
	  (when other-buffer
		(set-window-buffer (next-window) other-buffer))))

  (defun sanityinc/split-window()
	"Split the window to see the most recent buffer in the other window.
Call a second time to restore the original window configuration."
	(interactive)
	(if (eq last-command 'sanityinc/split-window)
		(progn
		  (jump-to-register :sanityinc/split-window)
		  (setq this-command 'sanityinc/unsplit-window))
	  (window-configuration-to-register :sanityinc/split-window)
	  (switch-to-buffer-other-window nil)))

  (defun sanityinc/toggle-current-window-dedication ()
	"Toggle whether the current window is dedicated to its current buffer."
	(interactive)
	(let* ((window (selected-window))
		   (was-dedicated (window-dedicated-p window)))
	  (set-window-dedicated-p window (not was-dedicated))
	  (message "Window %sdedicated to %s"
			   (if was-dedicated "no longer " "")
			   (buffer-name)))))

Don’t ask to kill on exit

Mainly because of open terminals don’t ask on killing Emacs to stop process.

(setq confirm-kill-processes nil)

Editing Utilities

General editing configurations.

Meow - Modal Editing

xC-x
hC-h
cC-c
mM-
gC-M-
(use-package meow
  :hook (after-init . meow-global-mode)
  :demand t
  :config
  (setq meow-replace-state-name-list
		 '((normal . "🟢")
		   (motion . "🟡")
		   (keypad . "🟣")
		   (insert . "🟠")
		   (beacon . "🔴")))
  (add-to-list 'meow-mode-state-list '(org-mode . insert))
  (add-to-list 'meow-mode-state-list '(eat-mode . insert))
  (add-to-list 'meow-mode-state-list '(vterm-mode . insert))
  (add-to-list 'meow-mode-state-list '(git-commit-mode . insert))
  (setq meow-cheatsheet-layout meow-cheatsheet-layout-colemak-dh)
  (meow-motion-overwrite-define-key
	;; Use e to move up, n to move down.
	;; Since special modes usually use n to move down, we only overwrite e here.
	'("e" . meow-prev)
	'("<escape>" . ignore))
  (meow-leader-define-key
	'("?" . meow-cheatsheet)
	;; To execute the originally e in MOTION state, use SPC e.
	'("e" . "H-e")
	'("o" . switch-window)
	'("1" . meow-digit-argument)
	'("2" . meow-digit-argument)
	'("3" . meow-digit-argument)
	'("4" . meow-digit-argument)
	'("5" . meow-digit-argument)
	'("6" . meow-digit-argument)
	'("7" . meow-digit-argument)
	'("8" . meow-digit-argument)
	'("9" . meow-digit-argument)
	'("0" . meow-digit-argument)
	'("f ." . find-file-at-point))
  (meow-normal-define-key
	'("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)
	'("-" . negative-argument)
	'(";" . meow-reverse)
	'("," . meow-inner-of-thing)
	'("." . meow-bounds-of-thing)
	'("[" . meow-beginning-of-thing)
	'("]" . meow-end-of-thing)
	'("/" . meow-visit)
	'("a" . meow-append)
	'("A" . meow-open-below)
	'("b" . meow-back-word)
	'("B" . meow-back-symbol)
	'("c" . meow-change)
	'("i" . meow-prev)
	'("I" . meow-prev-expand)
	'("f" . meow-find)
	'("g" . meow-cancel-selection)
	'("G" . meow-grab)
	'("n" . meow-left)
	'("N" . meow-left-expand)
	'("o" . meow-right)
	'("O" . meow-right-expand)
	'("j" . meow-join)
	'("k" . meow-kill)
	'("l" . meow-line)
	'("L" . meow-goto-line)
	'("m" . meow-mark-word)
	'("M" . meow-mark-symbol)
	'("e" . meow-next)
	'("E" . meow-next-expand)
	'("h" . meow-block)
	'("H" . meow-to-block)
	'("p" . meow-yank)
	'("q" . meow-quit)
	'("r" . meow-replace)
	'("s" . meow-insert)
	'("S" . meow-open-above)
	'("t" . meow-till)
	'("u" . meow-undo)
	'("U" . meow-undo-in-selection)
	'("v" . meow-search)
	'("w" . meow-next-word)
	'("W" . meow-next-symbol)
	'("x" . meow-delete)
	'("X" . meow-backward-delete)
	'("y" . meow-save)
	'("z" . meow-pop-selection)
	'("'" . repeat)
	'("<escape>" . ignore)))

Avy

(use-package avy
  :commands avy-goto-char-timer
  :custom (avy-timeout-seconds 0.3)
  :bind ("M-j" . avy-goto-char-timer)
  :config
  (defun avy-action-copy-whole-line (pt)
	(save-excursion
      (goto-char pt)
      (cl-destructuring-bind (start . end)
          (bounds-of-thing-at-point 'line)
		(copy-region-as-kill start end)))
	(select-window
	 (cdr (ring-ref avy-ring 0))) t)
  (defun avy-action-yank-whole-line (pt)
	"Quick copy line."
	(avy-action-copy-whole-line pt)
	(save-excursion (yank)) t)
  (defun avy-action-teleport-whole-line (pt)
	"Quick copy line to current point."
    (avy-action-kill-whole-line pt)
    (save-excursion (yank)) t)
  (defun avy-embark-act (pt)
	"Use Embark to act on the item at PT."
	(unwind-protect
		(save-excursion
          (goto-char pt)
          (embark-act))
      (select-window
       (cdr (ring-ref avy-ring 0))) t))
  (setf
   (alist-get ?y avy-dispatch-alist) 'avy-embark-act
   (alist-get ?y avy-dispatch-alist) 'avy-action-yank
   (alist-get ?w avy-dispatch-alist) 'avy-action-copy
   (alist-get ?W avy-dispatch-alist) 'avy-action-copy-whole-line
   (alist-get ?Y avy-dispatch-alist) 'avy-action-yank-whole-line
   (alist-get ?t avy-dispatch-alist) 'avy-action-teleport
   (alist-get ?T avy-dispatch-alist) 'avy-action-teleport-whole-line))
avy multi-cursor
(use-package lasgun						
  :ensure (:host github :repo "aatmunbaxi/lasgun.el")
  :config
  (require 'transient)
  ;; Defines some lasgun actions
  (define-lasgun-action lasgun-action-upcase-word t upcase-word)
  (define-lasgun-action lasgun-action-downcase-word t downcase-word)
  (define-lasgun-action lasgun-action-kill-word nil kill-word)

  (transient-define-prefix lasgun-transient ()
	"Main transient for lasgun."
	[["Single Marks"
	  ("c" "Char timer" lasgun-mark-char-timer :transient t)
	  ("w" "Word" lasgun-mark-word-0 :transient t)
	  ("l" "Begin of line" lasgun-mark-line :transient t)
	  ("s" "Symbol" lasgun-mark-symbol-1 :transient t)
	  ("w" "Whitespace end" lasgun-mark-whitespace-end :transient t)
	  ("x" "Clear lasgun mark ring" lasgun-clear-lasgun-mark-ring :transient t)
	  ("u" "Undo lasgun mark" lasgun-pop-lasgun-mark :transient t)]
	 ["Single Mark Actions"
	  ("SPC" "Make cursors" lasgun-make-multiple-cursors)
	  ("." "Embark act all" lasgun-embark-act-all)
	  ("U" "Upcase" lasgun-action-upcase-word)
	  ("l" "Downcase" lasgun-action-downcase-word)
	  ("K" "Kill word" lasgun-action-kill-word)
	  ("q" "Quit" transient-quit-one)]])
  (global-set-key (kbd "M-SPC i") 'lasgun-transient))

Transient

(use-package transient
  :bind
  ("C-x g" . sn/project-menu)
  (:map isearch-mode-map
		("C-t" . sn/isearch-menu))
  :config
  (transient-define-prefix sn/project-menu ()
	"Project Actions"
	[["Commpile"
	   ("c" "Compile" protogg-compile)
	   ("r" "Recompile" recompile)
	   ("m" "Makefile" makefile-runner)]
	  ["Git"
		("s" "Status" magit-status)
		("d" "Dispatch" magit-dispatch)
		("R" "Rebase menu" sn/smerge)
		("g" "Time Machine" git-timemachine)]]
	[["Misc"
	   ("q" "Quit" transient-quit-one)
	   ("p" "Switch Project" project-switch-project)]])
  (transient-define-prefix sn/isearch-menu ()
	"isearch Menu"
	[["Edit Search String"
	  ("e" "Edit the search string (recursive)"
	   isearch-edit-string :transient nil)
	  ("w" "Pull next word or character word from buffer"
	   isearch-yank-word-or-char :transient nil)
	  ("s" "Pull next symbol or character from buffer"
	   isearch-yank-symbol-or-char :transient nil)
	  ("l" "Pull rest of line from buffer"
	   isearch-yank-line :transient nil)
	  ("y" "Pull string from kill ring"
	   isearch-yank-kill :transient nil)
	  ("t" "Pull thing from buffer"
	   isearch-forward-thing-at-point :transient nil)]
	 ["Replace"
	  ("q" "Start ‘query-replace’"
	   anzu-isearch-query-replace :if-nil buffer-read-only :transient nil)
	  ("x" "Start ‘query-replace-regexp’"
		anzu-isearch-query-replace-regexp :if-nil buffer-read-only :transient nil)]]
	[["Toggle"
	  ("X" "Toggle regexp searching"
	   isearch-toggle-regexp :transient nil)
	  ("S" "Toggle symbol searching"
	   isearch-toggle-symbol :transient nil)
	  ("W" "Toggle word searching"
	   isearch-toggle-word :transient nil)
	  ("F" "Toggle case fold"
	   isearch-toggle-case-fold :transient nil)
	  ("L" "Toggle lax whitespace"
	   isearch-toggle-lax-whitespace :transient nil)]
	 ["Misc"
	  ("l" "Start ‘consult-line’"
	   consult-line :transient nil)
	  ("g" "Start ‘consult-git-grep’"
	   consult-git-grep :transient nil)
	  ("r" "Start ‘consult-ripgrep’"
	   consult-ripgrep :transient nil)
	  ("o" "occur"
	   isearch-occur :transient nil)]]))

File Handler Functions

Delete the current file

(defun delete-this-file ()
  "Delete the current file, and kill the buffer."
  (interactive)
  (unless (buffer-file-name)
	 (error "No file is currently being edited"))
  (when (yes-or-no-p (format "Really delete '%s'?"
							  (file-name-nondirectory buffer-file-name)))
	 (delete-file (buffer-file-name))
	 (kill-this-buffer)))

This Emacs Lisp config block defines a function called delete-this-file. It deletes the current file and kills the buffer associated with it. It first checks if there is a file being edited in the buffer. If not, it throws an error. Then, it prompts the user for confirmation to delete the file. If the user confirms, it proceeds to delete the file using delete-file and kills the buffer using =kill-this-buffer

Rename the current file

(defun rename-this-file-and-buffer (new-name)
  "Renames both current buffer and file it's visiting to NEW-NAME."
  (interactive "sNew name: ")
  (let ((name (buffer-name))
		 (filename (buffer-file-name)))
	 (unless filename
	   (error "Buffer '%s' is not visiting a file!" name))
	 (progn
	   (when (file-exists-p filename)
		 (rename-file filename new-name 1))
	   (set-visited-file-name new-name)
	   (rename-buffer new-name))))

This Emacs Lisp configuration block defines a function called rename-this-file-and-buffer which renames both the current buffer and the file it’s visiting to a new name specified by the user. It takes user input for the new name using the interactive keyword, checks if the buffer is visiting a file, renames the file if it exists, updates the visited file name, and renames the buffer accordingly.

Toggle Mode Line

(defun toggle-mode-line ()
  "toggles the modeline on and off"
  (interactive)
  (setq mode-line-format
 		(if (equal mode-line-format nil)
 			(default-value 'mode-line-format)))
  (redraw-display))

This Emacs Lisp block defines a function called “toggle-mode-line” that toggles the display of the mode line on and off. When called interactively, it checks if the mode line is currently visible by comparing it to nil. If it is visible, it sets the mode-line-format to the default value, effectively hiding the mode line. If it is not visible, it sets the mode-line-format to nil, showing the mode line. Finally, it redraws the display to reflect the changes.

Marks

advice to add to functions that don’t add mark

(transient-mark-mode t)
(delete-selection-mode t)
;; (kill-ring-deindent-mode t) ; emacs 30
(defun sn/add-mark-before (func &rest args)
  "Add a mark before calling FUNC with ARGS."
  (push-mark (point) t nil)
  (apply func args))

Move & Duplicating Lines

Shift lines up and down with M-up and M-down. When paredit is enabled, it will use those keybindings. For this reason, you might prefer to use M-S-up and M-S-down, which will work even in lisp modes.

(use-package move-dup
  :bind(("M-<up>" . move-dup-move-lines-up)
		 ("M-<down>" . move-dup-move-lines-down)
		 ("C-c d" . move-dup-duplicate-down)
		 ("C-c u" . move-dup-duplicate-up)))

This configuration block uses the use-package macro to manage the move-dup package. It sets up several keybindings and enables move-dup globally after initialization with the after-init hook. The keybindings allow you to move lines up and down, duplicate lines up and down using different key combinations.

Whole Line Or Region

Cut/copy the current line if no region is active.

(use-package whole-line-or-region
  :config (whole-line-or-region-global-mode t))

This Emacs Lisp code block configures the whole-line-or-region package, enabling global mode and binding the key combination “M-j” to the function comment-dwim.

Beginning Of Line Text Then Line

(defun smarter-move-beginning-of-line (arg)
  "Move point back to indentation of beginning of line.

Move point to the first non-whitespace character on this line.
If point is already there, move to the beginning of the line.
Effectively toggle between the first non-whitespace character and
the beginning of the line.

If ARG is not nil or 1, move forward ARG - 1 lines first.  If
point reaches the beginning or end of the buffer, stop there."
  (interactive "^p")
  (setq arg (or arg 1))

  ;; Move lines first
  (when (/= arg 1)
	 (let ((line-move-visual nil))
	   (forward-line (1- arg))))

  (let ((orig-point (point)))
	 (back-to-indentation)
	 (when (= orig-point (point))
	   (move-beginning-of-line 1))))

;; remap C-a to `smarter-move-beginning-of-line'
(global-set-key [remap move-beginning-of-line]
				 'smarter-move-beginning-of-line)

This Emacs Lisp configuration block defines a function called smarter-move-beginning-of-line. This function moves the cursor to the indentation of the beginning of the current line. If the cursor is already at the indentation, it moves to the actual beginning of the line. The function also accepts an argument ARG which, if non-nil or non-zero, moves the cursor forward ARG - 1 lines before executing the main logic.

This configuration also remaps C-a (the default keybinding for move-beginning-of-line) to the smarter-move-beginning-of-line function using the global-set-key function.

Switch Windows Via Letters

(use-package ace-window
  :custom
  (aw-keys '(?a ?r ?s ?d ?t ?n ?e ?i ?o))
  (aw-ignore-current t)
  :bind ("M-o" . ace-window))

Swap Windows

  • Switch buffer focus using control + arrow key.
  • Move buffer direction with control+shift+arrow key.
(use-package windswap
  :config
  (windmove-default-keybindings 'control)
  (windswap-default-keybindings 'shift 'control))

This Emacs Lisp code configures the windswap package, which provides functions to navigate and rearrange windows. It sets up keybindings for both windmove (to move between windows) and windswap (to swap windows) using the control and shift keys. This configuration is executed after Emacs initializes.

Sudo Editing

This is completely unnecessary since you could just tramp the same file really quick but using this package is a slightly nicer user experience.

(use-package sudo-edit
  :commands (sudo-edit))

Place Buffer As Fullframe

(use-package fullframe)

revert all unsaved buffers

(defun revert-all-buffers-no-confirm ()
  "Revert all buffers without confirmation."
  (interactive)
  (dolist (buf (buffer-list))
    (with-current-buffer buf
      (when (and (buffer-file-name) (buffer-modified-p))
        (revert-buffer t t t)))))

Mini-buffer / Completion Framework

What make Emacs, Emacs.

Minbuffer

(use-package minibuffer
  :ensure nil
  :bind
  (:map minibuffer-local-completion-map
  		("<backtab>" . minibuffer-force-complete))
  :custom
  (enable-recursive-minibuffers t)
  (minibuffer-eldef-shorten-default t)
  (read-minibuffer-restore-windows t) ;; don't revert to original layout after cancel.
  (resize-mini-windows t)
  (minibuffer-prompt-properties
   '(read-only t cursor-intangible t face minibuffer-prompt))
  :hook
  (completion-list-mode . force-truncate-lines)
  (minibuffer-setup . (lambda ()
  						(cursor-intangible-mode 1)))
  :config
  (minibuffer-depth-indicate-mode)
  (minibuffer-electric-default-mode))

Vertico

(use-package vertico
  :bind
  (:map vertico-map
		("M-j" . vertico-quick-insert)
		("C-q" . vertico-quick-exit))
  :init
  (vertico-mode 1)
  (vertico-multiform-mode 1)
  :config
  (add-to-list 'vertico-multiform-commands
			   '(project-switch-project buffer)))
(use-package marginalia
  :init
  (marginalia-mode)
  :custom
  (marginalia-align 'right)
  :bind
  (:map minibuffer-local-map
		("M-a" . marginalia-cycle))
  :custom
  (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))
(use-package all-the-icons-completion
  :hook (marginalia-mode-hook . all-the-icons-completion-marginalia-setup)
  :init (all-the-icons-completion-mode))

postframe candidate menu

(use-package vertico-posframe
  :after vertico
  :config
  (vertico-posframe-mode 1)
  ;; don't change colors
  (defun my-vertico-posframe-get-border-color-advice (&rest _args)
  "Always return the color of `vertico-posframe-border`."
	(face-attribute 'vertico-posframe-border :background nil t))
  (advice-add 'vertico-posframe--get-border-color :override #'my-vertico-posframe-get-border-color-advice)
  :custom
  (vertico-posframe-poshandler #'posframe-poshandler-frame-center)
  (vertico-posframe-vertico-multiform-key "M-m"))

fuzzy match

Supposed to be better than built in flex.

(use-package hotfuzz
  :after orderless)

Orderless

instead of fuzzy (flex) in emacs terms orderless is a very nice completion framework it’s particularly good at finding matches at end of things faster. Copy some stuff from here https://github.com/oantolin/emacs-config/blob/d0ffbd9527e48bd88dc4c9937e4dc80f783d844e/init.el#L375C2-L396C72https://github.com/oantolin/emacs-config/blob/d0ffbd9527e48bd88dc4c9937e4dc80f783d844e/init.el#L375C2-L396C72

(use-package orderless
  :custom
  (orderless-matching-styles 'orderless-regexp)
  (orderless-component-separator #'orderless-escapable-split-on-space)
  (read-file-name-completion-ignore-case t)
  (read-buffer-completion-ignore-case t)
  (completion-ignore-case t)
  (completion-lazy-hilit t)
  (completion-flex-nospace t)
  (completion-category-defaults nil)
  (completion-styles '(orderless))
  (completion-category-overrides '((file (styles basic partial-completion)))))

Edit Search Results Directly

wgrep lets you edit directly (good with embark export).

(use-package wgrep
  :custom
  (wgrep-auto-save-buffer t)
  (wgrep-enable-key "r"))

Consult

https://github.com/minad/consult

(use-package consult
  :after vertico
  :bind
  ("C-s" . (lambda () (interactive) (consult-line (thing-at-point 'symbol))))
  ("C-r" . (lambda () (interactive) (consult-ripgrep nil (thing-at-point 'symbol))))
  ("M-S" . (lambda () (interactive) (consult-line-multi (thing-at-point 'symbol))))
  ("C-c M-x" . consult-mode-command)
  ("C-c h" . consult-history)
  ("C-c k" . consult-kmacro)
  ("C-c m" . consult-man)
  ("C-c i" . consult-info)
  ([remap Info-search] . consult-info)
  ;; C-x bindings in `ctl-x-map'
  ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command
  ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer
  ("C-x f" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
  ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
  ("C-x t b" . consult-buffer-other-tab)    ;; orig. switch-to-buffer-other-tab
  ("C-x r b" . consult-bookmark)            ;; orig. bookmark-jump
  ;; Custom M-# bindings for fast register access
  ("M-\"" . consult-register)
  ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated)
  ("C-M-'" . consult-register)
  ;; Other custom bindings
  ("M-y" . consult-yank-pop)                ;; orig. yank-pop
  ;; M-g bindings in `goto-map'
  ("M-SPC e" . consult-compile-error)
  ("M-g g" . consult-goto-line)             ;; orig. goto-line
  ("M-g M-g" . consult-goto-line)           ;; orig. goto-line
  ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
  ("M-SPC m" . consult-mark)
  ("M-SPC g" . consult-global-mark)
  ("M-g i" . consult-imenu)
  ("M-g I" . consult-imenu-multi)
  ;; M-s bindings in `search-map'
  ("M-s d" . consult-find)                  ;; Alternative: consult-fd
  ("M-s c" . consult-locate)
  ("M-s g" . consult-grep)
  ("M-s G" . consult-git-grep)
  ("M-s r" . consult-ripgrep)
  ("M-s l" . consult-line)
  ("M-s L" . consult-line-multi)
  ("M-s k" . consult-keep-lines)
  ("M-s u" . consult-focus-lines)
  ;; Isearch integration
  ("M-s 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))
  :init
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)
  ;; Example of advising consult-line
  (advice-add #'consult-line :around #'sn/add-mark-before)  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref)
  (setq register-preview-delay 0.5
		register-preview-function #'consult-register-format)
  :custom
  (consult-narrow-key "<")
  (consult-preview-key '("M-," :debounce 0 any))
  :config
  (setq consult-ripgrep-args (concat consult-ripgrep-args " --hidden"))
  (defun vc-modified-file ()
	"Use completion to go to a modified file in the Git repository."
	(interactive)
	(let* ((default-directory (vc-root-dir))  ;; Ensures we're in the root of the project
           (git-cmd "git status --porcelain=v1 --untracked-files=no")  ;; Git command to get modified files
           (files (split-string (shell-command-to-string git-cmd) "\n" t))
           (modified-files (mapcar (lambda (line)
									 (string-trim (substring line 3))) files))
           ;; Use completing-read to select the file
           (selected-file (completing-read "Goto vc file: " modified-files nil t)))
      (when selected-file
		(find-file selected-file))))
  (defvar consult--source-vc-modified-file
	`(:name     "VC Modified File"
				:narrow   ?g
				:category file
				:face     consult-file
				:history  file-name-history
				:state    ,#'consult--file-state
				:new
				,(lambda (file)
				   (consult--file-action
					(expand-file-name file (vc-root-dir))))
				:enabled
				,(lambda ()
				   (vc-root-dir))
				:items
				,(lambda ()
				   (when-let (root (vc-root-dir))
					 (let ((len (length root))
						   (ht (consult--buffer-file-hash))
						   items)
					   (dolist (file (vc-modified-files) (nreverse items))
						 (unless (eq (aref file 0) ?/)
						   (let (file-name-handler-alist) ;; No Tramp slowdown please.
							 (setq file (expand-file-name file))))
						 (when (and (not (gethash file ht)) (string-prefix-p root file))
						   (let ((part (substring file len)))
							 (when (equal part "") (setq part "./"))
							 (put-text-property 0 1 'multi-category `(file . ,file) part)
							 (push part items))))))))
	"VC modified file candidate source for `consult-buffer'.")
  (defvar consult--source-org
	(list :name     "Org"
		  :category 'buffer
		  :narrow   ?o
		  :face     'consult-buffer
		  :history  'buffer-name-history
		  :state    #'consult--buffer-state
		  :new
		  (lambda (name)
			(with-current-buffer (get-buffer-create name)
			  (insert "#+title: " name "\n\n")
			  (org-mode)
			  (consult--buffer-action (current-buffer))))
		  :items
		  (lambda ()
			(mapcar #'buffer-name
					(seq-filter
					 (lambda (x)
					   (eq (buffer-local-value 'major-mode x) 'org-mode))
					 (buffer-list))))))
  (defvar consult--source-vterm
	(list :name     "Term"
		  :category 'buffer
		  :narrow   ?v
		  :face     'consult-buffer
		  :history  'buffer-name-history
		  :state    #'consult--buffer-state
		  :new
		  (lambda (name)
			(vterm (concat "shell: " name))
			(setq-local vterm-buffer-name-string nil))
		  :items
		  (lambda () (consult--buffer-query
					  :sort 'visibility
					  :as #'buffer-name
					  :include '("shell\\:\\ " "shell")))))
  (defun consult-term ()
	(interactive)
	(consult-buffer '(consult--source-vterm)))
  (defvar consult--source-star
	(list :name     "*Star-Buffers*"
		  :category 'buffer
		  :narrow   ?s
		  :face     'consult-buffer
		  :history  'buffer-name-history
		  :state    #'consult--buffer-state
		  :items
		  (lambda () (consult--buffer-query :sort 'visibility
											:as #'buffer-name
											:include '("\\*." "^magit")))))
  ;; remove org and vterm buffers from buffer list
  (setq consult--source-buffer
		(plist-put
		 consult--source-buffer :items
		 (lambda () (consult--buffer-query
					 :sort 'visibility
					 :as #'buffer-name
					 :exclude '("\\*."           ; star buffers
								"\\#."
								"shell"
								"shell\\:\\ "        ; Term buffers
								"^magit"         ; magit buffers
								"[\\.]org$"))))) ; org files

  (setq consult--source-project-buffer
		(plist-put
		 consult--source-project-buffer :items
		 (lambda ()
		   (consult--buffer-query
			:sort 'visibility
			:as #'buffer-name
			:exclude '("\\*."           ; star buffers
					   "Term\\ "        ; Term buffers
					   "^magit"          ; magit buffers
					   "^type-break.el"
					   "\#\!*")))))
  ;; reorder, mainly to move recent-file down and  org
  (setq consult-buffer-sources
		'(consult--source-hidden-buffer
		  consult--source-modified-buffer
		  consult--source-buffer
		  consult--source-org
		  consult--source-vterm
		  consult--source-bookmark
		  consult--source-recent-file
		  consult--source-file-register
		  consult--source-project-buffer-hidden
		  consult--source-project-recent-file-hidden
		  consult--source-star))
  (setq consult-project-buffer-sources
		'(consult--source-project-buffer
		  consult--source-vc-modified-file
		  consult--source-vterm
		  consult--source-project-recent-file
		  consult--source-star)))

consult web

 (use-package consult-web
	:ensure (:host github :repo "armindarvish/consult-web")
	:after consult
	:custom
	(consult-web-show-preview t) ;;; show previews
	(consult-web-preview-key "C-o") ;;; set the preview key to C-o
	(consult-web-highlight-matches t) ;;; highlight matches in minibuffer
	(consult-web-default-count 5) ;;; set default count
	(consult-web-default-page 0) ;;; set the default page (default is 0 for the first page)
	(consult-web-dynamic-input-debounce 0.8)
	(consult-web-dynamic-input-throttle 1.6)
	(consult-web-dynamic-refresh-delay 0.8)
	:config
	;; Add sources and configure them
	;;; load the example sources provided by default
	(require 'consult-web-sources)

	;;; set multiple sources for consult-web-multi command. Change these lists as needed for different interactive commands. Keep in mind that each source has to be a key in `consult-web-sources-alist'.
	(setq consult-web-multi-sources '("Wikipedia" "chatGPT" "Google")) ;; consult-web-multi
	(setq consult-web-dynamic-sources '("gptel" "StackOverFlow" )) ;; consult-web-dynamic
	(setq consult-web-scholar-sources '("PubMed")) ;; consult-web-scholar
	(setq consult-web-omni-sources (list "elfeed" "Wikipedia" "gptel" "YouTube" 'consult-buffer-sources 'consult-notes-all-sources)) ;;consult-web-omni
	(setq consult-web-dynamic-omni-sources (list "Known Project" "File" "Bookmark" "Buffer" "Reference Roam Nodes" "Zettel Roam Nodes" "Line Multi" "elfeed" "Wikipedia" "gptel" "Youtube")) ;;consult-web-dynamic-omni

	;; Per source customization
	;;; Pick you favorite autosuggest command.
	;; (setq consult-web-default-autosuggest-command #'consult-web-dynamic-brave-autosuggest) ;;or any other autosuggest source you define

	;;; Set API KEYs. It is recommended to use a function that returns the string for better security.
	;; (setq consult-web-google-customsearch-key "YOUR-GOOGLE-API-KEY-OR-FUNCTION")
	;; (setq consult-web-google-customsearch-cx "YOUR-GOOGLE-CX-NUMBER-OR-FUNCTION")
	;; (setq consult-web-stackexchange-api-key "YOUR-STACKEXCHANGE-API-KEY-OR-FUNCTION")
	;; (setq consult-web-pubmed-api-key "YOUR-PUBMED-API-KEY-OR-FUNCTION")
	;; (setq consult-web-openai-api-key "YOUR-OPENAI-API-KEY-OR-FUNCTION")
	;;; add more keys as needed here.
	)

Embark

Do thing with thing at point in minbuffer or regular buffer. read their readme to actually understand.

(use-package embark
  :bind
  ("M-SPC SPC" . embark-act)
  ("C-;" . embark-dwim)
  ("C-h B" . embark-bindings)
  (:map minibuffer-mode-map
		("M-SPC" . embark-act))
  (:map embark-region-map
		("w" . google-this)
		("g" . gptel))
  :custom
  (embark-mixed-indicator-delay 0.6)
  (prefix-help-command #'embark-prefix-help-command)
  (embark-indicators ; the default 
   '(embark-mixed-indicator
	 embark-highlight-indicator
	 embark-isearch-highlight-indicator)))
(use-package embark-consult
  :hook (embark-collect-mode . consult-preview-at-point-mode))

Project

(use-package project
  :ensure nil
  :bind-keymap ("C-c p". project-prefix-map))

Protogg

Don’t like the congestive overhead of thinking of if I want the project variant.

(use-package protogg 
  :ensure (:host github :repo "nehrbash/protogg")
  :custom (protogg-minibuffer-toggle-key "M-g")
  :bind (("M-SPC c" . protogg-compile)
		 ([remap dired] . protogg-dired) ;; C-x d
		 ("C-c e" . protogg-eshell)
		 ("M-s d" . protogg-find-dired)
		 ([remap find-file] . protogg-find-file) ;; C-x C-f
		 ([remap list-buffers] . protogg-list-buffers) ;; type C-x C-b
		 ;; note these are not interactive so they won't toggle.
		 ([remap async-shell-command] . protogg-async-shell-command) ;; M-&
		 ([remap shell-command] . protogg-shell-command) ;; M-!
		 ([remap switch-to-buffer] . sn/consult-buffer)
		 ("M-s i" . sn/imenu))
  :config
  (protogg-define 'consult-project-buffer 'consult-buffer sn/consult-buffer)
  (protogg-define 'consult-imenu-multi 'consult-imenu sn/imenu))

Corfu

Corfu is responsible for displaying the completion list. I use overlay for text buffers and dropdown list for programming. To show candidate overlays it is no longer mandatory to utilize ‘corfu-candidate-overlay’, instead the build-in preview mode will work just fine.

(use-package corfu
  :after orderless
  :hook (((prog-mode conf-mode yaml-mode) . sn/corfu-basic))
  :bind (:map corfu-map ("M-SPC" . corfu-insert-separator)
		  ("TAB" . corfu-next)
		  ([tab] . corfu-next)
		  ("S-TAB" . corfu-previous)
		  ([backtab] . corfu-previous))
  :custom
  (corfu-cycle t)
  (corfu-preselect 'prompt) ;; Always preselect the prompt
  ;; default/writting settings, see sn/corfu-basic for coding completion
  (tab-first-completion t)
  (tab-always-indent 'complete)
  (corfu-auto-delay 0.8)
  (corfu-popupinfo-delay 0.2)
  (corfu-quit-no-match 'separator)
  (corfu-auto-prefix 2)
  (completion-cycle-threshold nil)
  :init
  (global-corfu-mode t)
  (global-completion-preview-mode t)
  :config
  (defun orderless-fast-dispatch (word index total)
	(and (= index 0) (= total 1) (length< word 4)
	  `(orderless-regexp . ,(concat "^" (regexp-quote word)))))
  (orderless-define-completion-style orderless-fast
	"A basic completion suitable for coding."
	(orderless-style-dispatchers '(orderless-fast-dispatch))
	(orderless-matching-styles '(orderless-literal orderless-regexp)))
  (defun sn/corfu-basic ()
	"Setup completion for programming"
	(setq-local
	  corfu-auto t
	  corfu-auto-delay 0
	  corfu-quit-no-match t
	  completion-styles '(orderless-fast basic)
	  corfu-popupinfo-delay .8))
  (corfu-popupinfo-mode t)
  (defun corfu-move-to-minibuffer ()
	"For long canadate lists view in minibuffer"
	(interactive)
	(pcase completion-in-region--data
      (`(,beg ,end ,table ,pred ,extras)
		(let ((completion-extra-properties extras)
			   completion-cycle-threshold completion-cycling)
		  (consult-completion-in-region beg end table pred)))))
  (keymap-set corfu-map "M-m" #'corfu-move-to-minibuffer)
  (add-to-list 'corfu-continue-commands #'corfu-move-to-minibuffer))

More terminal support

Enable if ever

(use-package corfu-terminal
  :after corfu
  :ensure (:host codeberg :repo "akib/emacs-corfu-terminal"))

Icons for list

(use-package kind-icon
  :after corfu
  :custom ((kind-icon-default-face 'corfu-default))
  :config
  (plist-put kind-icon-default-style :height 0.9)
  (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))

cape - Completion At Point Extensions

built-in hippie-exp and dabbrev is pretty good substitute if cape doesn’t float your boat. it tries many diffrent functions.

(use-package cape
  :bind
  ("M-/" . completion-at-point) ;; overwrite dabbrev-completion binding with capf
  ("C-c /" . sn/cape)
  :custom (dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'"))
  :config
  (defun cape-tabnine ()
	(interactive)
	(cape-capf-interactive #'tabnine-completion-at-point))
  (transient-define-prefix sn/cape ()
	"explicit Completion type"
	[[
	  ("d" "Dabbrev" cape-dabbrev)
	  ("s" "Spelling" cape-dict)
	  ("k" "Keyword" cape-keyword)
	  ("l" "Line" cape-line)]
	 [
	  ("f" "File" cape-file)
	  ("h" "History" cape-history)
	  ("a" "Abbrev" cape-abbrev)
	  ("q" "Quit" transient-quit-one)]
	 [
	  ("e" "Elisp Symbol" cape-elisp-symbol)
	  ("E" "Elisp Block" cape-elisp-block)
	  ("t" "Tags" complete-tag)
	  ("c" "tabnine" cape-tabnine)
	  ]])
  :init
  (add-to-list 'completion-at-point-functions #'cape-dict)
  (add-to-list 'completion-at-point-functions #'cape-dabbrev)
  (add-to-list 'completion-at-point-functions #'cape-file)
  (add-to-list 'completion-at-point-functions #'cape-abbrev))

Snippets

yasnippet

(use-package yasnippet
  :hook ((text-mode
		  prog-mode
		  conf-mode) . yas-minor-mode-on)
  :bind ("C-c s" . yas-insert-snippet)
  :custom
  (yas-verbosity 1)
  (yas-snippet-dir "~/.emacs.d/snippets")
  (yas-wrap-around-region t))
(use-package yasnippet-snippets
  :after yasnippet)
(use-package yasnippet-capf
  :after yasnippet) 

Spelling

Using flyspell-correct as it uses completing-read by default so that it uses consult for it’s completion Flask QWERTY Xylophone Blizzard Trqvel

(use-package jinx
  :after vertico
  :bind
  (:map jinx-overlay-map
		("C-M-$" . #'jinx-correct-all))
  :init
  (global-jinx-mode t)
  :config
  (add-to-list 'vertico-multiform-categories
			   '(jinx grid (vertico-grid-annotate . 30)))
  (defun jinx-save-corrected-word ()
	"Save corrected word to a file."
	(interactive)
	  (let ((current-word (thing-at-point 'word t)))
		(with-temp-buffer
		  (insert current-word)
		  (insert "\n")
		  (append-to-file (point-min) (point-max) (concat user-emacs-directory "jinx_corrections")))))
  (advice-add 'jinx-correct :after #'jinx-save-corrected-word))

Define word

(use-package define-word
  :commands (define-word)
  :bind ("M-s D" . define-word-at-point))

This config block sets up the define-word package and flyspell-correct package in Emacs. The define-word package provides a command for looking up definitions of words, while the flyspell-correct package adds a keybinding to correct spelling mistakes when using flyspell mode.

Dired

Built in.

(use-package dired
  :ensure nil
  :hook (dired-mode . (lambda ()
  						(dired-omit-mode 1)
  						(dired-hide-details-mode 1)
  						(toggle-mode-line)
  						(hl-line-mode 1)))
  :custom
  ((dired-mouse-drag-files t)
	(dired-omit-files "^\\.\\.?$")
	(dired-listing-switches "-agho --group-directories-first")
	(dired-omit-verbose nil)
	(dired-recursive-deletes 'top)
	(dired-dwim-target t)))
(use-package dired-single
  :ensure (:host github :repo "emacsattic/dired-single")
  :after dired
  :bind (:map dired-mode-map
  		  ("b" . dired-single-up-directory) ;; alternative would be ("f" . dired-find-alternate-file)
  		  ("f" . dired-single-buffer)))
(use-package dired-ranger
  :after dired
  :bind (:map dired-mode-map
  		  ("w" . dired-ranger-copy)
  		  ("m" . dired-ranger-move)
  		  ("H" . dired-omit-mode)
  		  ("y" . dired-ranger-paste)))
(use-package all-the-icons)
(use-package dired-subtree 
  :after dired
  :bind (:map dired-mode-map
		  ("<tab>" . dired-subtree-toggle)
		  ("<backtab>" . dired-subtree-cycle)))

(use-package all-the-icons-dired
  :after dired
  :hook (dired-mode . all-the-icons-dired-mode))
(use-package dired-collapse
  :after dired
  :hook  (dired-mode . dired-collapse-mode))
(use-package diredfl
  :after dired
  :hook (dired-mode . diredfl-mode))
(use-package dired-hide-dotfiles
  :after dired
  :hook (dired-mode . dired-hide-dotfiles-mode)
  :bind (:map dired-mode-map
  		  ("." . dired-hide-dotfiles-mode)))

Consult Directories

(use-package consult-dir
  :after consult
  :bind
  ("C-x C-d" . consult-dir)
  (:map vertico-map
		("C-x C-d" . consult-dir)
		("C-x C-j" . consult-dir-jump-file))
  :config
  (add-to-list 'consult-dir-sources 'consult-dir--source-tramp-ssh t)
  (defun consult-dir--tramp-docker-hosts ()
	"Get a list of hosts from docker."
	(when (require 'docker-tramp nil t)
	  (let ((hosts)
			(docker-tramp-use-names t))
		(dolist (cand (docker-tramp--parse-running-containers))
		  (let ((user (unless (string-empty-p (car cand))
						(concat (car cand) "@")))
				(host (car (cdr cand))))
			(push (concat "/docker:" user host ":/") hosts)))
		hosts)))
  (defvar consult-dir--source-tramp-docker
	`(:name     "Docker"
				:narrow   ?d
				:category file
				:face     consult-file
				:history  file-name-history
				:items    ,#'consult-dir--tramp-docker-hosts)
	"Docker candiadate source for `consult-dir'.")
  (add-to-list 'consult-dir-sources 'consult-dir--source-tramp-docker t))

Org Mode

Text based writing.

General Configure

(use-package org-contrib
  :after org)
(use-package org
  :ensure nil
  :demand t
  :bind
  ("C-c a" .  gtd)
  ("C-c c" . org-capture)
  (:map org-mode-map
		( "C-M-<up>" . org-up-element)
		("C-c v" . wr-mode))
  :hook
  (org-mode . wr-mode)
  (org-mode . (lambda ()
				(add-hook 'after-save-hook #'sn/org-babel-tangle-dont-ask
						  'run-at-end 'only-in-org-mode)))
  :custom
  (org-todo-keywords
   (quote ((sequence "TODO(t)" "NEXT(n/!)" "INPROGRESS(i/!)" "|" "DONE(d!/!)")
		   (sequence "PROJECT(p)" "|" "DONE(d!/!)" "CANCELLED(c@/!)")
		   (sequence "WAITING(w@/!)" "DELEGATED(e!)" "HOLD(h)" "|" "CANCELLED(c@/!)")))
   org-todo-repeat-to-state "NEXT")
  (org-todo-keyword-faces
   (quote (("NEXT" :inherit warning)
		   ("PROJECT" :inherit font-lock-string-face))))
  (org-adapt-indentation t)
  (org-clock-resolve-expert t)
  (org-auto-align-tags nil)
  (org-edit-src-content-indentation 0)
  (org-edit-timestamp-down-means-later t)
  (org-ellipsis "")
  (org-fast-tag-selection-single-key 'expert)
  (org-hide-emphasis-markers t)
  (org-image-actual-width nil)
  (org-insert-heading-respect-content t)
  (org-log-done 'time)
  (org-pretty-entities t)
  (org-return-follows-link  t)
  (org-special-ctrl-a/e t)
  (org-src-fontify-natively t)
  (org-catch-invisible-edits 'show-and-error)
  (org-src-tab-acts-natively t)
  (org-src-ask-before-returning-to-edit-buffer nil)
  (org-startup-folded t)
  (org-startup-with-inline-images t)
  (org-tags-column 0)
  ;; TODO(SN): https://github.com/karthink/org-auctex
  (org-startup-with-latex-preview nil);; wait for the async rendering to be merged
  (org-support-shift-select t)
  (org-archive-location "%s_archive::* Archive")
  (org-latex-pdf-process '("latexmk -pdflatex='lualatex -shell-escape -interaction nonstopmode' -pdf -outdir=~/.cache/emacs %f"))
  (org-directory "~/doc")
  (org-default-notes-file (concat org-directory "/notes.org"))
  (org-agenda-files
   (cl-remove-if-not #'file-exists-p
					 '("~/doc/inbox.org"
					   "~/doc/projects.org"
					   "~/doc/gcal.org"
					   "~/doc/repeater.org")))
  (org-capture-templates
   `(("t" "Tasks")
	 ("tt" "Todo" entry (file+headline "~/doc/inbox.org" "Inbox")
	  "* TODO %?\nOn %U\While Editing %a\n" :clock-keep t)
	 ("ti" "Inprogress" entry (file+headline "~/doc/inbox.org" "Inprogress")
	  "* INPROGRESS %?\nSCHEDULED: %t\nOn %U\While Editing %a\n" :clock-keep t :clock-in t)
	 ("p" "New Project")
	 ("pp" "Personal Project" entry (file+headline "~/doc/projects.org" "Things I Want Done")
	  "* PROJECT %?\n" :clock-keep t)
	 ("pP" "Personal Project (clock-in)" entry (file+headline "~/doc/projects.org" "Things I Want Done")
	  "* PROJECT %?\n" :clock-keep t :clock-in t)
	 ("pw" "Work Project" entry (file+headline "~/doc/projects.org" "Work")
	  "* PROJECT %?\n" :clock-keep t)
	 ("pW" "Work Project (clock-in)" entry (file+headline "~/doc/projects.org" "Work")
	  "* PROJECT %?\n" :clock-keep t :clock-in t)
	 ("c" "Current task" checkitem (clock))
	 ("r" "Roam")
	 ("rt" "Go to today's daily note" entry (function (lambda ()
														(org-roam-dailies-goto-today)
														(org-capture-finalize))))
	 ("rf" "Find or create an Org-roam node" entry (function (lambda ()
															   (org-roam-node-find)
															   (org-capture-finalize))))
	 ("rv" "Open Roam UI in browser" entry (function (lambda ()
													   (org-roam-ui-open)
													   (org-capture-finalize))))))
  :config
  (defun sn/org-babel-tangle-dont-ask ()
	"Tangle Org file without asking for confirmation."
	(let ((org-confirm-babel-evaluate nil))
	  (org-babel-tangle)))
  (org-babel-do-load-languages
   'org-babel-load-languages
   `((dot . t)
	 (emacs-lisp . t)
	 (gnuplot . t)
	 (latex . t)
	 (python . t)
	 (,(if (locate-library "ob-sh") 'sh 'shell) . t)
	 (sql . t)
	 (sqlite . t)))
  (defun sn/org-clock-in-if-inprogress ()
	"Clock in when the task state is changed to INPROGRESS."
	(when (string= org-state "INPROGRESS")
	  (org-clock-in)))
  (add-hook 'org-after-todo-state-change-hook 'sn/org-clock-in-if-inprogress)
  :init
  (define-minor-mode wr-mode
	"Set up a buffer for word editing.
   This enables or modifies a number of settings so that the
   experience of word processing is a little more like that of a
   typical word processor."
	:interactive t " Writing" nil
	(if wr-mode
		(progn
		  (setq 
				word-wrap t
				cursor-type 'bar)
		  (when (eq major-mode 'org)
			(kill-local-variable 'buffer-face-mode-face))
		  (buffer-face-mode 1)
		  (setq-local
		   blink-cursor-interval 0.8
		   show-trailing-whitespace nil
		   line-spacing 0.2
		   electric-pair-mode nil)
		  (olivetti-mode 1)
		  (visual-line-mode 1)
		  (variable-pitch-mode 1))

	  (kill-local-variable 'word-wrap)
	  (kill-local-variable 'cursor-type)
	  (kill-local-variable 'blink-cursor-interval)
	  (kill-local-variable 'show-trailing-whitespace)
	  (kill-local-variable 'line-spacing)
	  (kill-local-variable 'electric-pair-mode)
	  (buffer-face-mode -1)
	  (visual-line-mode -1)
	  (olivetti-mode -1)
	  (variable-pitch-mode -1))))

Mermaid

(use-package ob-mermaid
  :after org
  :ensure-system-package (mmdc . "paru -S --needed --noconfirm mermaid-cli")
  :config
  (add-to-list 'org-babel-load-languages '(mermaid . t)))

Window capture

(defun gtd () (interactive)
		 (progn
		   (org-resolve-clocks)
		   (org-agenda 'nil "g")))
(defun sn/org-capture-frame ()
  "Run org-capture in its own frame."
  (interactive)
  (require 'cl-lib)
  (select-frame-by-name "capture")
  (delete-other-windows)
  (cl-letf (((symbol-function 'switch-to-buffer-other-window) #'switch-to-buffer))
    (condition-case err
        (org-capture)
      ;; "q" signals (error "Abort") in `org-capture'
      ;; delete the newly created frame in this scenario.
      (user-error (when (string= (cadr err) "Abort")
                    (delete-frame))))))
(add-hook 'org-capture-mode-hook 'toggle-mode-line)

UI Packages

Modern Style

To remove a lot of smaller packages ad adopt a lager all in one package

(use-package org-modern
  :init
  (global-org-modern-mode t))

Org Appear

Provides a way to toggle visibility of hidden elements such as emphasis markers, links, etc. by customizing specific variables.

(use-package org-appear
  :ensure (:host github :repo "awth13/org-appear")
  :hook (org-mode . org-appear-mode))

Latex Fragments

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

Clock In/Out

Pads visited in Org-mode are opened in Evince (and other file extensions are handled according to the defaults)

(use-package org-clock
  :ensure nil  ;; built in
  :bind 
  (("C-o" . org-clock-map))
  :config
  (defvar org-clock-map (make-sparse-keymap)
    "Keymap for org-clock commands.")

  (define-key org-clock-map (kbd "j") 'org-clock-goto)
  (define-key org-clock-map (kbd "l") 'org-clock-in-last)
  (define-key org-clock-map (kbd "i") 'org-clock-in)
  (define-key org-clock-map (kbd "o") 'org-clock-out)
  :hook
  (org-clock-in . type-break-mode)
  (org-clock-out . (lambda () (type-break-mode -1)))
  (org-clock-in . (lambda () (org-todo "INPROGRESS")
  					(org-save-all-org-buffers)))
  (org-clock-out . (lambda ()
  					 (unless (string-equal (org-get-todo-state) "DONE")
  					   (org-todo "NEXT")
  					   (setq org-clock-heading "")
  					   (org-save-all-org-buffers))))
  :init
  (org-clock-persistence-insinuate)
  :custom
  (org-clock-in-resume t)
  (org-clock-persist t)
  ;; Save clock data and notes in the LOGBOOK drawer
  (org-clock-into-drawer t)
  ;; Save state changes in the LOGBOOK drawer
  (org-log-into-drawer t)
  ;; Removes clocked tasks with 0:00 duration
  (org-clock-out-remove-zero-time-clocks t)
  ;; dont' show clock in bar because we use system bar
  (org-clock-clocked-in-display nil)
  ;; Enable auto clock resolution for finding open clocks
  (org-clock-auto-clock-resolution (quote when-no-clock-is-running))
  ;; Include current clocking task in clock reports
  (org-clock-report-include-clocking-task t)
  ;; use pretty things for the clocktable
  (org-pretty-entities t)
  (org-clock-persist 'history))

Type Breaks

I like type break more then pomodoro session.

 (use-package type-break
	:ensure nil
	:custom
	(org-clock-ask-before-exiting nil)
	(type-break-interval (* 25 60)) ;; 25 mins
	(type-break-good-rest-interval (* 5 60)) ;; 5 mins
	(type-break-good-break-interval (* 5 60)) ;; 5 mins
	(type-break-keystroke-threshold '(nil . 3000)) ;; 500 words is 3,000
	(type-break-demo-boring-stats t)
	(type-break-file-name nil) ;; don't save across sessions file is annoying
	(type-break-query-mode t)
	(type-break-warning-repeat nil)
	;; This will stop the warnings before it's time to take a break
	(type-break-time-warning-intervals '())
	(type-break-keystroke-warning-intervals '())
	(type-break-query-function 'sn/type-break-query)
	(type-break-mode-line-message-mode nil)
	(type-break-demo-functions '(type-break-demo-boring))
	:init
	(defun sn/org-mark-current-done ()
	  "Clock out of the current task and mark it as DONE."
	  (interactive)
	  (let ((org-clock-out-switch-to-state "DONE"))
		(org-clock-out)
		(setq org-clock-heading "")
		(org-save-all-org-buffers)))
	(defun sn/type-break-toggle ()
	  (interactive)
	  (if type-break-mode
		  (type-break-mode -1)
		(type-break-mode 1)))
	(defun sn/type-break-query (a &rest b)
	  "Auto say yes and ask to quit type break."
	  (if (>= (type-break-time-difference
								   type-break-interval-start
								   type-break-time-last-break) 0)
		  (y-or-n-p "Do you want to continue type-break? ")
		t))
	(defun org-clock-in-to-task-by-title (task-title)
	  "Clock into an Org Agenda task by its title within a custom agenda command."
	  (interactive "sEnter the title of the task: ")
	  (save-window-excursion
		(org-agenda nil "t")
		(with-current-buffer "*Org Agenda(t)*"
		  (goto-char (point-min))
		  (if (search-forward task-title nil t)
			  (progn
				(org-agenda-goto)
				(org-clock-in))
			(message "Task with title \"%s\" not found in the custom agenda view." task-title)))))
	(defun format-seconds-to-mm-ss (seconds)
	  "Formats time to MM:SS."
	  (let* ((minutes (floor (/ seconds 60)))
			 (remaining-seconds (- seconds (* minutes 60))))
		(format "%02d:%02d" minutes remaining-seconds)))
	(defun type-break-json-data ()
	  "Prints type break data used in eww bar."
	  (let* ((time-difference  (when type-break-mode (type-break-time-difference nil type-break-time-next-break)))
			 (formatted-time (if time-difference (format-seconds-to-mm-ss time-difference)
							   "00:00"))
			 (percent (if type-break-mode
						  (number-to-string (/ (* 100.0 time-difference)
											   type-break-interval))
						"0"))
			 (json-data `(:percent ,percent
								   :time ,formatted-time
								   :task ,(if (string-empty-p org-clock-heading)
											  "No Active Task"
											org-clock-heading)
								   :summary ,(concat (if (or (not org-clock-heading) (string= org-clock-heading ""))
														 "No Active Task"
													   org-clock-heading)
													 " " formatted-time)
								   :keystroke ,(if type-break-mode (cdr type-break-keystroke-threshold) "none")
								   :keystroke-count ,(if type-break-mode type-break-keystroke-count 0))))
		(json-encode json-data))))

Auto Save PDF Toggle

(defun toggle-org-pdf-export-on-save ()
  (interactive)
  (if (memq 'org-latex-export-to-pdf after-save-hook)
	  (progn
		(remove-hook 'after-save-hook 'org-latex-export-to-pdf t)
		(message "Disabled org pdf export on save for current buffer..."))
	(add-hook 'after-save-hook 'org-latex-export-to-pdf nil t)
	(message "Enabled org export on save for current buffer...")))

(defun toggle-org-html-export-on-save ()
  (interactive)
  (if (memq 'org-html-export-to-html after-save-hook)
	  (progn
		(remove-hook 'after-save-hook 'org-html-export-to-html t)
		(message "Disabled org html export on save for current buffer..."))
	(add-hook 'after-save-hook 'org-html-export-to-html nil t)
	(message "Enabled org html export on save for current buffer...")))

Agenda

(use-package org-agenda
  :ensure nil
  :hook (org-agenda-mode . hl-line-mode)
  :custom
  (org-agenda-prefix-format "%i  %?-2 t%s")
  (org-agenda-tags-column 0)
  (org-agenda-block-separator ?─)
  (org-agenda-category-icon-alist
   `(
	 ("work" "~/.dotfiles/icons/work.svg" nil nil :ascent center :mask heuristic)
	 ("music" "~/.dotfiles/icons/music.svg" nil nil :ascent center :mask heuristic)
	 ("chore" "~/.dotfiles/icons/chore.svg" nil nil :ascent center :mask heuristic)
	 ("events" "~/.dotfiles/icons/events.svg" nil nil :ascent center :mask heuristic)
	 ("inbox" "~/.dotfiles/icons/inbox.svg" nil nil :ascent center :mask heuristic)
	 ("walk" "~/.dotfiles/icons/walk.svg" nil nil :ascent center :mask heuristic)
	 ("solution" "~/.dotfiles/icons/solution.svg" nil nil :ascent center :mask heuristic)
	 ("community" "~/.dotfiles/icons/community.svg" nil nil :ascent center :mask heuristic)
	 ("idea" "~/.dotfiles/icons/idea.svg" nil nil :ascent center :mask heuristic)
	 ("personal" "~/.dotfiles/icons/man.svg" nil nil :ascent center :mask heuristic)
	 ("scheduled" "~/.dotfiles/icons/scheduled.svg" nil nil :ascent center :mask heuristic)
	 ("class" "~/.dotfiles/icons/class.svg" nil nil :ascent center :mask heuristic)
	 ("plant" "~/.dotfiles/icons/plant.svg" nil nil :ascent center :mask heuristic)
	 ("check" "~/.dotfiles/icons/check.svg" nil nil :ascent center :mask heuristic)
	 ("search" "~/.dotfiles/icons/search.svg" nil nil :ascent center :mask heuristic)
	 ("home" "~/.dotfiles/icons/home.svg" nil nil :ascent center :mask heuristic)
	 ("book" "~/.dotfiles/icons/book.svg" nil nil :ascent center :mask heuristic)
	 ("cook" "~/.dotfiles/icons/cook.svg" nil nil :ascent center :mask heuristic)
	 ("buy" "~/.dotfiles/icons/buy.svg" nil nil :ascent center :mask heuristic)
	 ("shower" "~/.dotfiles/icons/shower.svg" nil nil :ascent center :mask heuristic)
	 ("archive" "~/.dotfiles/icons/archive.svg" nil nil :ascent center :mask heuristic)))
  :config
  (setq-default org-agenda-clockreport-parameter-plist '(:link t :maxlevel 3))
  ;; Set active-project-match
  (let ((active-project-match "-INBOX/PROJECT"))
	(setq org-stuck-projects `(,active-project-match ("NEXT" "INPROGRESS"))
  		  org-agenda-compact-blocks t
  		  org-agenda-sticky t
  		  org-agenda-start-on-weekday nil
  		  org-agenda-span 'day
  		  org-agenda-include-diary nil
  		  org-agenda-use-time-grid nil
  		  org-agenda-window-setup 'current-window
  		  org-agenda-sorting-strategy
  		  '((agenda habit-down time-up user-defined-up effort-up category-keep)
  			(todo category-up effort-up)
  			(tags category-up effort-up)
  			(search category-up)))
	(setq org-agenda-custom-commands
  		  `(("g" "GTD"
  			 ((agenda "" nil)
  			  (tags "INBOX"
  					((org-agenda-overriding-header "Inbox")
  					 (org-tags-match-list-sublevels nil)
  					 (org-agenda-skip-function
  					  '(lambda ()
  						 (org-agenda-skip-entry-if 'nottodo '("TODO" "DONE" "CANCELLED"))))))
			  (tags-todo ,active-project-match
  						 ((org-agenda-overriding-header "Projects")
  						  (org-tags-match-list-sublevels t)
  						  (org-agenda-sorting-strategy
  						   '(category-keep))))
			  (tags-todo "-INBOX"
  						 ((org-agenda-overriding-header "Next Actions")
  						  (org-agenda-tags-todo-honor-ignore-options t)
  						  (org-agenda-todo-ignore-scheduled 'future)
  						  (org-agenda-skip-function
  						   '(lambda ()
  							  (or (org-agenda-skip-subtree-if 'todo '("HOLD" "WAITING"))
  								  (org-agenda-skip-entry-if 'nottodo '("NEXT" "INPROGRESS")))))
  						  (org-tags-match-list-sublevels t)
  						  (org-agenda-sorting-strategy '(todo-state-down effort-up category-keep))))
  			  (stuck nil
  					 ((org-agenda-overriding-header "Stuck Projects")
  					  (org-agenda-tags-todo-honor-ignore-options t)
  					  (org-tags-match-list-sublevels t)
  					  (org-agenda-todo-ignore-scheduled 'future)))
  			  (tags-todo "-INBOX-repeater"
  						 ((org-agenda-overriding-header "Orphaned Tasks")
  						  (org-agenda-tags-todo-honor-ignore-options t)
  						  (org-agenda-todo-ignore-scheduled 'future)
  						  (org-agenda-skip-function
  						   '(lambda ()
  							  (or (org-agenda-skip-subtree-if 'todo '("PROJECT" "HOLD" "WAITING" "DELEGATED"))
  								  (org-agenda-skip-subtree-if 'nottodo '("TODO")))))
  						  (org-tags-match-list-sublevels t)
  						  (org-agenda-sorting-strategy '(category-keep))))
  			  (tags-todo "/WAITING"
  						 ((org-agenda-overriding-header "Waiting")
  						  (org-agenda-tags-todo-honor-ignore-options t)
  						  (org-agenda-todo-ignore-scheduled 'future)
  						  (org-agenda-sorting-strategy
  						   '(category-keep))))
  			  (tags-todo "/DELEGATED"
  						 ((org-agenda-overriding-header "Delegated")
  						  (org-agenda-tags-todo-honor-ignore-options t)
  						  (org-agenda-todo-ignore-scheduled 'future)
  						  (org-agenda-sorting-strategy '(category-keep))))
  			  (tags-todo "-INBOX"
  						 ((org-agenda-overriding-header "On Hold")
  						  (org-agenda-skip-function
  						   '(lambda ()
  							  (or (org-agenda-skip-subtree-if 'todo '("WAITING"))
  								  (org-agenda-skip-entry-if 'nottodo '("HOLD")))))
  						  (org-tags-match-list-sublevels nil)
  						  (org-agenda-sorting-strategy '(category-keep))))))))))

Task Settings

Refiling

;; Targets include this file and any file contributing to the agenda - up to 5 levels deep
(setq org-refile-targets '((nil :maxlevel . 5) (org-agenda-files :maxlevel . 5)))
(with-eval-after-load 'org-agenda
  (add-to-list 'org-agenda-after-show-hook 'org-show-entry))
(advice-add 'org-refile :after (lambda (&rest _) (org-save-all-org-buffers)))
;; Exclude DONE state tasks from refile targets
(defun sanityinc/verify-refile-target ()
  "Exclude todo keywords with a done state from refile targets."
  (not (member (nth 2 (org-heading-components)) org-done-keywords)))
(setq org-refile-target-verify-function 'sanityinc/verify-refile-target)
(defun sanityinc/org-refile-anywhere (&optional goto default-buffer rfloc msg)
  "A version of `org-refile' which allows refiling to any subtree."
  (interactive "P")
  (let ((org-refile-target-verify-function))
	(org-refile goto default-buffer rfloc msg)))
(defun sanityinc/org-agenda-refile-anywhere (&optional goto rfloc no-update)
  "A version of `org-agenda-refile' which allows refiling to any subtree."
  (interactive "P")
  (let ((org-refile-target-verify-function))
	(org-agenda-refile goto rfloc no-update)))

;; Targets start with the file name - allows creating level 1 tasks
;;(setq org-refile-use-outline-path (quote file))
(setq org-refile-use-outline-path t)
(setq org-outline-path-complete-in-steps nil)

;; Allow refile to create parent tasks with confirmation
(setq org-refile-allow-creating-parent-nodes 'confirm)

Google Calendar

Add my Gmail. Has secrets so don’t push.

(use-package org-gcal
  :config
  (defun load-gcal-credentials ()
	"Load Google Calendar credentials from a JSON file."
	(let* ((json-file "~/.gcal-emacs")
		   (json-data (json-read-file json-file)))
	  (setq plstore-cache-passphrase-for-symmetric-encryption t)
	  (setq org-gcal-client-id (cdr (assoc 'client-id json-data)))
	  (setq org-gcal-client-secret (cdr (assoc 'client-secret json-data)))
	  (setq org-gcal-fetch-file-alist `((,(cdr (assoc 'mail json-data)) .  "~/doc/gcal.org")))))
  (load-gcal-credentials)
  :bind (:map org-agenda-mode-map
			  ("M-g" . org-gcal-sync)))

example ~/.gcal-emacs

{
  "client-id": "foo.apps.googleusercontent.com",
  "client-secret": "my-secret",
  "mail": "foo.bar@gmail.com"
}

Table of Contents

It’s nice to have a table of contents section for long literate configuration files (like this one!) so I use toc-org to automatically update the TOC in any header with a property named TOC. Simply add a :TOC: tag to the header you want to be the table of contents. there are many TOC packages but I have found this one as it works in org files and rendered on Git-Lab. Note: This package can also be used for markdown but is not configured for it.

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

PDF Tools

Better PDF viewer, lots of cool stuff. make sure pdf-info-epdfinfo-program in path.

idk toggle-mode-line is not working for this mode but the timer work around forks fine

(use-package pdf-tools
  :defer 5
  :hook (pdf-tools-enabled . (lambda ()
						 (pdf-view-midnight-minor-mode 1)
						 (toggle-mode-line)))
  :custom
  (pdf-view-display-size 'fit-width)
  (pdf-view-midnight-colors '("#e8e4b1" . "#352718" ))
  :config
  (pdf-loader-install))

Multi Page Scroll

(use-package pdf-continuous-scroll-mode
  :after pdf-tools
  :custom
  (pdf-continuous-suppress-introduction t)
  :ensure (:host github :repo "dalanicolai/pdf-continuous-scroll-mode.el"))  

Org Roam

(use-package org-roam
  :init (setq-default org-roam-v2-ack t)
  :config (org-roam-db-autosync-mode)
  :custom
  (org-roam-directory "~/doc/Roam/")
  (org-roam-completion-everywhere t)
  (org-roam-completion-system 'default)
  (org-roam-dailies-directory "Journal/")
  (setq org-roam-dailies-capture-templates
	'(("d" "default" entry
		"* %?"
		:target (file+head "%<%Y-%m-%d>.org"
				  "#+title: %<%Y-%m-%d>\n"))))
  :bind (("C-c n f"   . org-roam-node-find)
		  ("C-c n d"   . org-roam-dailies-goto-date)
		  ("C-c n n"   . org-roam-buffer-display-dedicated)
		  ("C-c n c"   . org-roam-dailies-capture-today)
		  ("C-c n C" . org-roam-dailies-capture-tomorrow)
		  ("C-c n t"   . org-roam-dailies-goto-today)
		  ("C-c n y"   . org-roam-dailies-goto-yesterday)
		  ("C-c n r"   . org-roam-dailies-goto-tomorrow)
		  ("C-c n G"   . org-roam-graph)
		  :map org-mode-map
		  (("C-c n i" . org-roam-node-insert))))
(use-package consult-org-roam
  :bind ("C-c n g" . org-roam-node-find)
  :after org-roam)

Org Roam UI

Don’t really have a need to use yet

(use-package org-roam-ui
  :ensure (:host github :repo "org-roam/org-roam-ui")
  :after org-roam
  :custom
  (org-roam-ui-sync-theme t)
  (org-roam-ui-follow t)
  (org-roam-ui-update-on-save t)
  (org-roam-ui-open-on-start nil))

Code Languages & File Modes

General

(use-package hl-line
  :ensure nil ;; built-in
  :hook (prog-mode . hl-line-mode))

Auto indent comments past fill-column

(use-package simple
  :ensure nil ;; built-in
  :custom
  (comment-auto-fill-only-comments t)
  (idle-update-delay 0.1)
  :hook (prog-mode . auto-fill-mode))

Indent bars

Very faint indicator, tree-sitter based.

(use-package indent-bars
  :ensure (:host github :repo "jdtsmith/indent-bars")
  :hook ((prog-mode conf-mode yaml-mode) . indent-bars-mode)
  :custom
  (indent-bars-color '(highlight :face-bg t :blend 0.2))
  (indent-bars-pattern ".")
  (indent-bars-width-frac 0.3)
  (indent-bars-pad-frac 0.1))

HEX Colors

Show hex colors while coding or editing themes.

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

Tree sitter

Enable syntax highlighting based on the tree-sitter. already installed

(use-package treesit
  :ensure nil
  :mode ("\\.tsx\\'" . tsx-ts-mode)
  :preface
  (defun mp-setup-install-grammars ()
    "Install Tree-sitter grammars if they are absent."
    (interactive)
    (dolist (grammar
             ;; Note the version numbers. These are the versions that
             ;; are known to work with Combobulate *and* Emacs.
             '((css . ("https://github.com/tree-sitter/tree-sitter-css"))
               (go . ("https://github.com/tree-sitter/tree-sitter-go"))
			   (gomod . ("https://github.com/camdencheek/tree-sitter-go-mod"))
               (html . ("https://github.com/tree-sitter/tree-sitter-html"))
               (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript" "v0.20.1" "src"))
               (json . ("https://github.com/tree-sitter/tree-sitter-json"))
               (markdown . ("https://github.com/ikatyang/tree-sitter-markdown"))
               (python . ("https://github.com/tree-sitter/tree-sitter-python"))
               (rust . ("https://github.com/tree-sitter/tree-sitter-rust"))
               (toml . ("https://github.com/tree-sitter/tree-sitter-toml"))
               (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "v0.20.3" "tsx/src"))
               (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "v0.20.3" "typescript/src"))
               (yaml . ("https://github.com/ikatyang/tree-sitter-yaml" "v0.5.0"))
			   ))
      (add-to-list 'treesit-language-source-alist grammar)
      ;; Only install `grammar' if we don't already have it
      ;; installed. However, if you want to *update* a grammar then
      ;; this obviously prevents that from happening.
      (unless (treesit-language-available-p (car grammar))
        (treesit-install-language-grammar (car grammar)))))

  ;; Optional. Combobulate works in both xxxx-ts-modes and
  ;; non-ts-modes.

  ;; You can remap major modes with `major-mode-remap-alist'. Note
  ;; that this does *not* extend to hooks! Make sure you migrate them
  ;; also
  (dolist (mapping
           '((python-mode . python-ts-mode)
             (css-mode . css-ts-mode)
             (typescript-mode . typescript-ts-mode)
             (js2-mode . js-ts-mode)
             (bash-mode . bash-ts-mode)
             (conf-toml-mode . toml-ts-mode)
             (go-mode . go-ts-mode)
			 (go-mod-mode . go-mod-ts-mode)
             (css-mode . css-ts-mode)
             (json-mode . json-ts-mode)
             (js-json-mode . json-ts-mode)))
    (add-to-list 'major-mode-remap-alist mapping))
  :config
  (mp-setup-install-grammars)
  :custom
  (treesit-font-lock-level 4))

Combobulate

Treesitter movement

(use-package combobulate
  :ensure (:host github :repo "mickeynp/combobulate" :branch "development")
  :custom (combobulate-key-prefix "C-c j")
  :hook (prog-mode . combobulate-mode))

Eglot

(use-package eglot
  :ensure nil
  :hook
  ((go-ts-mode rust-ts-mode bash-ts-mode js-ts-mode terraform-mode) . eglot-ensure)
  (eglot-managed-mode . eglot-inlay-hints-mode)
  (eglot-managed-mode . sn/setup-eglot)
  (eglot-managed-mode . sn/eglot-eldoc)
  :preface
  (defun sn/eglot-eldoc ()
    (setq eldoc-documentation-strategy
      'eldoc-documentation-compose-eagerly))
  :bind
  (:map eglot-mode-map
	("C-h ." . eldoc-doc-buffer)
	("C-c r" . eglot-rename)
	("C-c t" . eglot-find-typeDefinition)
	("C-c i" . eglot-find-implementation)
	("C-c a" . eglot-code-actions)
	("C-c q" . eglot-code-action-quickfix)
	("C-c o" . eglot-code-action-organize-imports))
  :custom
  (eglot-report-progress nil)
  (eglot-autoshutdown t)
  (eglot-sync-connect nil)
  (eglot-events-buffer-config '(:size 0 :format full))
  :config
  (setq-default eglot-workspace-configuration
	'(:gopls
	   (:usePlaceholders t
		 :staticcheck t
		 :gofumpt t
		 :analyses (:nilness t
					 :unusedparams t
					 :unusedwrite t
					 :unusedvariable t)
		 :hints (:assignVariableTypes t
				  :constantValues t
				  :rangeVariableTypes t))
	   :js-ts
	   (:format
		 (:convertTabsToSpaces t
		   :indentSize 1
		   :tabSize 1
		   :tabWidth 1))))
  (defun eglot-rename (newname)
	"Rename the current symbol to NEWNAME."
	(interactive
	  (list (read-from-minibuffer
			  (format "Rename `%s' to: " (or (thing-at-point 'symbol t)
										   "unknown symbol"))
			  (thing-at-point 'symbol t) nil nil nil
			  (symbol-name (symbol-at-point)))))
	(eglot-server-capable-or-lose :renameProvider)
	(eglot--apply-workspace-edit
	  (eglot--request (eglot--current-server-or-lose)
		:textDocument/rename `(,@(eglot--TextDocumentPositionParams)
								:newName ,newname))
	  this-command))
  
  (advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
  (defun eglot-organize-imports ()
	(interactive)
	(eglot-code-actions nil nil "source.organizeImports" t))
  (defun sn/cape-in-string ()
	(cape-wrap-inside-string
	  (cape-capf-super
		#'cape-file
		#'cape-dabbrev
		#'cape-dict)))
  (defun sn/cape-in-comment ()
	(cape-wrap-inside-comment
	  (cape-capf-super
		#'cape-dabbrev
		#'cape-dict
		#'cape-file)))
  (defun sn/cape-in-code ()
	(cape-wrap-nonexclusive
	  (cape-capf-inside-code
		(cape-capf-super
		  #'eglot-completion-at-point
		  #'yasnippet-capf
		  #'cape-dabbrev))))
  (defun sn/cape-ai ()
	(cape-wrap-prefix-length
	  (cape-capf-accept-all #'codeium-completion-at-point) 2))
  (defun sn/setup-eglot ()
	"Eglot setup customizations"
	(add-hook 'before-save-hook #'eglot-format-buffer -10 'local)
	(add-hook 'before-save-hook #'eglot-organize-imports nil 'local)
	(setq-local
	  cape-dabbrev-min-length 3
	  completion-at-point-functions (list
									  #'sn/cape-in-code
									  #'sn/cape-in-string
									  #'sn/cape-in-comment
									  #'sn/cape-ai))))
(use-package consult-eglot
  :after eglot
  :bind
  (:map eglot-mode-map
	("C-c f" . consult-eglot-symbols)))

Prettify Documentation

eldoc resizing the message buffer is a little jarring. This box is nicer but does not dynamically get out of the way if the area overlaps with the area your typing

(use-package eldoc-box
  :hook (eglot-managed-mode . eldoc-box-hover-mode))  

Dape

(use-package dape
  :bind ("<F7>" . dape)
  ;; To use window configuration like gud (gdb-mi)
  :init
  (setq dape-buffer-window-arrangement 'gud)
  :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)o (add-hook 'dape-on-start-hooks
            (defun dape--save-on-start ()
              (save-some-buffers t t))))

Git

hook eglot so that not enabled in most buffers and lower priority (also don’t like it in text documents)

UI

(use-package git-gutter
  :config
  (global-git-gutter-mode t)
  :custom
  (git-gutter:ask-p nil)
  (git-gutter:update-interval 0.8))
(use-package git-gutter-fringe
  :after git-gutter
  :config
  (define-fringe-bitmap 'git-gutter-fr:added [224] nil nil '(center repeated))
  (define-fringe-bitmap 'git-gutter-fr:modified [224] nil nil '(center repeated))
  (define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240] nil nil 'bottom))
(use-package blamer
  :bind
  ("C-c C-i" . blamer-mode)
  ("C-c i" . blamer-show-posframe-commit-info)
  :custom
  (blamer-idle-time 0.2)
  (blamer-min-offset 70))

Magit

  • project-switch-project was added so that magit shows up as an action item.
(use-package magit
  :ensure nil
  :config
  (require 'magit-extras)
  (require 'transient)
  (require 'smerge-mode)
  (transient-define-prefix sn/smerge ()
	"Rebase Menu"
	[["Smerge nav/show"
	   ("n" "Next" smerge-next :transient t)
	   ("p" "Prev" smerge-prev :transient t)
	   ("h" "Highlight diff" smerge-refine :transient t)]
	  ["Quick Resolve"
		("a" "Keep All" smerge-keep-all :transient t)
		("u" "Keep Upper" smerge-keep-upper :transient t)
		("l" "Keep Lower" smerge-keep-lower :transient t)]]
	[["Resolve"
	   ("r" "Resolve Intelligently" smerge-resolve :transient t)
	   ("R" "Auto Resolve All" smerge-resolve-all :transient t)
	   ("e" "Resolve With Ediff" smerge-ediff)]
	  ["Actions"
		("q" "Quit" transient-quit-one)
		("s" "Magit Status" magit-status)
		("S" "git Logs" magit-pg-repo)]])
  :custom
  (magit-diff-refine-hunk t))
(use-package git-timemachine
  :custom (git-timemachine-show-minibuffer-details t))
Todos

hl-todo is problematic for elpaca.

(use-package hl-todo
  :ensure (hl-todo :depth nil)
  :init (global-hl-todo-mode t)
  :hook (ef-themes-post-load . my-ef-themes-hl-todo-faces)
  :config
  (defun my-ef-themes-hl-todo-faces ()
	"Configure `hl-todo-keyword-faces' with Ef themes colors.
The exact color values are taken from the active Ef theme."
	(ef-themes-with-colors
      (setq hl-todo-keyword-faces
			`(("HOLD" . ,yellow)
              ("TODO" . ,red)
              ("NEXT" . ,blue)
              ("THEM" . ,magenta)
              ("PROG" . ,cyan-warmer)
              ("OKAY" . ,green-warmer)
              ("DONT" . ,yellow-warmer)
              ("FAIL" . ,red-warmer)
              ("BUG" . ,red-warmer)
              ("DONE" . ,green)
              ("NOTE" . ,blue-warmer)
              ("KLUDGE" . ,cyan)
              ("HACK" . ,cyan)
              ("TEMP" . ,red)
              ("FIXME" . ,red-warmer)
              ("XXX+" . ,red-warmer)
              ("REVIEW" . ,red)
              ("DEPRECATED" . ,yellow)))))
  (my-ef-themes-hl-todo-faces))
(use-package magit-todos
  :init (magit-todos-mode 1))
Forge
(use-package forge
  :ensure nil
  :after magit)
(use-package embark-vc
  :after embark)
Pretty graph
(use-package magit-pretty-graph
  :ensure (:host github :repo "georgek/magit-pretty-graph")
  :bind 
  )

Open in browser

(use-package browse-at-remote
  :bind
  ("C-c g g" . browse-at-remote)
  ("C-c g k" . browse-at-remote-kill))

Terminal

(use-package eat
  :hook ((eat-mode . (lambda ()
					   (setq-local
						left-margin-width 3
						right-margin-width 3
						cursor-type 'bar)
					   (toggle-mode-line)
					   (face-remap-add-relative
						'default
						:family "Iosevka"
						:background "#281d12")
					   (face-remap-set-base
						'default
						:family "Iosevka"
						:background "#281d12")
					   (face-remap-add-relative
						'fringe
						:background "#281d12")
					   )))
  :custom ((eat-kill-buffer-on-exit t)
		   (eat-enable-yank-to-terminal t))
  ;; :bind
  ;; ("M-t" . eat-project-other)
  ;; ("C-M-t" . eat-other-window)
  )

Vterm

vterm was chosen over eat because eat does not support tramp very well

(use-package svg-tag-mode)
(use-package vterm
  :hook
  (vterm-mode . (lambda ()
				  (toggle-mode-line)
				  (set (make-local-variable 'buffer-face-mode-face) '(:family "IosevkaTerm Nerd Font"))
				  (buffer-face-mode t)
				  (setq-local left-margin-width 3
							  right-margin-width 3
							  cursor-type 'bar)
				  (face-remap-add-relative
				   'default
				   :background "#281d12")
				  (face-remap-set-base
				   'default
				   :background "#281d12")
				  (face-remap-add-relative
				   'fringe
				   :background "#281d12"))))

(use-package vterm-tabs
  ;; :ensure (:host github :repo "nehrbash/vterm-tabs")
  :load-path "~/src/vterm-tabs"
  :bind
  (("<f6>" . vterm-tabs-toggle)
   :map vterm-mode-map
   ("C-M-s" . consult-term)
   ("M-w" . copy-region-as-kill)
   ("C-y" . vterm-yank))
  :custom
  (vterm-buffer-maximum-size 800)
  (vterm-tramp-shells
   '(("ssh" "/bin/bash")
	 ("docker" "/bin/bash")
	 ("sudo" "/bin/bash")))
  (vterm-always-compile-module t)
  :config
  (require 'svg-tabs)
  (global-vterm-tabs-mode 1))

Direnv

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

Ligatures

Look at wiki if you change fonts for correct config. Currently using Iosevka.

(use-package ligature
  :config
  (ligature-set-ligatures 'prog-mode '("<---" "<--"  "<<-" "<-" "->" "-->" "--->" "<->" "<-->" "<--->" "<---->" "<!--"
                                       "<==" "<===" "<=" "=>" "=>>" "==>" "===>" ">=" "<=>" "<==>" "<===>" "<====>" "<!---"
                                       "<~~" "<~" "~>" "~~>" "::" ":::" "==" "!=" "===" "!=="
                                       ":=" ":-" ":+" "<*" "<*>" "*>" "<|" "<|>" "|>" "+:" "-:" "=:" "<******>" "++" "+++"))
  (global-ligature-mode t))

Compile Helpers

(use-package makefile-runner
  :ensure (:host github :repo "danamlund/emacs-makefile-runner"))
(use-package compile
  :ensure nil
  :custom
  (compilation-scroll-output t)
  (compile-command "task "))

Static Checking

keep switching between the 2 so I will leave both here and to quickly toggle between the 2.

Flymake

Has nice built in end of line although it’s a lot of clutter.

(use-package flymake
  :ensure nil
  :hook (prog-mode . flymake-mode)
  :custom
  (flymake-wrap-around t)
  (flymake-no-changes-timeout 3)
  (flymake-fringe-indicator-position 'right-fringe)
  ;; (flymake-show-diagnostics-at-end-of-line 'short)
  :config
  (add-to-list 'display-buffer-alist
             '("\\*Flymake diagnostics.*\\*"
               (display-buffer-reuse-window
                display-buffer-in-side-window)
               (side . bottom)
               (slot . 0)
               (window-height . 0.3)))
  :bind
  ("M-g f" . consult-flymake)          
  ("M-SPC p" . flymake-show-project-diagnostics))
(use-package flymake-shellcheck
   :commands flymake-shellcheck-load
   :hook (bash-ts-mode . flymake-shellcheck-load))
Display error in box on hover

For now I like line error in eldoc.

(use-package flymake-diagnostic-at-point
  :after flymake
  :config
  (add-hook 'flymake-mode-hook #'flymake-diagnostic-at-point-mode))  

Folding

(use-package treesit-fold
  :ensure (:host github :repo "emacs-tree-sitter/treesit-fold")
  :bind ("M-SPC f" . treesit-fold-toggle)
  :custom (treesit-fold-summary-max-length 80)
  :init
  (global-treesit-fold-mode))

Go

  • gomodifytags
  • goplay

    fill struct is now in code actions.

(use-package go-mode
  :ensure-system-package
  ((staticcheck . "go install honnef.co/go/tools/cmd/staticcheck@latest")
   (gofumpt . "go install mvdan.cc/gofumpt@latest")
   (gopls . "go install golang.org/x/tools/gopls@latest"))
  :hook (go-ts-mode . (lambda ()
						(subword-mode 1)
						(setq-local go-ts-mode-indent-offset 4))))
(use-package go-tag
  :ensure-system-package (gomodifytags . "go install github.com/fatih/gomodifytags@latest")
  :bind (:map go-ts-mode-map ("C-c C-t" . go-tag-add)))
(use-package go-impl
  :ensure-system-package (impl . "go install github.com/josharian/impl@latest")
  :bind (:map go-ts-mode-map ("C-c C-i" . go-impl)))
(use-package go-gen-test
  :ensure-system-package (gotests . "go install github.com/cweill/gotests/gotests@latest")
  :bind (:map go-ts-mode-map ("C-c t g" . go-gen-test-dwim)))
(use-package gotest
  :bind
  (:map go-ts-mode-map
		("C-c t f" . go-test-current-file)
		("C-c t t" . go-test-current-test)))

Rust

Copy paste form here https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/.

(use-package rust-ts-mode
  :ensure nil
  :mode ("\\.rs\\'" . rust-ts-mode)
  :hook (rust-ts-mode . (lambda ()
						  (setq-local compile-command "cargo run")))
  :config
  (add-to-list 'eglot-server-programs '((rust-ts-mode rust-mode) . ("rustup" "run" "stable" "rust-analyzer"))))
(use-package cargo-jump-xref
  :after toml-mode
  :ensure (:host github :repo "eval-exec/cargo-jump-xref.el")
  :config
  (add-to-list 'xref-backend-functions #'cargo-jump-xref-backend))

Guile

(use-package geiser
  :config
  (setq geiser-default-implementation 'guile)
  (setq geiser-active-implementations '(guile))
  (setq geiser-implementations-alist '(((regexp "\\.scm$") guile))))
(use-package geiser-guile
  :after geiser)

Shell

(use-package bash-ts-mode
  :ensure nil
  :mode ("\\.sh\\'" . bash-ts-mode))

Java Script

(use-package js-ts-mode
  :ensure nil
  :mode ("\\.js\\'" . js-ts-mode))

TOML

(use-package toml-ts-mode
  :ensure nil
  :hook (toml-ts-mode . goto-address-prog-mode))

Python

install server pip install -U jedi-language-server

(use-package python
  :mode ("\\.py\\'" . python-mode)
  :interpreter ("python" . python-mode))
(use-package conda
  :after python
  :commands (conda-env-list conda-env-activate)
  :config
  ;; The location of your anaconda home will be guessed from a list of common
  ;; possibilities, starting with `conda-anaconda-home''s default value (which
  ;; will consult a ANACONDA_HOME envvar, if it exists).
  ;;
  ;; If none of these work for you, `conda-anaconda-home' must be set
  ;; explicitly. Afterwards, run M-x `conda-env-activate' to switch between
  ;; environments
  (or (cl-loop for dir in (list conda-anaconda-home
								"~/.anaconda"
								"~/.miniconda"
								"~/.miniconda3"
								"~/.miniforge3"
								"~/anaconda3"
								"~/miniconda3"
								"~/miniforge3"
								"~/opt/miniconda3"
								"/usr/bin/anaconda3"
								"/usr/local/anaconda3"
								"/usr/local/miniconda3"
								"/usr/local/Caskroom/miniconda/base"
								"~/.conda")
			   if (file-directory-p dir)
			   return (setq conda-anaconda-home (expand-file-name dir)
							conda-env-home-directory (expand-file-name dir)))
	  (message "Cannot find Anaconda installation"))

  ;; integration with term/eshell
  (conda-env-initialize-interactive-shells)

  (add-to-list 'global-mode-string
			   '(conda-env-current-name (" conda:" conda-env-current-name " "))
			   'append))
(use-package jupyter
  :config
  (add-to-list 'org-babel-load-languages '(jupyter . t))
  (setq code-cells-convert-ipynb-style '(
										 ("pandoc" "--to" "ipynb" "--from" "org")
										 ("pandoc" "--to" "org" "--from" "ipynb")
										 org-mode)))

CSV

(use-package csv-mode
  :mode ("\\.[Cc][Ss][Vv]\\'" . csv-mode)
  :config
  (setq csv-separators '("," ";" "|" " " ", ")))

YAML

(use-package yaml-ts-mode
  :ensure nil
  :hook (yaml-ts-mode . goto-address-prog-mode))

Docker

(use-package docker
  :ensure-system-package
  (docker . "paru -S docker")
  (docker-compose . "paru -S docker-compose")
  (devcontainer . "npm install -g @devcontainers/cli")
  :bind ("M-SPC d" . docker)
  :config
  (fullframe docker-images tablist-quit)
  (fullframe docker-volumes tablist-quit)
  (fullframe docker-networks tablist-quit)
  (fullframe docker-containers tablist-quit))
(use-package docker-compose-mode
  :mode ("\docker-compose.yml\\'" . docker-compose-mode))

SQL

(use-package sqlformat
  :ensure-system-package (pgformatter)
  :hook (sql-mode . sqlformat-on-save-mode)
  :custom
  (sqlformat-command 'pgformatter)
  (setq sqlformat-args '("-s2" "-g")))

Terraform

(use-package terraform-mode)

Lisp

(use-package lisp-mode
  :ensure nil
  :custom (lisp-indent-offset 2))

Yuck

Yuck is the eww configuration language.

(use-package yuck-mode
  :mode ("\\.yuck\\'" . yuck-mode)
  :hook (yuck-mode . (lambda () (setq-local lisp-indent-offset 2))))

Markdown

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

All things HTML

Only use go templates so this works for me. if I work with more complex projects I may need to refactor to set on a per-project case.

(use-package web-mode
  :mode (("\\.html?\\'" . web-mode)
		 ("\\.css\\'" . web-mode)
		 ("\\.jsx?\\'" . web-mode)
		 ("\\.tsx?\\'" . web-mode)
		 ("\\.json\\'" . web-mode))
  :hook (web-mode . sn/web-mode-hook)
  :custom (web-mode-markup-indent-offset 2)
  :config
  (defun sn/web-mode-hook()
	"Set web-mode engine to 'go' if in web-mode."
	(when (equal major-mode 'web-mode)
      (web-mode-set-engine "go"))))

projects

(defun sn/start-ag-devcontainer ()
  "Close analytics-hub buffers, start the dev container, and open Dired and Magit."
  (interactive)
  ;; Close all buffers in ~/src/analytics-hub/
  (dolist (buffer (buffer-list))
    (when (string-prefix-p (expand-file-name "~/src/analytics-hub/") (or (buffer-file-name buffer) ""))
      (kill-buffer buffer)))
  ;; Set default directory and run the dev container command
  (let* ((default-directory (expand-file-name "~/src/analytics-hub/"))
         (output-buffer "*Start Dev-Container Output*")
         (result (call-process-shell-command "devcontainer up --workspace-folder ." nil output-buffer t)))
    (if (= result 0)
        (progn
          (message "Dev container started successfully.")
          ;; Open Dired and Magit only if the container starts successfully
          (dired "/docker:dev-container:/workspace/")
          (magit-status))
      (message "Error: Command failed. Check %s for details." output-buffer))))

Fancy Bloat

Mu4e - Mail

(use-package mu4e
  :ensure nil
  :commands (mu4e)
  ;; :load-path "/usr/share/emacs/site-lisp/mu4e/"
  :init
  (setq smtpmail-smtp-server "smtp.fastmail.com"
  		smtpmail-smtp-service 465
  		smtpmail-stream-type 'ssl)
  :custom
  ;; This is set to 't' to avoid mail syncing issues when using mbsync
  (mu4e-change-filenames-when-moving t)
  ;; Refresh mail using isync every 10 minutes
  (mu4e-update-interval (* 10 60))
  (mu4e-get-mail-command "mbsync -a")
  (mu4e-maildir "~/Mail")
  (mu4e-drafts-folder "/[Gmail]/Drafts")
  (mu4e-sent-folder   "/[Gmail]/Sent Mail")
  (mu4e-refile-folder "/[Gmail]/All Mail")
  (mu4e-trash-folder  "/[Gmail]/Trash")
  :config
  (setq mu4e-maildir-shortcuts
  		'(("/Inbox"             . ?i)
  		  ("/[Gmail]/Sent Mail" . ?s)
  		  ("/[Gmail]/Trash"     . ?t)
  		  ("/[Gmail]/Drafts"    . ?d)
  		  ("/[Gmail]/All Mail"  . ?a))))

Voice to Text

Speech-to-Text interface for Emacs using OpenAI’s whisper speech recognition model. For the inference engine it uses the awesome C/C++ port whisper.cpp that can run on consumer grade CPU (without requiring a high end GPU).

(use-package whisper
  :ensure (:host github :repo "natrys/whisper.el")
  :bind ("M-SPC w" . whisper-run)
  :config
  (setq whisper-install-directory "~/.cache/"
		whisper-model "base"
		whisper-language "en"
		whisper-translate nil))

AI

GPT

This section contains an Emacs Lisp function that reads a text file containing an OpenAI key and a configuration for the GPT Emacs package. The package is installed using the use-package macro and configured to use the gpt-3.5-turbo model with Emacs’ org-mode as the default mode for text editing. The gptel package is also bound to the <f5> and C-<f5> keys for quick access to the GPT language generation functionality.

(use-package gptel
  :bind
  ("<f5>" . gptel-toggle-sidebar)
  (:map vterm-mode-map
	 ("<f5>" . gptel-toggle-sidebar))
  ("C-<f5>" . gptel-menu)
  :hook (org-mode . gptel-activate-if-model-exists)
  :custom
  (gptel-model 'gpt-4o)
  (gptel-display-buffer-action
    '((display-buffer-reuse-window display-buffer-in-side-window)
       (side . right)
       (window-width . 80)
       (slot . 0)))
  (gptel-default-mode 'org-mode)
  :config
  (defun gptel-toggle-sidebar ()
	"Toggle a custom sidebar for the buffer '*My Sidebar*'."
	(interactive)
	(let ((buffer-name "AI Chat"))
	  (if-let* ((window (get-buffer-window buffer-name)))
		;; If the sidebar is already open, close it.
		(delete-window window)
		;; Else, create the sidebar using
		(let ((chat-buffer (gptel buffer-name)))
		  (display-buffer-in-side-window
			chat-buffer gptel-display-buffer-action)
		  (let ((window (get-buffer-window chat-buffer)))
			(when window
			  (set-window-dedicated-p window t)
			  (set-window-parameter window 'no-other-window t)
			  (select-window window)
			  (setq mode-line-format nil)))))))
  (defun gptel-close-headers (from to)
   	"Fold all org headers in the current buffer, except for the last response."
   	(when (eq major-mode 'org-mode)
	  (progn
   		(condition-case nil
          (progn
   			(org-cycle-global 0)
   			(goto-char from)
   			(while (outline-invisible-p (line-end-position))
			  (progn
				(outline-show-subtree)
				(outline-next-visible-heading 1))))
   		  (error (message "gptel-close-headers error: %s" (error-message-string err))))
		(outline-show-subtree) ; not sure why but sometimes needs this
		(org-end-of-line))))
  (add-to-list 'gptel-post-response-functions #'gptel-close-headers)
  (defun gptel-save-if-file (to from)
   	"Save the current buffer if it is associated with a file."
   	(when (buffer-file-name)
      (save-buffer)))
  (add-to-list 'gptel-post-response-functions #'gptel-save-if-file)
  (defun gptel-activate-if-model-exists ()
	"Activate gptel mode if the GPTEL_MODEL property exists in any part of the Org document."
	(org-with-wide-buffer
      (goto-char (point-min))
      (let ((found nil))
		(while (and (not found) (re-search-forward "^\\*+" nil t))
          (when (org-entry-get (point) "GPTEL_MODEL")
			(setq found t)))
		(when found
          (gptel-mode 1))))))

Codeium

(use-package codeium
  :ensure (:host github :repo "Exafunction/codeium.el")
  :after cape
  :custom
  (codeium-log-buffer nil)
  :config
  (advice-add 'codeium-completion-at-point :around #'cape-wrap-buster)
  
  ;; You can overwrite all the codeium configs!
  ;; for example, we recommend limiting the string sent to codeium for better performance
  (defun my-codeium/document/text ()
    (buffer-substring-no-properties (max (- (point) 3000) (point-min)) (min (+ (point) 1000) (point-max))))
  ;; if you change the text, you should also change the cursor_offset
  ;; warning: this is measured by UTF-8 encoded bytes
  (defun my-codeium/document/cursor_offset ()
    (codeium-utf8-byte-length
      (buffer-substring-no-properties (max (- (point) 3000) (point-min)) (point))))
  (setq codeium/document/text 'my-codeium/document/text)
  (setq codeium/document/cursor_offset 'my-codeium/document/cursor_offset)
  )

Tabnin

Alternative to codeium, supposed to be really fast.

(use-package tabnine 
  :bind
  (:map prog-mode-map
		("M-SPC t d" . tabnine-chat-document-code)
		("M-SPC t g" . tabnine-chat-generate-test-for-code)
		("M-SPC t e" . tabnine-chat-explain-code)
		("M-SPC t f" . tabnine-chat-fix-code)))
(use-package tabnine-capf
  :after cape
  :ensure (:host github :repo "50ways2sayhard/tabnine-capf")
  :hook (kill-emacs . tabnine-capf-kill-process)
  :bind ("M-SPC /" . (lambda () (interactive) (cape-capf-interactive #'tabnine-completion-at-point)))
  ;; (keymap-global-set "M-SPC /" (cape-capf-interactive #'tabnine-completion-at-point))
  )  

starhugger/ ollama

(use-package starhugger
  :ensure (:repo "https://gitlab.com/daanturo/starhugger.el" :files (:defaults "*.py"))
  :init
  (setq starhugger-completion-backend-function #'starhugger-ollama-completion-api)
  ;; (setq starhugger-hugging-face-api-token "hf_ your token here")
  (setq starhugger-model-id "codellama")
  :bind ("M-SPC s" . starhugger-trigger-suggestion)
  :config
  ;; `starhugger-inline-menu-item' makes a conditional binding that is only active at the inline suggestion start
  (define-key starhugger-inlining-mode-map (kbd "TAB") (starhugger-inline-menu-item #'starhugger-accept-suggestion))
  (define-key starhugger-inlining-mode-map (kbd "M-[") (starhugger-inline-menu-item #'starhugger-show-prev-suggestion))
  (define-key starhugger-inlining-mode-map (kbd "M-]") (starhugger-inline-menu-item #'starhugger-show-next-suggestion))
  (define-key starhugger-inlining-mode-map (kbd "M-f") (starhugger-inline-menu-item #'starhugger-accept-suggestion-by-word))
  )

Customize Dir Local

(use-package cus-dir
  :ensure (:host gitlab :repo "mauroaranda/cus-dir")
  :bind ("C-x p d" . customize-dirlocals-project))

Typing Practice

Typing practice inside Emacs.

(use-package speed-type
  :defer t)

Google This

dwin like google thing.

(use-package google-this
  :bind ("M-s w" . google-this))

Dev Documentation

(use-package devdocs
  :defer t)

Emacs Everywhere

bound to key ~$Mod n~q . modified version of https://github.com/psibi/emacs-everywhere

(use-package ea
  :load-path "~/.emacs.d/lisp")

Playing around with frames

also looking at window-setup-hook

(defun setup-min-frame ()
  "Set up frames for minibuffer and editor."
  (setq default-minibuffer-frame
		(make-frame
		 '((name . "Emacs Minibuffer")
		   (width . 80)
		   (height . 1)
		   (minibuffer . only)
		   (top . 0) ;; Ensure it's at the top
		   (left . 0)))))
(defun setup-no-min-frame ()
  "Set up frames for minibuffer and editor."
  (setq new-frame
		(make-frame
		 '((name . "Emacs Frame")
		   (width . 80)
		   (height . 30)
		   (minibuffer . nil)
		   (top . 50) ;; Adjust as needed
		   (left . 0)))))

;; (add-hook 'window-setup-hook 'setup-frames)  

Go Taskfile

(use-package consult-taskfile
  :load-path "~/src/consult-taskfile"
  :bind
  ("M-SPC x" . consult-task)
  ("M-SPC c" . taskfile))

Emetnt chat on Matrix

(use-package ement
  :custom
  (ement-room-prism 'both)
  (ement-save-sessions t))
(use-package burly)

App Launcher

(use-package app-launcher
  :ensure (:host github :repo "SebastienWae/app-launcher")
  :bind ("M-SPC L" . app-launcher-run-app)
  :demand t
  :config
  (defun sn/app-launcher ()
	"Lauch app and delete frame."
	(interactive)
      (unwind-protect
          (progn
			(app-launcher-run-app))
		(delete-frame frame))))

Zalgo Text

(use-package zalgo-mode
  ;; :load-path "~/src/zalgo-mode"
  :ensure (:host github :repo "nehrbash/zalgo-mode")
  :bind
  ("C-c z z" . zalgo-mode) ;; minor mode for typeing zalgo
  ("C-c z r" . zalgo-transform-region)
  ("C-c z w" . zalgo-transform-word)
:custom
(zalgo-max-up 5)
(zalgo-max-mid 3)
(zalgo-max-down 5))

Eww

 (use-package eww
   :ensure nil
   :custom
   (eww-auto-rename-buffer 'title)
   :config
   (define-advice eww (:around (oldfun &rest args) always-new-buffer)
     "Always open EWW in a new buffer."
     (let ((current-prefix-arg '(4)))
       (apply oldfun args)))
   ;; :bind
   ;; (:map eww-mode-map
   ;;           [mouse-8] #'eww-back-url
   ;;           [mouse-9] #'eww-forward-url)
)

Inspiration

Other dotfiles repos and blog posts for inspiration: