This is a .org
file that contains elisp org-babel code blocks. I will describe my configuration with org-mode and include the elisp configuration in org-babel code blocks. There is a Resources and Planning section at the end.
In the Org Babel
section of this file there is a save-hook to populate the user-emacs-directory
with .el
files containing the elisp from the code blocks. Each code block declares which file it will be tangled to.
This video summarizes my goals perfectly.
TODO___________________________---------------============--------------=========----------
In the Org
section there is also a hook to check for local info files when this file is loaded in emacs but to link to the website when loaded from http.
- Prefer builtin features.
- Prefer packages that use builtin features.
- Configuration should have as little scope as required.
- Configurations are defined near their dependencies.
- Dependencies should be clear.
- When not
display-graphic-p
, emacs should defer all possible loading.
Configuration is broken up into multiple files for the following considerations
- Pros:
- Debugging Un-break emacs startup by disabling a file instead of all customization
- Modular Loading Options Special versions (terminal version) can load a subset of the files a good deferring system could emulate this with practical parity? its unlikely that loading all of the words instead of some of them is in the scope where there would be a noticeable time difference
- Cons:
- Adds Complexity
- Adds Startup Time? Causes more garbage collections than loading one file Can possibly be mitigated with appropriate settings
The first init file loaded from user-emacs-directory
This file is limited to
- setting and un-setting load-time settings
- loading other init files
- built-in settings
- Change garbage collection threshold to 50 MB
- The default is 800 000 bytes
Garbage collections free memory by take time, raising the threshold uses more memory but saves time.
;---------------------------- Load Time Settings ----------------------------;
(setq gc-cons-threshold (* 50 1000 1000))
Non gui builtin features and vanilla tweaks
(when (eq system-type 'windows-nt)
(let ((msys-path "C:/msys64/usr/bin"))
(unless (member msys-path exec-path)
(setq exec-path (append (list msys-path) exec-path)))))
TODO - fix and add global version
A wrapper that is passed the function that is being hooked and the modes to exclude from a hook
;-------------------------- Exclude Mode from Hook --------------------------;
;; (defun mf/exclude-mode-from-global-hook (hook-function args &rest excluded-modes)
;; "Exclude EXCLUDED-MODES modes when adding HOOK-FUNCTION to a global hook"
;; (lambda ()
;; (unless (member major-mode excluded-modes)
;; (funcall (add-hook hook-function args)))))
(defun mf/exclude-mode-from-hook (hook-function args excluded-modes)
"Exclude EXCLUDED-MODES modes when adding HOOK-FUNCTION to a hook"
(lambda ()
(unless (member major-mode excluded-modes)
(apply hook-function args))))
(defun mf/maybe-make-dir (dir)
(unless (file-exists-p dir)
(make-directory dir)))
(defun mf/after-specific-time (hour minute)
"Check if the current time is after a specific time of day.
Example usage: (after-specific-time? 18 30) for 6:30 PM."
(let* ((now (decode-time)) ; Get the current time as a list
(current-hour (nth 2 now)) ; Extract the hour from the current time
(current-minute (nth 1 now)) ; Extract the minute from the current time
(target-time (list hour minute)) ; Create a list with the target time
(current-time (list current-hour current-minute))) ; Create a list with the current time
(or (and (> current-hour hour) t) ; Check if current hour is greater than target hour
(and (= current-hour hour) ; If hour is the same, check minutes
(> current-minute minute)))))
TODO - make delims handle odd title length TODO - use comment-start var TODO - Make tangle/func add delimes based on header (remove from blocks)
Make a bar to help visually divide files
;---------------------------- File Deliminators ----------------------------;
(defun mf/make-file-delims (title &optional line-limit comment-char padding)
"Make delimitors for files; the default length is 80 padding 3 and comment character #"
(interactive
(list (read-string "Title: ")
(read-number "Line limit (80): " 80)
(read-string "Comment character (#): " "#" comment-start comment-start)
(read-number "Padding (3): " 3)))
(let* ((default-line-limit 80)
(default-comment-char "#")
(default-padding 3)
(actual-line-limit (or line-limit default-line-limit))
(actual-comment-char (or comment-char default-comment-char))
(actual-padding (or padding default-padding))
(title-length (length title))
(remaining-space (- actual-line-limit
title-length
(* 2 actual-padding)
;; (if (cl-evenp title-length)
;; 1 0)
))
;; Constuct the line
(string (concat
actual-comment-char
(make-string (/ remaining-space 2) ?-) ;; Pad with dashes on the left
(make-string actual-padding ? ) ;; Pad with spaced on the left
title
(make-string actual-padding ? )
(make-string (/ remaining-space 2) ?-)
actual-comment-char)))
(if (interactive-p)
(insert string)
(message "%s" string))))
;; (let ((default-comment-char (or comment-start "#"))) ;; Set default comment char
;; (list (read-string (format "Comment character (%s): " default-comment-char)
;; nil nil default-comment-char) ;; Use default-comment-char as default value
;; (defun mf/longest-line-length (file-path)
;; "Return the length of the longest line in the specified file."
;; (interactive)
;; (with-temp-buffer
;; (insert-file-contents file-path)
;; (goto-char (point-min))
;; (let ((max-length 0))
;; (while (not (eobp))
;; (setq max-length (max max-length (- (line-end-position) (line-beginning-position))))
;; (forward-line 1))
;; max-length)))
(defun mf/longest-line-length (&optional file-path)
"Return the length of the longest line in the specified file.
If FILE-PATH is not provided, operate on the current buffer."
(interactive)
(with-temp-buffer
(if file-path
(insert-file-contents file-path)
(setq file-path (buffer-file-name)))
(goto-char (point-min))
(let ((max-length 0))
(while (not (eobp))
(setq max-length (max max-length (- (line-end-position) (line-beginning-position))))
(forward-line 1))
max-length)))
TODO - Move user functions I want to byte compile to file and auto compile
Emacs can compile elisp
- Turn off compiler warnings
- Set the native comp cache directory
;------------------------------- Native Comp -------------------------------;
(if (native-comp-available-p)
(progn
;; (setq native-comp-async-report-warnings-errors nil)
(add-to-list 'native-comp-eln-load-path (expand-file-name "eln-cache/" user-emacs-directory))
))
Enable buffer auto-revert (auto-update)
- Disable Auto reverting in Buffer-menu-mode since it behaves unexpectedly.
;------------------------------- Auto-Revert -------------------------------;
(require 'autorevert)
(setq global-auto-revert-ignore-modes (list 'Buffer-menu-mode))
(setq global-auto-revert-non-file-buffers t)
(global-auto-revert-mode t)
Frame defaults to full-screen maximized in compatible window managers or desktop environments
;------------------------------ Frame Settings ------------------------------;
(add-to-list 'default-frame-alist '(fullscreen . maximized))
Open Buffer List in same window.
;----------------------------- Window Settings -----------------------------;
(setq display-buffer-alist
(cons
'("\\*Buffer List\\*"
(display-buffer-same-window))
display-buffer-alist))
Switch to new windows when created
(defun mf/window-follow (&rest _arg)
"Advice to follow a function which spawn a window."
(other-window 1))
(advice-add 'split-window-below :after #'mf/window-follow)
(advice-add 'split-window-right :after #'mf/window-follow)
TODO: choose and integrate backend
Auth-source “is a way for multiple appreciations to share a single (password) configuration for user convenience”. It can be used with many backends.
- Set auth-sources
- mf/get-auth-source-secret takes “host” or site name and passes back secret (password)
;------------------------------- Auth-Source -------------------------------;
(setq auth-sources '("~/Documents/Keys/.authinfo.gpg"))
(defun mf/get-auth-source-secret (host)
"Retrieve a secret from auth-source for a given HOST."
(let ((secret (car (auth-source-search :host host :max 1))))
(when (functionp (plist-get secret :secret))
(funcall (plist-get secret :secret)))))
;; (use-package auth-source-pass
;; :after gptel
;; :config
;; (auth-source-pass-enable))
TODO: pull quotes from internet
Write a quote in the scratch buffer header line
;--------------------------------- Scratch ---------------------------------;
(setq initial-scratch-message nil)
(setq quotes
'("\"Be yourself; everyone else is already taken. - Oscar Wilde\" - Gpt3.5"
"\"I have not failed. I've just found 10,000 ways that won't work. - Thomas Edison\" - Gpt3.5"
"\"If you want to achieve greatness, stop asking for permission. - Unknown\" - Gpt3.5"
"\"The biggest risk is not taking any risk. In a world that's changing really quickly, the only strategy that is guaranteed to fail is not taking risks. - Mark Zuckerberg\" - Gpt3.5"
"\"It is what it is.\" - Marc from Spain"
"\"So we've looked at the data...\" - Ancient Proverb"
"\"Take it easy, will you?\" - Older lady I \"heeled\" while rushing" ))
(defun mf/header-quote (target-buffer)
(interactive)
(if (get-buffer target-buffer)
(let ((index (random (length quotes))))
(with-current-buffer target-buffer
(goto-char (point-max))
(setq-local header-line-format (nth index quotes))))
(message "%s does not exist" target-buffer)))
(defun mf/scratch-setup (target-buffer)
(mf/header-quote target-buffer)
(topspace-mode 1))
(defun mf/scratch-advice (orig-fun &rest args)
(if (not (string-equal (buffer-name) "*scratch*"))
(progn
(mf/header-quote "*scratch*")
(apply orig-fun args)
(topspace-mode 1))
(message "We're already here.")))
(advice-add 'scratch-buffer :around 'mf/scratch-advice)
(add-hook 'server-after-make-frame-hook (lambda () (mf/scratch-setup "*scratch*")))
Options
Function | Description |
---|---|
backup-by-copying t | Don’t clobber symlinks |
backup-directory-alist | Location of autosave dir |
delete-old-versions t | Silently delete excess backups |
kept-new-versions 6 | Number of versions to keep when a numbered backup is made |
kept-old-versions 2 | |
version-control t | Use versioned backups |
Put autosave files (#<filename>#) in user-emacs-directory/autosaves Put backup files (<filename>~) in user-emacs-directory/backups https://www.emacswiki.org/emacs/AutoSave
(mf/maybe-make-dir (concat user-emacs-directory "autosaves/"))
(mf/maybe-make-dir (concat user-emacs-directory "backups/"))
(setq auto-save-file-name-transforms
`((".*" ,(concat user-emacs-directory "autosaves/") t)))
(setq backup-directory-alist
`(("." . ,(concat user-emacs-directory "backups/"))))
History and persistence related settings
Restore session on restart
- Currently disabled because it breaks bufferp switching(?) and q to quit special files(??)
;--------------------------------- History ---------------------------------;
;; (defun mf/desktop-setup ()
;; (setq desktop-dirname (expand-file-name "emacs" (or (getenv "XDG_DATA_HOME") "~/.local/share")))
;; (desktop-save-mode 1))
;; (if (daemonp)
;; (progn
;; (add-hook 'server-after-make-frame-hook #'mf/desktop-setup)
;; (desktop-read)
;; (message "RED DE DESKTOP"))
;; (mf/desktop-setup))
Open ‘Recent Files’ buffer
(recentf-mode 1)
(global-set-key (kbd "C-x M-f") 'recentf-open-files)
SaveHist - A builtin that saves minibuffer history
;--------------------------------- SaveHist ---------------------------------;
(require 'savehist)
(add-hook 'vertico-mode-hook 'savehist-mode)
‘Block-undo’ marcros to save undo space
- from this post
;----------------------------------- Undo -----------------------------------;
(defun block-undo (fn &rest args)
(let ((marker (prepare-change-group)))
(unwind-protect (apply fn args)
(undo-amalgamate-change-group marker))))
(dolist (fn '(kmacro-call-macro
kmacro-exec-ring-item
dot-mode-execute
apply-macro-to-region-lines))
(advice-add fn :around #'block-undo))
hs-minor-mode
offers function and comment folding
;--------------------------------- Folding ---------------------------------;
(when (daemonp)
(require 'hideshow))
(defun mf/load-hideshow ()
"Load and enable hideshow minor mode"
(require 'hideshow)
(hs-minor-mode 1))
(with-eval-after-load 'hideshow
(define-key hs-minor-mode-map (kbd "<backtab>") 'hs-toggle-hiding)
(define-key hs-minor-mode-map (kbd "<C-tab>") 'hs-hide-all)
(define-key hs-minor-mode-map (kbd "<C-iso-lefttab>") 'hs-show-all))
(add-hook 'sh-mode-hook #'mf/load-hideshow)
(add-hook 'prog-mode-hook #'mf/load-hideshow)
TODO - Restrict Scope fix for system quit - was working?
Prompt for some things instead of doing them automatically
Quit attempt prompts for confirmation in graphical mode
- Terminal mode is for fast editing so I leave it enabled
;--------------------------------- Prompts ---------------------------------;
(when (display-graphic-p)
(setq confirm-kill-emacs 'y-or-n-p))
(defun mf/confirm-kill-emacsd (orig-fun &rest args)
"Ask for confirmation before killing Emacs server."
(if (daemonp)
(if (yes-or-no-p "Do you really want to kill the frame?")
(apply orig-fun args)
(message "Frame was not killed."))
(apply orig-fun args)))
(advice-add 'save-buffers-kill-terminal :around #'mf/confirm-kill-emacsd)
;; (when (daemonp)
;; (defun mf/confirm-kill-emacsd (orig-fun &rest args)
;; "Ask for confirmation before killing Emacs server."
;; (if (yes-or-no-p "Do you really want to kill the frame?")
;; (apply orig-fun args)
;; (message "Emacs server was not killed."))
;; (advice-add 'save-buffers-kill-terminal :around #'mf/confirm-kill-emacsd)))
;; (add-hook 'server-after-make-frame-hook #'mf/confirm-kill-emacsd)
If file is read only, prompt y|n to try to load files with root privileges
- Inspired by this stack overflow reply.
(defun mf/find-file-sudo-maybe ()
"Find file as root if necessary."
(interactive)
(unless (and buffer-file-name
(file-writable-p buffer-file-name))
(if (y-or-n-p (concat "File is read-only. Open as root? "))
(find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))
(message "File opened without root privileges."))))
(add-hook 'find-file-hook 'mf/find-file-sudo-maybe)
Prompt yes-or-no when overwriting file
(defun mf/use-yes-or-no-p (orig-fun &rest args)
"Wrap `yes-or-no-p' to use `yes-or-no-p' instead of `y-or-n-p'."
(cl-letf (((symbol-function 'y-or-n-p) #'yes-or-no-p))
(apply orig-fun args)))
(advice-add 'write-file :around #'mf/use-yes-or-no-p)
Only popup buffer for :error
level warnings
;--------------------------------- Popups ---------------------------------;
(setq warning-minimum-level :error)
Cut and copy work on entire lines if no active region
- From this post
;---------------------------- Text Manuipulation ----------------------------;
(defun mf/slick-copy (orig-fun &rest args)
"When called interactively with no active region, copy a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(message "Single line yanked")
(list (line-beginning-position)
(line-beginning-position 2))))
(apply orig-fun args))
(advice-add 'kill-ring-save :around 'mf/slick-copy)
(defun mf/slick-cut (orig-fun &rest args)
"When called interactively with no active region, kill a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(message "Single line killed")
(list (line-beginning-position)
(line-beginning-position 2))))
(apply orig-fun args))
(advice-add 'kill-region :around 'mf/slick-cut)
Delete matching parenthesis with backward-kill-word
; <C-backspace>, <M-backspace>
- From this post
(defun mf/delete-pair (orig-fun &rest args)
"Killing open parenthesis with backwards-kill-word kills close patenthesis"
(if (eq (char-syntax (char-before)) ?\()
(progn
(backward-char 1)
(save-excursion
(forward-sexp 1)
(delete-char -1))
(forward-char 1)
(append-next-kill)
(kill-backward-chars 1))
(apply orig-fun args)))
;; ad-do-it)
(advice-add 'backward-kill-word :around 'mf/delete-pair)
Remove excess whitespace when joining lines
- From this post
- Optionally use
delete-horizontal-space
instead ofjust-one-space 1
(defun mf/kill-line-before-autoindent ()
"Kill excess whitespace when joining lines.
If the next line is joined to the current line, kill the extra indent whitespace in front of the next line."
(when (and (eolp) (not (bolp)))
(save-excursion
(forward-char 1)
(just-one-space 1))))
(advice-add 'kill-line :before 'mf/kill-line-before-autoindent)
- Add point to tag marker ring when calling functions that will move your cursor this is an unintended use of the tag marker ring
;-------------------------------- Navigation --------------------------------;
(defun mf/add-point-to-find-tag-marker-ring (&rest r)
"Handy advising function to push point to the tag marker stack (R ignored)."
(require 'etags)
(xref-push-marker-stack))
(advice-add 'find-function :before 'mf/add-point-to-find-tag-marker-ring)
(advice-add 'consult-ripgrep :before 'mf/add-point-to-find-tag-marker-ring)
(advice-add 'consult-line :before 'mf/add-point-to-find-tag-marker-ring)
(advice-add 'consult-info :before 'mf/add-point-to-find-tag-marker-ring)
Set defaults
(setq browse-url-chromium-program "thorium-browser")
TODO Nice up https://github.com/protesilaos/dotfiles/blob/master/emacs/.emacs.d/prot-lisp/prot-eww.el
(use-package eww
:ensure nil
:commands (eww)
:init
;; (setq
;; browse-url-browser-function 'eww-browse-url ; Use eww as the default browser
;; shr-use-fonts nil ; No special fonts
;; shr-use-colors nil ; No colours
;; shr-indentation 2 ; Left-side margin
;; shr-width 70 ; Fold text to 70 columns
;; eww-search-prefix "https://wiby.me/?q=") ; Use another engine for searching
:config
;; (setq eww-restore-desktop t)
;; (setq eww-desktop-remove-duplicates t)
;; (setq eww-header-line-format nil)
(setq eww-search-prefix "https://duckduckgo.com/html/?q=")
(setq eww-download-directory (expand-file-name "~/Downloads/Eww/"))
(setq eww-suggest-uris
'(eww-links-at-point
thing-at-point-url-at-point))
(setq eww-bookmarks-directory (locate-user-emacs-file "eww-bookmarks/"))
(setq eww-history-limit nil))
;; (setq eww-use-external-browser-for-content-type
;; "\\`\\(video/\\|audio\\)") ; On GNU/Linux check your mimeapps.list
;; (setq eww-browse-url-new-window-is-tab nil)
;; (setq eww-form-checkbox-selected-symbol "[X]")
;; (setq eww-form-checkbox-symbol "[ ]")
;; NOTE `eww-retrieve-command' is for Emacs28. I tried the following
;; two values. The first would not render properly some plain text
;; pages, such as by messing up the spacing between paragraphs. The
;; second is more reliable but feels slower. So I just use the
;; default (nil), though I find wget to be a bit faster. In that case
;; one could live with the occasional errors by using `eww-download'
;; on the offending page, but I prefer consistency.
;;
;; '("wget" "--quiet" "--output-document=-")
;; '("chromium" "--headless" "--dump-dom")
;; (setq eww-retrieve-command nil))
- Keybind for minibuffer
(global-set-key (kbd "C-c b") 'switch-to-minibuffer)
- Display Emacs load time and gcs
- Refresh dwm blocks if in daemon mode
- Inhibit startup Message
;--------------------------------- Startup ---------------------------------;
(add-hook 'emacs-startup-hook
(lambda ()
(message "*** Emacs loaded in %s with %d garbage collections."
(format "%.2f seconds"
(float-time
(time-subtract after-init-time before-init-time)))
gcs-done)))
(if (daemonp)
(add-hook 'emacs-startup-hook
(lambda ()
(shell-command "pkill -RTMIN+7 dwmblocks"))))
(setq inhibit-startup-message t)
mf/org-dropbox | Run dropbox when any ~/Dropbox file is saved |
Function | Description |
---|---|
mf/xrdb-xresources | Aftersave hook to reinit .Xresources |
;------- Save Hooks -------\
(defun mf/xrdb-xresources ()
"Run xrdb on ~/.Xresources ."
(message "running xrdb hook")
(when (and (buffer-file-name) ; check buffer has a name - why??
(string-equal (buffer-file-name)
(expand-file-name "~/.Xresources")))
(let ((command-result (shell-command "xrdb ~/.Xresources")))
(when (= command-result 0)
(message "Xrdb Updated")))))
(defun mf/add-xrdb-hook ()
"Add mf/xrdb-xresources to 'after-save-hook'."
(add-hook 'after-save-hook #'mf/xrdb-xresources nil :local))
(add-hook 'conf-xdefaults-mode-hook #'mf/add-xrdb-hook)
Sexps that are run when emacs is killed.
- Refresh dwmblocks when emacs is killed
;-------------------------------- Kill Hooks --------------------------------;
(if (daemonp)
(add-hook 'kill-emacs-hook
(lambda ()
(shell-command "pkill -RTMIN+7 dwmblocks"))))
TODO - Use setup.el? elpaca?
Package manger configs
Package | Description |
---|---|
package.el | The Emacs package utility |
- Set package repository locations
- Install use-package if not installed
- Make sure all packages are installed
;----------------------------- Package Managers -----------------------------;
(require 'package)
(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")
("org" . "https://orgmode.org/elpa/")
("melpa-stable" . "https://stable.melpa.org/packages/")))
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
M-x List Packages
(add-hook 'package-menu-mode-hook (lambda () (setq truncate-lines t)))
(add-hook 'package-menu-mode-hook (lambda () (visual-line-mode -1)))
from here
;---------------------------- Reinstall Package ----------------------------;
(defun er-reinstall-package (pkg)
(interactive (list (intern (completing-read "Reinstall package: " (mapcar #'car package-alist)))))
(unload-feature pkg)
(package-reinstall pkg)
(require pkg))
https://github.com/radian-software/straight.el
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name
"straight/repos/straight.el/bootstrap.el"
(or (bound-and-true-p straight-base-dir)
user-emacs-directory)))
(bootstrap-version 7))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(setq package-enable-at-startup nil)
;; Load the new Org version for straight+babel errors
(straight-use-package 'org)
Package | Description |
---|---|
use-package | Macros for cleaner init files |
use-package-ensure | Ensures all use-packaged packages are installed |
- Initialize use-package on non-linux systems
- use-package-verbose for annoying messages
(straight-use-package 'use-package)
;; (unless (package-installed-p 'use-package)
;; (package-install 'use-package))
;; (eval-when-compile
;; (require 'use-package))
(require 'use-package-ensure)
(setq use-package-always-ensure t)
(setq use-package-always-demand (daemonp))
(setq use-package-verbose t)
TODO - Make non critical startup errors more obvious
TODO - load different configs on not display-graphic-p
if not daemonp
etc? or just defer well
TODO - move custom after?
Set and load custom file Load elsip init-files
;-------------------------------- Load Files --------------------------------;
(setq custom-file (locate-user-emacs-file "mf-custom.el"))
;; (load custom-file 'noerror 'nomessage)
(load custom-file)
(defun mf/load-init-with-msg (file-names)
"Load a list of user init files and message if succesful"
(dolist (file-name file-names)
(condition-case err
(progn
(load (concat user-emacs-directory file-name))
(mf/make-file-delims (concat "Loaded " file-name)))
(error (message "Failed to load %s: %s" file-name err)))))
;; (setq debug-on-error t) ;annoying
(mf/load-init-with-msg '(
"mf-packages.el"
"mf-keys.el"
"mf-org.el"
"mf-gui.el"
))
(mf/make-file-delims "Loaded init.el")
;----------------------------- Un-Set Settings -----------------------------;
(setq gc-cons-threshold (* 2 1000 1000))
Non-gui and non-org packages are loaded here
Packages that provide documentation features
Helpful - Better documentation
;------- Documentation -------\
(use-package helpful
:defer (not (daemonp))
:commands (helpful-callable helpful-variable helpful-command helpful-key)
:bind
([remap describe-function] . helpful-function)
([remap describe-symbol] . helpful-symbol)
([remap describe-variable] . helpful-variable)
([remap describe-command] . helpful-command)
([remap describe-key] . helpful-key))
Todo - fix with eval after load
View man packages in emacs, woman is nice but does not support a mandoc format.
(define-advice man (:before (&rest _args) my-woman-prompt)
"Use woman complation for man."
(interactive (progn
(require 'woman)
(list (woman-file-name nil)))))
(with-eval-after-load 'Man
'(progn
;; (set-face-attribute 'Man-underline nil :foreground "cyan")
(set-face-attribute 'Man-overstrike nil :foreground "white")))
;; (set-face-attribute 'Man-underline nil :inherit 'link)
;; (set-face-attribute 'Man-overstrike nil :inherit 'keywowrd)Z))
(use-package dictionary)
Completion Packages
Oerderless - Orderless and wildcard completion support
;----------------------- General Completion Packages -----------------------;
(use-package orderless
;; :after vertico
:init
(setq completion-styles '(orderless basic)
completion-category-defaults nil
completion-category-overrides '((file (styles partial-completion)))))
TODO - Spelling Completion in minibuffer https://robbmann.io/posts/emacs-29-completions/
TODO - Break up
Completion in the minibuffer
Package | Description |
---|---|
Consult | Consult completing-read for minibuffer completion |
Vertico | Vertical minibuffer completion UI |
Marginalia | Additional mini-buffer completion information |
Emacs | Minibuffer settings |
;----------------------- Minibuffer Completion -----------------------;
(use-package consult
:init
(defun mf/get-project-root ()
(when (fboundp 'projectile-project-root)
(projectile-project-root)))
:demand t
:bind (("C-s" . consult-line)
("C-S-s" . consult-ripgrep)
("C-M-l" . consult-imenu)
("C-h C-s" . consult-info)
("C-h C-s" . consult-info)
:map minibuffer-local-map
("C-r" . consult-history))
:custom
(consult-project-root-function #'mf/get-project-root)
(completion-in-region-function #'consult-completion-in-region))
(use-package vertico
:diminish
;; :bind (:map vertico-map
;; ("C-j" . vertico-exit))
:custom
(vertico-cycle t)
:init
(vertico-mode))
(use-package vertico-posframe
:after vertico
:custom
(vertico-posframe-parameters
'((left-fringe . 8)
(right-fringe . 8)))
:init
;; (add-hook 'vertico-posframe-mode-hook (lambda () (setq truncate-lines t)))
;; (add-hook 'vertico-posframe-mode-hook (lambda () (visual-line-mode -1)))
(defun mf/vertico-setup ()
"Check emacs frame orientation and turn on posframe-mode if portrait."
(interactive)
(if (> (frame-pixel-height) (frame-pixel-width))
(vertico-posframe-mode 1))
(message "%s %s" (frame-pixel-height) (frame-pixel-width)))
(if (daemonp)
(add-hook 'server-after-make-frame-hook #'mf/vertico-setup)
:config
(mf/vertico-setup)))
(use-package marginalia
:after vertico
:custom
(marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
:init
(marginalia-mode))
(use-package emacs
:bind
(:map minibuffer-mode-map
("TAB" . completion-at-point))
:init
;; Add prompt indicator to `completing-read-multiple'.
;; Alternatively try `consult-completing-read-multiple'.
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
;; Vertico commands are hidden in normal buffers.
;; (setq read-extended-command-predicate
;; #'command-completion-default-include-p)
;; Enable recursive minibuffers
(setq enable-recursive-minibuffers t))
A front-end for ag (‘the silver searcher’), the C ack replacement.
(use-package ag
:defer (not (daemonp)))
TODO: DEFERR, ignore [RET]
Corfu - COmpletion in Region FUnction
- Corfu does not provide any back ends
;------- Completion at Point -------\
(use-package corfu
:custom
(corfu-cycle t)
(corfu-auto t)
(corfu-auto-delay 0.25)
(corfu-auto-prefix 3)
(corfu-quit-at-boundary t)
(corfu-quit-no-match 'separator)
(corfu-separator ?\s)
(corfu-on-exact-match 'quit)
(corfu-preview-current nil)
:bind (:map corfu-map
("C-n" . corfu-next)
("C-p" . corfu-previous)
("C-g" . corfu-quit))
:init
(global-corfu-mode))
Enable corfu in the minibuffer
;; (defun corfu-enable-in-minibuffer ()
;; "Enable Corfu in the minibuffer."
;; (when (local-variable-p 'completion-at-point-functions)
;; ;; (setq-local corfu-auto nil) ;; Enable/disable auto completion
;; (setq-local corfu-echo-delay 0 ;; Disable automatic echo and popup
;; corfu-popupinfo-delay 0)
;; (corfu-mode 1)))
;; (add-hook 'minibuffer-setup-hook #'corfu-enable-in-minibuffer)
Single <return> enters corfu in shell
;; (defun corfu-send-shell (&rest _)
;; "Send completion candidate when inside comint/eshell."
;; (cond
;; ((and (derived-mode-p 'eshell-mode) (fboundp 'eshell-send-input))
;; (eshell-send-input))
;; ((and (derived-mode-p 'comint-mode) (fboundp 'comint-send-input))
;; (comint-send-input))))
;; (advice-add #'corfu-insert :after #'corfu-send-shell)
TAB cycle if there are only few candidates
- Enable indentation+completion using the TAB key.
(use-package emacs
:init
(setq completion-cycle-threshold nil)
(setq tab-always-indent 'complete))
Cape - Completion At Point Extensions
(use-package cape
:bind (("C-c p p" . completion-at-point) ;; capf
("C-c p t" . complete-tag) ;; etags
("C-c p d" . cape-dabbrev) ;; or dabbrev-completion
("C-c p h" . cape-history)
("C-c p f" . cape-file)
("C-c p k" . cape-keyword)
("C-c p s" . cape-elsip-symbol)
("C-c p a" . cape-abbrev)
("C-c p l" . cape-line)
("C-c p w" . cape-dict)
("C-c p \\" . cape-tex)
("C-c p _" . cape-tex)
("C-c p ^" . cape-tex)
("C-c p &" . cape-sgml)
("C-c p r" . cape-rfc1345))
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
;; NOTE: The order matters!
(add-to-list 'completion-at-point-functions #'cape-history)
(add-to-list 'completion-at-point-functions #'cape-keyword)
(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-tex)
(add-to-list 'completion-at-point-functions #'cape-elisp-block)
;; (add-to-list 'completion-at-point-functions #'cape-sgml)
;; (add-to-list 'completion-at-point-functions #'cape-rfc1345)
(add-to-list 'completion-at-point-functions #'cape-dict)
;; (add-to-list 'completion-at-point-functions #'cape-abbrev)
;; change org blocks form text mode
;; (add-to-list 'completion-at-point-functions #'cape-elisp-symbol)
;; only for prog mode
;; (add-to-list 'completion-at-point-functions #'cape-line)
)
TODO: lite ispell mode TODO: dicts TODO: combine into toggle able revertible check doc func (aggresive spelling, whitespace-mode etc.)
Package | Description |
---|---|
flyspell.el | Spell checking mode |
whitespace.el | Show whitespace |
- Set $DICPATH to “$HOME/Documents/Dictionaries” for hunspell.
- Tell ispell-mode to use hunspell.
(setenv "DICPATH" (concat (getenv "HOME") "/Documents/Dictionaries")) (setq ispell-program-name "/usr/bin/hunspell") (use-package flyspell :init (setq flyspell-default-dictionary "en_CA") (setq ispell-personal-dictionary (expand-file-name ".mf-personal_en_CA" (getenv "DICPATH"))) :hook ((org-mode . flyspell-mode) (text-mode . flyspell-mode) (prog-mode . flyspell-prog-mode)) :bind ("C-c f" . flyspell-mode)) (use-package whitespace :bind ("C-c w" . whitespace-mode))
(use-package smartparens
:diminish smartparens-mode
:ensure smartparens ;; install the package
:hook (prog-mode text-mode markdown-mode) ;; add `smartparens-mode` to these hooks
:config
;; load default config
(require 'smartparens-config))
Package | Description |
---|---|
Gptel | No-frills emacs auto-gpt client |
;------- LLM -------\
(defun mf/check-host-availability (host port)
"Check if HOST at PORT is reachable."
(let ((reachable nil))
(condition-case nil
(let ((conn (open-network-stream "test-conn" nil host port)))
(setq reachable t)
(delete-process conn))
(error nil))
reachable))
(defun mf/start-ollama-if-not-running ()
"Check if ollama is running and start it if not, with user confirmation."
(let ((exit-code (call-process "ollama" nil nil nil "ps")))
(if (= exit-code 0)
(message "ollama is already running.")
(if (y-or-n-p "ollama is not running. Do you want to start it? ")
(progn
(message "Starting ollama...")
(start-process "start-ollama" nil "sudo" "rc-service" "ollama" "start")
;; (shell-command "sudo rc-service ollama start")
(message "ollama started successfully."))
(message "ollama will not be started.")))))
(use-package gptel
:defer (not (daemonp))
:commands gptel
:config
(gptel-make-ollama "OrcaMini-3b-Local"
:host "localhost:11434"
:stream t
:models '("orca-mini"))
(gptel-make-ollama "Deepseek-coder-1b-local"
:host "localhost:11434"
:stream t
:models '("deepseek-coder"))
(gptel-make-ollama "CodeGemma-2b-local"
:host "localhost:11434"
:stream t
:models '("codegemma:2b"))
;; (gptel-make-ollama "Gemma-2b-local"
;; :host "localhost:11434"
;; :stream t
;; :models '("gemma:2b"))
(gptel-make-ollama "Phi3-2b-local"
:host "localhost:11434"
:stream t
:models '("phi3:mini"))
(gptel-make-ollama "CodeLlama-7b-Local"
:host "localhost:11434"
:stream t
:models '("codellama:latest"))
(gptel-make-ollama "Llama3-8b-Local"
:host "localhost:11434"
:stream t
:models '("llama3:latest"))
(gptel-make-ollama "Starcoder-Local"
:host "localhost:11434"
:stream t
:models '("starcoder:latest"))
(gptel-make-ollama "Mistral-7b-Local"
:host "localhost:11434"
:stream t
:models '("mistral:latest"))
(gptel-make-ollama "Ollama-8b-CS"
:host "192.168.2.9:11434"
:stream t
:models '("llama3:8b"))
(gptel-make-ollama "CodeLlama-7b-CS"
:host "192.168.2.9:11434"
:stream t
:models '("codellama:7b"))
(gptel-make-ollama "Ollama-8b-NS"
:host "192.168.2.7:11434"
:stream t
:models '("llama3:8b"))
(setq gptel-default-mode 'org-mode
;; ;; gptel-model "llama3:70b"
;; ;; gptel-api-key (gptel-api-key-from-auth-source)
gptel-backend
(if (mf/check-host-availability "192.168.2.9" 11434)
(progn (gptel-make-ollama "Ollama-8b-CS"
:host "192.168.2.9:11434"
:stream t
:models '("llama3:8b")))
(progn (mf/start-ollama-if-not-running)
(gptel-make-ollama "Gemma-2b-Local"
:host "localhost:11434"
:stream t
:models '("gemma:2b"))))
;; gptel-model
;; (if )
;; (setq gptel-model "orca-mini")
;; (setq gptel-model "llama3:8b")
)
:bind (:map gptel-mode-map
("C-c q" . gptel-abort)
("C-c t" . gptel-org-set-topic)
("C-c M" . gptel-org-set-preperties)
("C-c m" . gptel-menu))
)
Package | Description |
---|---|
Eglot | Lsp backend |
Web-Mode | Major mode for editiong web templates |
Skewer-Mode | Live web development in Emacs |
Python-Mode | Major mode for editing python |
Haskell-Mode | Major mode for editing haskell |
Racket-Mode | Major mode for editing racket |
;------- LSP -------\
(use-package eglot
:init
(setq eglot-project-root-files '(".projectile" ".git" ".svn" ".hg" ".project"))
(setq eglot-ignored-server-capabilites '(:documentHighlightProvider))
(setq eglot-stay-out-of '(company capf flymake))
:hook
((c-mode c++mode obj-mode cuda-mode js-mode web-mode) . eglot-ensure)
:config
(add-to-list 'eglot-server-programs '((c++mode c-mode) "clangd")))
(use-package web-mode
:mode "\\.html?\\'"
;; :mode "\\\\.(html?\\|ejs\\|tsx\\|jsx\\)\\'"
:config
(setq-default web-mode-code-indent-offset 2)
(setq-default web-mode-markup-indent-offset 2)
(setq-default web-mode-attribute-indent-offset 2))
;; 1. Start the server with `httpd-start'
;; 2. Use `impatient-mode' on any buffer
(use-package impatient-mode
;;:mode "\\.html?\\'")
:mode "(\\.\\(html?\\|ejs\\|tsx\\|jsx\\)\\'")
(use-package skewer-mode
;;:mode "\\.html?\\'")
:mode "(\\.\\(html?\\|ejs\\|tsx\\|jsx\\)\\'")
(use-package python-mode
:hook (python-mode . eglot-ensure)
:custom
;; NOTE: Set these if Python 3 is called "python3" on your system!
(python-shell-interpreter "python3")
(dap-python-executable "python3"))
(use-package haskell-mode
:defer (not (daemonp)))
(use-package racket-mode
:defer (not (daemonp)))
Package | Description |
---|---|
Slime | Lisp REPL |
(use-package slime
:defer (not (daemonp))
:config
(setq inferior-lisp-program "sbcl")
(let ((slime-folder (expand-file-name "slime/" (or (getenv "XDG_DATA_HOME") "~/.local/share"))))
(unless (file-exists-p slime-folder)
(make-directory slime-folder)))
(setq slime-repl-history-file
(expand-file-name "slime/slime-history.eld" (or (getenv "XDG_DATA_HOME") "~/.local/share")))
(setq slime-compile-file-options `(:output-file ,(expand-file-name "slime/" (or (getenv "XDG_DATA_HOME") "~/.local/share"))))
(add-to-list 'load-path "/usr/share/emacs/site-lisp/slime/")
(slime-setup '(slime-fancy)))
Package | Description |
---|---|
Projectile | Project interaction library |
vc | Built in version control |
Magit | Git porcelain |
Forge | Additional git features |
;------- Version Control -------\
(use-package vc
:custom
(vc-follow-symlinks t))
(use-package projectile
:diminish projectile-mode
:init
(defun mf/projectile--local-search-dir (dir)
(when (file-directory-p dir)
(setq projectile-project-search-path `(,dir))))
(mf/projectile--local-search-dir "~/Code")
(mf/projectile--local-search-dir "~/.config")
(setq projectile-switch-project-action #'projectile-dired)
:bind-keymap
("C-c P" . projectile-command-map)
:config
(add-to-list 'project-find-functions #'(lambda (dir) (directory-files dir nil "\\.c\\'")))
(projectile-mode))
;;:custom ((projectile-completion-system 'vertico))
(use-package magit
:commands magit-status)
(use-package sqlite3
:after magit)
(use-package forge
:after magit)
Package | Description |
---|---|
vterm | Terminal emulator |
;------- Terminals -------\
(use-package vterm
:defer (not (daemonp))
:commands vterm
:config
(setq term-prompt-regexp "^[^#$%>\n]*[#$%>] *") ;; Set this to match your custom shell prompt
;;(setq vterm-shell "zsh") ;; Set this to customize the shell to launch
(setq vterm-max-scrollback 10000))
Call with C-x / Query search engines
(use-package engine-mode
:init
(setq engine/browser-function 'eww-browse-url)
:config
(engine-mode t))
(with-eval-after-load 'engine-mode
(defengine duckduckgo
"https://duckduckgo.com/?q=%s"
:term-transformation-hook (lambda (term) (if current-prefix-arg
(concat "\"" term "\"")
term))
:keybinding "d")
(defengine github
"https://github.com/search?ref=simplesearch&q=%s"
:keybinding "G")
(defengine emacswiki
"https://html.duckduckgo.com/html?q=%s site:emacswiki.org"
:keybinding "e")
(defengine google
"https://www.google.com/search?q=%s"
:keybinding "g")
(defengine reddit
"https://www.reddit.com/search?q=%s"
:keybinding "r")
(defengine wikipedia
"https://www.wikipedia.org/search-redirect.php?search=%s"
:keybinding "w"))
A web api package depending on w3m
(use-package w3m
:defer (not (daemonp)))
Package | Description |
---|---|
Tramp | Transparent Remote Access Multiple Protocol |
;------- Tramp -------\
(use-package tramp
:defer (not (daemonp))
:config
(setq tramp-default-method "ssh"
tramp-default-user "max")
(add-to-list 'tramp-connection-properties
(list (regexp-quote "/ssh:user@host:")
"remote-shell" "/bin/sh")))
;; (require 'tramp-sh nil t)
;; (setf tramp-ssh-controlmaster-options (concat "-o SendEnv TRAMP=yes " tramp-ssh-controlmaster-options))
;------- Arduino -------\
(use-package arduino-mode
:defer (not (daemonp)))
Package | Description |
---|---|
ERC | Emacs client for IRC |
erc-hl-nicks | Hilight nicknames in erc |
erc-image | Display images in erc |
;------- ERC -------\
(when (display-graphic-p)
(use-package erc
:defer (not (daemonp))
:init
(setq erc-server "irc.libera.chat"
;; erc-nick ""
;; erc-user-full-name ""
erc-track-shorten-start 8 ; Length of channel notifcation in mode-line
;; erc-autojoin-channels-alist '(("irc.libera.chat" "#systemcrafters" "#emacs"))
erc-kill-buffer-on-part t
erc-auto-query 'bury ; No auto-focus buffer when mentioned
erc-fill-column 79 ; Defualt
erc-fill-function 'erc-fill-static
erc-fill-static-center 20
erc-track-exclude-types '("JOIN" "NICK" "QUIT" "MODE" "AWAY")
erc-track-visibility nil) ; Only use the selected frame to consider notification seen
:config
(add-to-list 'erc-modules 'notifications)
(add-to-list 'erc-modules 'spelling)
(erc-services-mode 1)
(erc-update-modules))
;------- ERC Packages -------\
(use-package erc-hl-nicks
:defer (not (daemonp))
:after erc
:config
(add-to-list 'erc-modules 'hl-nicks))
(use-package erc-image
:defer (not (daemonp))
:after erc
:config
(setq erc-image-inline-rescale 600)
(add-to-list 'erc-modules 'image)))
Package | Description |
---|---|
buku | Org mode browser bookmarks |
;; (use-package ebuku
;; :defer (not (daemonp))
;; :config
;; (setq ebuku-buku-path "/usr/bin/buku"))
Package | Descrition |
---|---|
pdf-tools | Pdf support |
;------- File Types -------\
(use-package pdf-tools
;:pin manual ;; manually update *****breaks first install*****
;; :mode ("\\.pdf\\'" . pdf-view-mode)
:magic ("%PDF" . pdf-view-mode)
:config
(pdf-tools-install)
(setq-default pdf-view-display-size 'fit-page)
(setq pdf-annot-activate-created-annotations t)
:bind (:map pdf-view-mode-map
("C-s" . consult-line)))
- Load arduino files (.ino) in c-mode
(add-to-list 'auto-mode-alist
'("\\.ino\\'" . (lambda ()
(c-mode))))
Global key-binds using general hydra and which key, binds depending on package should be declared as close to their dependencies as possible.
If possible bind a key to its minimal required scope and use the :commands
macro to load the :deferred
package
Should emacs just be emacs?
e-~vi~-l give E-macs VI L-ayers
Package | Description |
---|---|
Evil | Vi Layers |
Evil Collection | Additional mode support for Evil |
(use-package evil
:init
(setq evil-want-integration t
evil-want-keybinding nil
evil-want-C-u-scroll t
evil-want-C-i-jump nil
evil-respect-visual-line-mode nil
evil-insert-state-cursor 'bar
evil-mode-line-format '(before . mode-line-front-space)
evil-disable-insert-state-bindings t
evil-move-beyond-eol t
evil-want-fine-undo t)
:config
(evil-mode 1)
(define-key evil-insert-state-map (kbd "C-h") 'evil-delete-backward-char-and-join)
;; Use visual line motions even outside of visual-line-mode buffers
(evil-global-set-key 'motion "j" 'evil-next-visual-line)
(evil-global-set-key 'motion "k" 'evil-previous-visual-line)
(evil-set-initial-state 'messages-buffer-mode 'normal)
(evil-set-initial-state 'dashboard-mode 'normal)
(evil-set-initial-state 'org-agenda-mode 'normal))
(use-package evil-collection
:after evil
:hook (evil-mode . evil-collection-init)
:diminish evil-collection-unimpaired-mode
:config
(evil-collection-init))
Complain about arrow keys Vim binds for dired
;------------------------------ Evil Key Binds ------------------------------;
(with-eval-after-load 'evil
(defun dw/dont-arrow-me-bro ()
(interactive)
(message "Arrow keys are bad, you know?"))
;; Disable arrow keys in normal and visual modes
(define-key evil-normal-state-map (kbd "<left>") 'dw/dont-arrow-me-bro)
(define-key evil-normal-state-map (kbd "<right>") 'dw/dont-arrow-me-bro)
(define-key evil-normal-state-map (kbd "<down>") 'dw/dont-arrow-me-bro)
(define-key evil-normal-state-map (kbd "<up>") 'dw/dont-arrow-me-bro)
(evil-global-set-key 'motion (kbd "<left>") 'dw/dont-arrow-me-bro)
(evil-global-set-key 'motion (kbd "<right>") 'dw/dont-arrow-me-bro)
(evil-global-set-key 'motion (kbd "<down>") 'dw/dont-arrow-me-bro)
(evil-global-set-key 'motion (kbd "<up>") 'dw/dont-arrow-me-bro)
(with-eval-after-load 'dired
(require 'evil-collection)
(evil-collection-define-key 'normal 'dired-mode-map
"h" 'dired-single-up-directory
"H" 'dired-omit-mode
"l" 'dired-single-buffer
"y" 'dired-ranger-copy
"X" 'dired-ranger-move
"p" 'dired-ranger-paste))
(defvar special-special-buffers '("*Warnings*" "*info*")
"List of special-buffers that are immune to <q>.")
(add-hook 'special-mode-hook
(lambda ()
(unless (or (eq major-mode 'eww-mode)
(member (buffer-name) special-special-buffers))
(define-key evil-normal-state-local-map
(kbd "q") 'kill-buffer-and-window))))
)
Package | Description |
---|---|
General | Leader keys |
Which-Key | Display available next keystrokes for keybinds |
Hydra | Prefix bindings |
;------- Key Packages -------\
(use-package general
:config
(general-create-definer mf/general-keys
:keymaps '(normal insert visual emacs)
:prefix "SPC"
:global-prefix "M-SPC"))
(use-package which-key
;; :diminish which-key-mode
:diminish
:config
(which-key-mode)
(setq which-key-idle-delay .33))
(use-package hydra
:after general
:commands defhydra)
Function | Description |
---|---|
mf/general-keys | Define leading keys in keybinds |
hydra-text-scale | Scale text with j and k |
hydra-find-file | |
hydra-find-config | |
hydra-find-dir | |
hydra-switch-buffer | |
hydra-switch-window |
;------- Which and Leader Keys -------\
(with-eval-after-load 'hydra
(with-eval-after-load 'general
(mf/general-keys
"t" '(:ignore t :wk "toggles")
"ts" '(hydra-text-scale/body :wk "scale text")
"tl" '(display-line-numbers-mode :wk "line-numbers")
"tP" '(visual-fill-column-mode :wk "padding")
"tp" '(mf/toggle-visual-fill-column-width :wk "vc-width")
"tt" '(mf/toggle-frame-transparency :wk "transparency")
"tT" '(mf/toggle-theme :wk "theme")
;; Find
"f" '(:ignore t :wk "find")
"ff" '(hydra-find-file/body :wk "find file")
"fc" '(hydra-find-config/body :wk "find conf.")
"fd" '(hydra-find-dir/body :wk "find dir.")
;; Help
"h" '(help-command :wk "help")
;; Eval
"x" '(:ignore t :wk "eval")
"xe" '(hydra-eval-emacs/body :wk "emacs")
;; Buffer mgmt
"j" '(hydra-switch-buffer/body :wk "switch buffer")
"w" '(hydra-switch-window/body :wk "switch window")
;; Switch to buffer
"m" '(mf/switch-to-messages :wk "*Messages*")
"s" '(scratch-buffer :wk "*scratch*")
"o" '(mf/org-scratch :wk "*org*")
"a" '(mf/org-agenda-overview :wk "agenda")
"A" '(mf/org-agenda-all :wk "agenda")
"?" '(man :wk "man")
"v" '(vterm :wk "vterm")
"/" '(eww :wk "eww")
"g" '(gptel :wk "gptel")
"SPC" '(which-key-show-full-major-mode :wk "which-key"))
(defhydra hydra-text-scale (:timeout 4)
"scale text"
("j" text-scale-increase "in")
("k" text-scale-decrease "out")
("<escape>" nil "finished" :exit t))
(defhydra hydra-find-file (:timeout 4)
"select file"
("e" (find-file (expand-file-name (concat user-emacs-directory "emacs.org")))"emacs.org" :exit t)
("t" (find-file (expand-file-name "~/Org/todo.org"))"todo.org" :exit t)
("b" (find-file (expand-file-name "~/Org/Music/2024.org"))"muisc.org" :exit t)
("m" (find-file (expand-file-name "~/Org/meal_log.org"))"meal_log.org" :exit t)
("M" (find-file (expand-file-name "~/Org/Roam/20231206174633-personal_media_list.org"))"medialist.org" :exit t)
("s" (find-file (expand-file-name "~/Org/Roam/20230829214507-start_here.org"))"roam start" :exit t)
("p" (find-file (expand-file-name "~/Org/Roam/20231213103046-projects.org"))"projects.org" :exit t)
("l" (find-file (expand-file-name "~/Org/links.org"))"links.org" :exit t)
("g" (find-file (expand-file-name "~/Org/toget.org"))"toget.org" :exit t)
("a" (find-file (expand-file-name "~/.config/AIS/readme.org"))"ais.org" :exit t)
("n" (find-file (expand-file-name "~/Org/notes.org"))"notes.org" :exit t)
("r" (find-file (expand-file-name "~/Documents/Recipe_Book/Recipe_Book_2/recipes.org"))"recipes.org" :exit t)
("<escape>" nil "exit" :exit t))
(defhydra hydra-find-config (:timeout 4)
("t" (find-file (concat custom-theme-directory "/doom-mfspacegrey-theme.el"))"theme" :exit t)
("d" (find-file (expand-file-name "~/.config/mf-dwm/config.h"))"dwm" :exit t)
("D" (find-file (expand-file-name "~/.config/mf-dwm/config.def.h"))"dwm" :exit t)
("x" (find-file (expand-file-name "~/.xinitrc"))".xinitrc" :exit t)
("r" (find-file (expand-file-name "~/.Xresources"))".Xresrouces" :exit t)
("<escape>" nil "exit" :exit t))
(defhydra hydra-find-dir (:timeout 4)
"select dir"
("e" (dired (expand-file-name user-emacs-directory))"emacs" :exit t)
("c" (dired (expand-file-name "~/Code"))"Code" :exit t)
("l" (dired (expand-file-name "~/.local/bin"))".local" :exit t)
("o" (dired (expand-file-name org-directory))"Org" :exit t)
("C" (dired (expand-file-name "~/.config"))"Config" :exit t)
("p" (dired (expand-file-name "~/Documents/PDFs"))"PDFs" :exit t)
("<escape>" nil "exit" :exit t))
(defhydra hydra-switch-buffer (:timeout 4)
"switch buffer"
("j" (switch-to-next-buffer)"next")
("k" (switch-to-prev-buffer)"previous")
("n" (lambda ()
(interactive)
(split-window-right)
(windmove-right))"v. split")
("N" (lambda ()
(interactive)
(split-window-below)
(windmove-down)) "h. split")
("q" (delete-window)"close")
("Q" (kill-this-buffer)"kill")
("c" (lambda ()
(interactive)
(delete-window)
(kill-this-buffer))"c & k")
("<escape>" nil "exit" :exit t))
(defhydra hydra-switch-window (:timeout 4)
"switch window"
("j" (other-window 1)"next")
("k" (other-window -1)"previous")
("n" (lambda ()
(interactive)
(split-window-right)
(windmove-right))"v. split")
("N" (lambda ()
(interactive)
(split-window-below)
(windmove-down)) "h. split")
("q" (delete-window)"close")
("Q" (kill-this-buffer)"kill")
("c" (lambda ()
(interactive)
(delete-window)
(kill-this-buffer))"c & k")
("<escape>" nil "exit" :exit t))
(defhydra hydra-eval-emacs (:timeout 4)
("i" (load-file user-init-file)"init.el" :exit t)
("<escape>" nil "exit" :exit t))
(defun mf/switch-to-messages ()
(interactive)
(switch-to-buffer "*Messages*"))
(defun mf/switch-to-org ()
(interactive)
(switch-to-buffer "*org*"))
))
One of these days I’m gonna get organazized.
Function/Package | Description |
---|---|
org | org-mode |
mf/org-mode-setup | Diminish indent mode, and add indent features |
Base Package
;--------------------------------- Org Mode ---------------------------------;
(use-package org
:pin org
:diminish 'org-indent-mode
:init
(setq org-todo-keywords
'((type "TODO(t)" "NEXT(n)" "|" "DONE(d!)" "HOLD(h)")))
(defun mf/org-mode-setup ()
(setq evil-auto-indent nil
org-adapt-indentation t
org-pretty-entities t
org-hide-emphasis-markers t
org-startup-with-inline-images t
org-image-actual-width '(600)))
:custom (org-directory "~/Org")
:commands (org-capture org-agenda)
:hook (org-mode . mf/org-mode-setup)
:config (setq org-startup-folded t
org-log-agenda-start-with-log-mode t
org-display-remote-inline-images 'cache
org-log-done 'time
org-log-into-drawer t)
:bind (("C-c a" . org-agenda)
("C-c L" . org-store-link)
("C-c c" . org-capture)))
Open info https:
strings locally if called from emacs
Options:
- advise org-open-at-point
(with-eval-after-load 'org
(defun mf/https-info-to-info-emacs (url)
"Convert an Emacs HTTPS Info URL and open the corresponding Info node."
(if (string-match "^https://www.gnu.org/software/emacs/manual/html_node/\\([^/]+\\)/\\([^/]+\\)\\.html$" url)
(let ((dir (match-string 1 url))
(node (match-string 2 url)))
(info dir)
(Info-goto-node node))
(message "This is not an 'Emacs Info' https: url")))
)
;; (defun mf/org-info-link-setup
;; (when (string-equal (file-name-directory (buffer-file-name))
;; (expand-file-name user-emacs-directory))
;; (advice-add org-open-link-a)
;; (add-hook 'org-mode-hook #'mf/org-info-link-setup)
Move header
and contents
at cursor to header
in archive.org or and save all org buffers
;--------------------------- Archive DONE Headers ---------------------------;
(with-eval-after-load 'org
(setq org-refile-targets
'(("archive.org" :maxlevel . 1)
("tasks.org" :maxlevel . 1)))
(advice-add 'org-refile :after 'org-save-all-org-buffers))
TODO - restrict to keybind so no evil state check?
org-cycle
does nothing if the cursor is at the beginning of an empty line
(defun org-cycle-leave-empty-line (orig-fun &rest args)
"Advice to prevent org-cycle from doing anything when at the beginning of an empty line."
(if (and (evil-normal-state-p)
(not (eq this-command 'org-shifttab))
(looking-at "^[[:space:]]*$"))
nil
(apply orig-fun args)))
(advice-add 'org-cycle :around #'org-cycle-leave-empty-line)
;; (with-eval-after-load 'org
;; (with-eval-after-load 'evil
;; (defun mf/org-cycle ()
;; "Advice to prevent org-cycle from doing anything when at the beginning of an empty line."
;; (interactive)
;; (if (looking-at "^[[:space:]]*$")
;; nil
;; (org-cycle)))
;; (evil-define-key 'normal org-mode-map "TAB" 'mf/org-cycle)
Enlarge the top two headers
(defun mf/org-headers ()
"Stop the org-level headers from increasing in height relative to the other text."
(dolist (face '(org-level-1
org-level-2
))
(set-face-attribute face nil :weight 'semi-bold :height 1.12)))
(add-hook 'org-mode-hook #'mf/org-headers)
Make id:
Links green and file:
links red
TODO:
- Underline different links with different color
- From stack exchange
- Schemes Chance face color - n options change underline color - n options, more subtle remove underline conditionally - 2 options
(with-eval-after-load 'doom-themes
(with-eval-after-load 'org
(defface org-link-id
'((t :inherit 'org-link
:weight bold
:underline "#50fa7b"))
"Face for Org-Mode links starting with id:."
:group 'org-faces)
(defface org-link-file
'((t :inherit 'org-link
:weight bold
:underline "#ff5555"))
"Face for Org-Mode links starting with file:."
:group 'org-faces)
(org-link-set-parameters
"id"
:face 'org-link-id)
(org-link-set-parameters
"file"
:face 'org-link-file)))
;; (defun mf/after-load-theme (&optional no-confirm no-enable)
;; (run-hooks 'after-load-theme-hook)
;; (mf/org-mode-setup-link-faces))
;; (advice-add 'load-theme :after #'mf/after-load-theme)
Display the link target in the minibuffer when cursor is on an org link
(defun mf/show-org-link-target ()
"Show the link target in the minibuffer when the cursor is on an Org link."
(interactive)
(when (eq major-mode 'org-mode)
(let ((element (org-element-context)))
(when (and element (eq (org-element-type element) 'link))
(message "%s" (org-element-property :raw-link element))))))
(add-hook 'post-command-hook 'mf/show-org-link-target)
https://lucidmanager.org/productivity/ricing-org-mode/ thank you once again minad https://github.com/minad/org-modern
Prettify tables, keywords and babel blocks
(use-package org-modern
:after org
:hook
(org-mode . global-org-modern-mode)
:custom
(org-modern-star nil)
(org-modern-hide-stars nil))
;; (org-modern-keyword t)
;; (org-modern-checkbox t)
;; (org-modern-table t))
https://github.com/gaoDean/org-remoteimg
Replace with org-yt and funcs
(use-package org-remoteimg
:defer (not (daemonp))
:straight (org-remoteimg :type git :host github :repo "gaoDean/org-remoteimg"))
;------- Org Buillets -------\
(use-package org-bullets
:after org
:hook (org-mode . org-bullets-mode))
Package | Description |
---|---|
org-bullets | Hide all but one header asterisk and stylize |
TODO: REPLACE with Dabarev and corfu
;; (use-package company-org-block
;; :custom
;; (company-org-block-edit-style 'auto) ;; 'auto, 'prompt, or 'inline
;; :hook ((org-mode . (lambda ()
;; (setq-local company-backends '(company-org-block))
;; (company-mode +1)))))
company-org-block | Code block completion after ‘<’, plan to implement or fork |
Automatic Table of Contents
make header called * <name> :toc:
;------- Org TOC -------\
;; (use-package toc-org
;; :commands toc-org-enable
;; :init (add-hook 'org-mode-hook 'toc-org-enable))
GitHub - legalnonsense/elgantt: A Gantt Chart (Calendar) for Org Mode Creating Gantt charts by Exporting to TaskJuggler
(use-package elgantt
;; :defer (not (daemonp))
:straight (elgantt :type git :host github :repo "legalnonsense/elgantt")
:init (setq elgantt-agenda-files (concat user-emacs-directory "straight/repos/elgantt/test.org")))
;; (use-package org-ql)
;; ;; :after elgant)
;; (use-package ts)
;; ;; :after elgant)
;; (use-package s)
;; ;; :after elgant)
;; (use-package dash)
;; ;; :after elgant)
Func to convert existing links
Insert link from clipboard and fetch HTML title for the description
;; (defun mf/org-web-tools-insert-link-for-url-dwim ()
;; "Insert org link if HTML url at point otherwise from clipboard."
;; (interactive)
;; (if-let ((url (thing-at-point 'url)))
;; (let ((htmlurl (thing-at-point 'url)))
;; (message "Extracted URL: %s" htmlurl)
;; (org-web-tools-insert-link-for-url htmlurl)
;; (delete-region (car (bounds-of-thing-at-point 'url))
;; (cdr (bounds-of-thing-at-point 'url))))
;; (progn
;; (message "No URL found at point.")
;; (org-web-tools-insert-link-for-url))))
;; (let ((list (org-web-tools--get-first-url)))
;; (insert (org-web-tools--org-link-for-url url)))
(use-package org-web-tools
:after org
:bind (:map org-mode-map
("C-c l" . org-web-tools-insert-link-for-url)))
;; ("C-c l" . mf/org-web-tools-insert-link-for-url-dwim)))
TODO - Conservative tangles on special save, daemon load, kill or some interval or other trigger
Org babel supports code blocks and regular org elements together, compile the code from the blocks, display results and/or “tangle” the code blocks into specified files.
;-------------------------------- Org Babel --------------------------------;
(with-eval-after-load 'org
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(C . t)
(haskell . t)))
(defun mf/org-babel-tangle-config ()
(when (string-equal (file-name-directory (buffer-file-name))
(expand-file-name user-emacs-directory))
(let ((org-confirm-babel-evaluate nil))
(org-babel-tangle))))
(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'mf/org-babel-tangle-config))))
Function/Package | Description |
---|---|
mf/org-babel-tangle-config | After-save hook to babel tangle to init files |
Make an org buffer that has a c code block that exports results
(with-eval-after-load 'org
(defun mf/org-scratch ()
"Create an Org mode scratch buffer."
(interactive)
(let ((org-buffer (get-buffer "*org*")))
(if org-buffer
(if (not (eq (current-buffer) org-buffer))
(switch-to-buffer org-buffer)
(message "We're already there"))
(let ((new-buffer (get-buffer-create "*org*")))
(with-current-buffer new-buffer
(org-mode) ; starting ealy prevents folding
(insert "* C\n"
"\n"
"#+begin_src C :includes <stdio.h> :exports results\n"
"\n"
"\n"
"\n"
"#+end_src\n"
"\n"
"#+RESULTS:"
"\n"
"\n"
"\n"
"\n"
"* Haskell\n"
"\n"
"#+begin_src haskell :exports results\n"
"\n"
"\n"
"\n"
"#+end_src\n"
"\n"
"#+RESULTS:\n"
"\n")
(mf/header-quote "*org*")
(topspace-mode 1)
(set-buffer-modified-p nil)
(switch-to-buffer new-buffer)
))))))
org-ref look at zotura
Initialize org-capture-templates
;-------------------------- Org Capture Templates --------------------------;
(with-eval-after-load 'org
(setq org-capture-templates '())
(add-to-list 'org-capture-templates
`("j" "Journal Entries"))
(add-to-list 'org-capture-templates
`("jj" "Journal" entry
(file+olp+datetree ,(concat (file-name-as-directory org-directory) "journal.org"))
"\n* %<%I:%M %p>\n\n%?\n\n"
:empty-lines 1))
(add-to-list 'org-capture-templates
`("jt" "Trip Journal" entry
(file+olp+datetree ,(concat (file-name-as-directory org-directory) "trip_journal.org"))
"\n* %<%I:%M %p>\n\n%?\n\n"
:empty-lines 1))
;; Today's date
;; (add-to-list 'org-capture-templates
;; `("m" "Meal Plan" entry
;; (file ,(concat (file-name-as-directory org-directory) "meal_log.org"))
;; "* %<%Y-%m-%d %A>\n** Meal One\n*** Pre-Meal\n*** Meal\n** Meal Two\n*** Pre-Meal\n*** Meal\n** Meal Three\n*** Pre-Meal\n*** Meal\n"))
(defun org-capture-meal-plan-template ()
"Return a capture template for meal planning with tomorrow's date."
(let ((date
(format-time-string "%Y-%m-%d %A" (time-add (current-time) (seconds-to-time 86400)))))
(concat "* " date "\n"
"** Meal One\n"
"*** Pre-Meal\n"
"*** Meal\n"
"** Meal Two\n"
"*** Pre-Meal\n"
"*** Meal\n"
"** Meal Three\n"
"*** Pre-Meal\n"
"*** Meal\n")))
(add-to-list 'org-capture-templates
`("m" "Meal Plan" entry
(file ,(concat (file-name-as-directory org-directory) "meal_log.org"))
(function org-capture-meal-plan-template)))
)
TODO - replace with daberev?
Tempo enables electric TAB keyword to template expansion
;------- Tempo Templates -------\
(with-eval-after-load 'org
(require 'org-tempo)
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("eli" . "src emacs-lisp :tangle ./init.el"))
(add-to-list 'org-structure-template-alist '("elg" . "src emacs-lisp :tangle ./mf-gui.el"))
(add-to-list 'org-structure-template-alist '("elk" . "src emacs-lisp :tangle ./mf-keys.el"))
(add-to-list 'org-structure-template-alist '("elo" . "src emacs-lisp :tangle ./mf-org.el"))
(add-to-list 'org-structure-template-alist '("elt" . "src emacs-lisp :tangle ./mf-templates.el"))
(add-to-list 'org-structure-template-alist '("els" . "src emacs-lisp :tangle ./mf-sh.el"))
(add-to-list 'org-structure-template-alist '("cc" . "src C :exports results"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(add-to-list 'org-structure-template-alist '("b" . "src bash :tangle ./ais_tangled.sh"))
(tempo-define-template "org-recipe"
'( "** "p n n
"*** Meta:" n n
" Dificulty : " n
" Time : " n
" Time Cooking : " n
" Servings : " n
" Equipment : "n n
"*** Ingredients:"n n
" | Ingredient | Amount |" n
" |------------+--------|" n
" | | |" n
" | | |" n
" | | |"n n
"*** Instrucions:"n n
" 1. "n n
"*** Notes:"n n
" - " n
)
"<r" "Insert org-recipe" 'org-tempo-tags)
)
Org agenda can aggregate your TODO headers and be used to schedule, track or prioritize tasks
- Set files org agenda pulls TODO headers from
;-------------------------------- Org Agenda --------------------------------; (with-eval-after-load 'org (setq org-agenda-files '( "~/Org/" "~/.config/emacs/emacs.org")) ;; '("~/Org/todo.org" ;; "~/Org/Project_Notes/" ;; "~/Org/tomake.org" ;; "~/Org/toget.org"
Display agenda with
;; (setq org-agenda-prefix-format '((todo . " %i %-12:c")))
;; (setq org-agenda-prefix-format '((todo . " %-4i %-12:c")))
(setq org-agenda-prefix-format '((agenda . " %i %-12:c%?-12t% s")
(todo . " %i %-12:c")
(tags . " %i %-12:c")
(search . " %i %-12:c")))
Variable | Description |
---|---|
%i | todo keyword |
%-12:c | Category left alighted with 12 space padding |
- Display All TODO Headers categorized by Next, Tasks., and Low Priority
(setq org-agenda-custom-commands '(("a" "All" ( ;; (agenda "" ((org-deadline-warning-days 7))) (todo "TDAY" ((org-agenda-overriding-header "Today"))) (todo "NEXT" ((org-agenda-overriding-header "Next Tasks"))) (todo nil ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo '("NEXT" "LOW"))) (org-agenda-overriding-header "Tasks"))) (todo "LOW" ((org-agenda-overriding-header "Low Priority"))))) ("o" "Overview" ( ;; (agenda "" ((org-deadline-warning-days 7))) (todo "TDAY" ((org-agenda-overriding-header "Today"))) (todo "NEXT" ((org-agenda-overriding-header "Next Tasks") (org-agenda-files (file-expand-wildcards "~/Org/*.org")))) (todo "" ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo '("NEXT" "TDAY" "LOW"))) (org-agenda-files (file-expand-wildcards "~/Org/*.org")) (org-agenda-overriding-header "Tasks"))) (todo "LOW" ((org-agenda-overriding-header "Low Priority") (org-agenda-files (file-expand-wildcards "~/Org/*.org")))))) ("w" "Workflow" ((todo "PLAN" ((org-agenda-overriding-header "Plan") (org-agenda-files org-agenda-files))) (todo "DESIGN" ((org-agenda-overriding-header "Design") (org-agenda-files org-agenda-files))) (todo "MAKE" ((org-agenda-overriding-header "Make") (org-agenda-files org-agenda-files)))))))
- Define header tags that agenda can sort by
(setq org-tag-alist '((:startgroup) ;; Put mutually exclusive tags here (:endgroup) ("computer" . ?d) ("learn" . ?l) ("write" . ?r) ("make" . ?f) ("ee" . ?w) ("music" . ?p) ("idea" . ?i)))
Functions for keybinds
(defun mf/org-agenda-overview ()
(interactive)
(org-agenda nil "o"))
(defun mf/org-agenda-all()
(interactive)
(org-agenda nil "a"))
RET
jumps to header
(with-eval-after-load 'evil
(add-hook 'org-agenda-mode-hook
(lambda ()
(define-key evil-normal-state-map (kbd "RET") 'org-agenda-switch-to))))
- End
with-eval-after-load 'org
)
A minimal implementation of Roam in emacs
Package | Description |
---|---|
org-roam | Roam, Zettelkasten for org-mode |
org-roam-consult | Org-roam consult support |
;------- Packages -------\
(use-package org-roam
;; :demand (daemonp)
:after org
:custom
(org-roam-directory (file-truename (expand-file-name (concat org-directory "/Roam/"))))
(org-roam-completion-everywhere t)
(org-roam-capture-templates
'(("p" "plain" plain
"%?"
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
:unnarrowed t)
("d" "Definition" plain
"\n* Definition\n\n - %?"
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
:empty-lines 1
:unnarrowed t)
("D" "Symbols Definition" plain
"#+options: ^:{}\n#+startup: entitiespretty\n* nDefinition\n\n - %?"
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
:unnarrowed t)
("l" "Logic" plain
"#+options: ^:{}\n#+startup: entitiespretty\n\n- A %?\n\n- B "
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
:unnarrowed t)
("r" "Recipe" plain
"#+options: ^:{}\n#+startup: entitiespretty\n\n%?\n\n"
:if-new (file+head "Recipes/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
:unnarrowed t)))
:bind (("C-c n t" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n i" . org-roam-node-insert)
("C-c n c" . mf/roam-set-coherency-property)
:map org-mode-map
("C-TAB" . completion-at-point))
:config
(defun mf/roam-set-coherency-property (value)
"Set the :Coherency property for the current heading."
(interactive "nEnter the Coherency value: ")
(org-set-property "Coherency" (number-to-string value)))
(setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
(org-roam-db-autosync-mode))
(use-package org-roam-ui
;; :demand (daemonp)
:diminish
:after org-roam
:init
(setq org-roam-ui-sync-theme t
org-roam-ui-follow t
org-roam-ui-open-on-start nil
org-roam-ui-update-on-save t
org-roam-ui-open-on-start t
org-roam-ui-browser-function 'browse-url-chromium))
Package | Description |
---|---|
org-roam-ui | Visualizer for org-roam |
org-roam-consult - Org-roam consult support
- Set all keys to start mode
- Configure mode
(use-package consult-org-roam
;; :demand (daemonp)
:diminish
:after org-roam
:commands (org-roam-node-find
consult-org-roam-find
consult-org-roam-backlinks
consult-org-roam-forward-links
consult-org-roam-search)
:init
(require 'consult-org-roam)
;; Activate the minor mode
(consult-org-roam-mode 1)
:custom
(consult-org-roam-grep-func #'consult-ripgrep)
;; Configure a custom narrow key for `consult-buffer'
(consult-org-roam-buffer-narrow-key ?r)
;; Display org-roam buffers right after non-org-roam buffers
;; in consult-buffer (and not down at the bottom)
(consult-org-roam-buffer-after-buffers t)
:config
;; Eventually suppress previewing for certain functions
(consult-customize
consult-org-roam-forward-links
:preview-key "M-.")
:bind
([remap org-roam-node-find] . consult-org-roam-file-find)
("C-c n b" . consult-org-roam-backlinks)
("C-c n l" . consult-org-roam-forward-links)
("C-c n s" . consult-org-roam-search))
TODO - Make Work
;; (require 'json)
;; (defun mf/get-wikipedia-definition (topic)
;; "Get a single line definition of a topic from Wikipedia."
;; (let ((url (format "https://en.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&exintro=true&titles=%s"
;; (url-hexify-string topic))))
;; (url-retrieve url
;; (lambda (status)
;; (when (eq (car status) :ok)
;; (goto-char (point-min))
;; (re-search-forward "\n\n\\({[^}]+}\\)\n\n" nil t)
;; (let ((json-object-type 'plist)
;; (json-key-type 'symbol)
;; (data (json-read)))
;; (if-let ((page (cdr (assq 'pages data)))
;; (page-info (car page)))
;; (message "%s" (cdr (assq 'extract page-info)))
;; (message "Definition not found."))))))))
;; (defun get-wikipedia-info (topic)
;; "Retrieve information about a given TOPIC from Wikipedia."
;; (let* ((url (format "https://en.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&exintro=true&titles=%s" topic))
;; (buffer (url-retrieve-synchronously url))
;; (json-response (with-current-buffer buffer (buffer-string))))
;; (kill-buffer buffer) ; Close the buffer
;; (when json-response
;; (let* ((json-object (json-read-from-string json-response))
;; (page-id (car (mapcar #'cdr (car (cdr (cdr (car (cdr (assoc 'pages json-object)))))))))
;; (extract-info (cdr (assoc 'extract (cdr (assoc page-id (cdr (assoc 'pages json-object))))))))
;; (when extract-info
;; (message "Definition of %s: %s" topic extract-info))))))
A mode to help create recipe documents like a recipe card or book.
(use-package org-chef
:defer (not (daemonp)))
;; :config
;; (add-to-list org-capture-templates
;; '(("c" "Cookbook" entry (file "~/org/cookbook.org")
;; "%(org-chef-get-recipe-from-url)"
;; :empty-lines 1)
;; ("R" "Recipe Entry" entry (file "~/Org/Recipes.org")
;; "* %^{Recipe title: }\n :PROPERTIES:\n :source-url:\n :servings:\n :prep-time:\n :cook-time:\n :ready-in:\n :END:\n** Ingredients\n %?\n** Directions\n\n"))))
- Remove the top bars, scroll bar and turn of tool tip mode
;;--------------------------- General Gui Settings ---------------------------;
(scroll-bar-mode -1)
(menu-bar-mode -1)
(tool-bar-mode -1)
(global-set-key (kbd "<f5>") 'menu-bar-mode)
(tooltip-mode -1)
;------------------------------- Transparency -------------------------------;
(set-frame-parameter nil 'alpha-background 93)
(if (daemonp)
(add-to-list 'default-frame-alist '(alpha-background . 93)))
(defun mf/toggle-frame-transparency ()
"Toggle transparency."
(interactive)
(let ((current-alpha (frame-parameter nil 'alpha-background)))
(cond
((eq current-alpha 88) (set-frame-parameter nil 'alpha-background 93))
((eq current-alpha 93) (set-frame-parameter nil 'alpha-background nil))
(t (set-frame-parameter nil 'alpha-background 88)))))
Set the cursor Set bar in the minibuffer
(setq-default cursor-type 'bar)
;; Change to 3px wide vertical bar
(add-hook 'minibuffer-setup-hook
(lambda ()
(setq-local cursor-type '(bar . 3))))
- Set visual line mode t
- Set line numbers relative for select modes
(global-visual-line-mode t) (column-number-mode t) (global-display-line-numbers-mode t) (setq display-line-numbers-type 'relative) (setq display-line-numbers-width 3) (dolist (mode '(org-mode-hook Info-mode-hook woman-mode-hook helpful-mode-hook Man-mode-hook package-menu-mode-hook term-mode-hook shell-mode-hook eshell-mode-hook vterm-mode-hook eww-mode-hook org-agenda-mode-hook pdf-view-mode-hook)) (add-hook mode (lambda () (display-line-numbers-mode -1)))) (add-hook 'pdf-view-mode-hook (lambda() (linum-mode 0)))
Define the space around the buffer(s).
9 px fringe Set fringe location
(set-fringe-mode 9)
(setq fringes-outside-margins nil)
TODO - Dynamic, use (window-pixel-width-before-size-change) and mf/longest-line-length https://stackoverflow.com/questions/92971/how-do-i-set-the-size-of-emacs-window
Historically 80 chars has been a widely adopted line length guideline, 100 is also somewhat common.
Function | Description |
---|---|
mf/visual-fill-column | Set fill column ‘width’ and ‘center text’ |
visual-fill-column | Add vertical padding around the buffer |
- Truncate package menu lines
(use-package visual-fill-column
:init
(defun mf/visual-fill-column (width center)
"Set visual-fill-column-width and visual-fill-column-center-text."
(interactive "nEnter the width: \nCenter text? (t or nil): ")
(setq visual-fill-column-width width
visual-fill-column-center-text center
visual-fill-column-fringes-outside-margins nil))
(defun mf/toggle-visual-fill-column-width ()
"Toggle between visual fill column widths 75, 100, 150, and 0."
(interactive)
(setq visual-fill-column-width
(cond ((= visual-fill-column-width 75) 100)
((= visual-fill-column-width 100) 150)
((= visual-fill-column-width 150) 0)
(t 75)))
(visual-fill-column-mode 1)
(message "Visual fill column width set to %d" visual-fill-column-width))
(add-hook 'package-menu-mode-hook
(lambda ()
(setq truncate-lines t)
(visual-line-mode -1)))
(mf/visual-fill-column 100 t)
:hook ((visual-line-mode . visual-fill-column-mode)
(Info-mode . (lambda () (mf/visual-fill-column 75 t)))
(minibuffer-setup . (lambda () (mf/visual-fill-column 150 t)))
(package-menu-mode . (lambda () (mf/visual-fill-column 150 t))))
:config
(setq visual-fill-column-center-text t)
(global-visual-fill-column-mode t))
TODO - fix numcoumn hiliting TODO - Possibly strange behaviour when in non-selected buffer is saved, could be “Header Space” section
Add immutable lines to the top of a buffer like word
(defun mf/instert-header-space()
"Add read-only and inaccessible lines at the top of the buffer."
(interactive)
(save-excursion
(goto-char (point-min))
(dotimes (_ 4)
(let ((overlay (make-overlay (point) (point))))
(overlay-put overlay 'before-string (propertize "\n" 'face '(:foreground "nil")))
(overlay-put overlay 'read-only t)
(overlay-put overlay 'invisible t)
(goto-char (overlay-end overlay))))))
(defun mf/insert-header-space-dwim ()
"Idempotnent add read-only and inaccessible lines at the top of the buffer."
(interactive)
(save-excursion
(goto-char (point-min))
(let ((existing-overlays (overlays-in (point-min) (point))))
(unless (cl-some (lambda (overlay)
(and (overlay-get overlay 'read-only)
(overlay-get overlay 'invisible)))
existing-overlays)
(dotimes (_ 4)
(let ((overlay (make-overlay (point) (point))))
(overlay-put overlay 'before-string (propertize "\n" 'face '(:foreground "nil")))
(overlay-put overlay 'read-only t)
(overlay-put overlay 'invisible t)
(goto-char (overlay-end overlay))))))))
(dolist (mode '(org-mode-hook
woman-mode-hook
Info-mode-hook
helpful-mode-hook
prog-mode-hook
text-mode-hook))
(add-hook mode (lambda () (mf/insert-header-space-dwim))))
TODO - Does this move the middle of the screen with C-L
;------- Scrolling -------\
(setq scroll-conservatively 101
scroll-margin 3
;; scroll-step
scroll-preserve-screen-position 't)
Pad all frames with 32p px border
;; (modify-all-frames-parameters '((internal-border-width . 32)))
(use-package topspace
:defer (unless(daemonp))
:hook (dired-mode))
padding just werks stack overflow help https://www.reddit.com/r/emacs/comments/vmcoxz/olivetti/
;; (use-package olivetti
;; :diminish
;; :hook (prog-mode fundamental-mode text-mode info-mode package-menu-mode)
;; :init
;; (setq olivetti-body-width 100)
;; :config
;; (define-globalized-minor-mode olivetti-global-mode olivetti-mode
;; (lambda ()
;; (unless (minibufferp)
;; (olivetti-mode 1)))))
https://github.com/rougier/book-mode
;; (use-package book-mode
;; :config
;; (book-mode 1))
Font | Description |
---|---|
SauceCodePro Nerd Font | Adobe Source Code Pro with Nerd Font Glyphs |
;------- Fonts -------\
(add-to-list 'default-frame-alist '(font . "SauceCodePro Nerd Font-11"))
(set-face-attribute 'default t :font "SauceCodePro Nerd Font-11")
;; (set-face-attribute 'default nil
;; :font "SauceCodePro Nerd Font")
;; (set-face-attribute 'fixed-pitch nil
;; :font "SauceCodePro Nerd Font")
;; from dt
;; (set-face-attribute 'default nil
;; :font "JetBrains Mono"
;; :height 110
;; :weight 'medium)
;; (set-face-attribute 'variable-pitch nil
;; :font "Ubuntu"
;; :height 120
;; :weight 'medium)
;; (set-face-attribute 'fixed-pitch nil
;; :font "JetBrains Mono"
;; :height 110
;; :weight 'medium)
;; ;; Makes commented text and keywords italics.
;; ;; This is working in emacsclient but not emacs.
;; ;; Your font must have an italic face available.
;; (set-face-attribute 'font-lock-comment-face nil
;; :slant 'italic)
;; (set-face-attribute 'font-lock-keyword-face nil
;; :slant 'italic)
;; This sets the default font on all graphical frames created after restarting Emacs.
;; Does the same thing as 'set-face-attribute default' above, but emacsclient fonts
;; are not right unless I also add this method of setting the default font.
;; (add-to-list 'default-frame-alist '(font . "JetBrains Mono-11"))
;; Uncomment the following line if line spacing needs adjusting.
;; (setq-default line-spacing 0.12)
Package | Description |
---|---|
Rainbow-Mode | Render hex-colors as font hilight |
Rainbow-Delimiters | Color parenthesizes |
Emojify | Render Emojis |
;------- GUI Packages -------\
(use-package rainbow-mode
:defer (not (daemonp))
:diminish)
(use-package rainbow-delimiters
:diminish
:hook (prog-mode . rainbow-delimiters-mode))
(use-package ansi-color
:defer (not (daemonp))
:config
(defun display-ansi-colors ()
"Render ansi colors in the current buffer."
(interactive)
(ansi-color-apply-on-region (point-min) (point-max))))
(use-package emojify
:defer (not (daemonp))
;; :demand (daemonp)
:hook (erc-mode . emojify-mode)
:commands emojify-mode)
Tree-sitter provides real-time incremental syntax parsing and font locking (syntax highlighting)
(setq treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
(c "https://github.com/tree-sitter/tree-sitter-c")
(cpp "https://github.com/tree-sitter/tree-sitter-cpp.git")
(cmake "https://github.com/uyha/tree-sitter-cmake")
(css "https://github.com/tree-sitter/tree-sitter-css")
(elisp "https://github.com/Wilfred/tree-sitter-elisp")
(go "https://github.com/tree-sitter/tree-sitter-go")
(haskell "https://github.com/tree-sitter/tree-sitter-haskell")
(html "https://github.com/tree-sitter/tree-sitter-html")
(javascript "https://github.com/tree-sitter/tree-sitter-javascript")
(json "https://github.com/tree-sitter/tree-sitter-json")
(make "https://github.com/alemuller/tree-sitter-make")
(markdown "https://github.com/ikatyang/tree-sitter-markdown")
(python "https://github.com/tree-sitter/tree-sitter-python")
(toml "https://github.com/tree-sitter/tree-sitter-toml")
(regex "https://github.com/tree-sitter/tree-sitter-regex")
(yaml "https://github.com/ikatyang/tree-sitter-yaml")))
(setq major-mode-remap-alist
'(((c-mode . c-ts-mode)
(cpp-mode . cpp-ts-mode)
(css-mode . css-ts-mode)
(elisp-mode . elisp-ts-mode)
(haskell-mode . haskell-ts-mode)
(html-mode . html-ts-mode)
(makefile-mode . make-ts-mode)
(python-mode . python-ts-mode))))
TODO - Add topspace TODO - https://lucidmanager.org/productivity/manage-files-with-emacs/ TODO - Fix omit mode TODO - move to trash and rm functionality
Package | Description |
---|---|
Dired | DIR EDitor |
Load dired omit mode settings
(use-package dired
:ensure nil
:commands (dired dired-jump)
:bind (("C-x C-j" . dired-jump))
:custom ((dired-listing-switches "-agho --group-directories-first")))
(autoload 'dired-omit-mode "dired-x")
Dired Jump
(use-package dired-single
:commands (dired dired-jump))
(use-package dired-ranger
:after dired
:defer (not (daemonp)))
(use-package dired-collapse
:after dired
:defer (not (daemonp)))
Package | Description |
---|---|
Dired Single | Dired Jump opens current buffer in dired (implement?) |
Dired Hacks | Proveds Dired-Ranger and Dired-Collapse |
Dired Ranger | Ranger Features in Dired |
(use-package perspective
:defer (not (daemonp))
;; :demand (daemonp)
:custom
(persp-mode-prefix-key (kbd "C-x x"))
:bind (("C-x k" . persp-kill-buffer*)
("C-x x d" . persp-ibuffer)
("C-M-j" . persp-switch-to-buffer*))
:init
(persp-mode))
Package | Description |
---|---|
Perspecitve | Group buffers in to perspectives |
TODO - Cleanup
- Unload themes before loading a theme
(define-advice load-theme (:before (&rest _args) theme-dont-propagate) "Discard all themes before loading new." (mapc #'disable-theme custom-enabled-themes))
- Set custom theme dir
- Load theme except in terminal mode
;---------------------------------- Theme ----------------------------------;
(setq custom-theme-directory (concat user-emacs-directory "themes"))
(defvar my-bell-color "#000")
(defun mf/set-bell-color ()
(setq my-bell-color (doom-color 'error))
)
(when (or (display-graphic-p)(daemonp))
(defun mf/load-theme ()
"Load themes based on variables."
(interactive)
(require 'mlscroll)
(if (mf/after-specific-time 18 30)
(load-theme dark-theme t)
(progn (load-theme light-theme t)
(set-frame-parameter nil 'alpha-background 100)))
(mf/set-bell-color)
(mf/mlscroll-setup))
;; (use-package timu-spacegrey-theme)
(use-package doom-themes
:config
(setq doom-homage-white-padded-modeline nil)
;; (load-theme 'doom-mfspacegrey t)
(setq light-theme 'doom-homage-white)
(setq dark-theme 'doom-mfspacegrey)
(if (daemonp)
(add-hook 'server-after-make-frame-hook #'mf/load-theme)
(mf/load-theme)))
(defun mf/toggle-theme ()
(interactive)
(if (memq light-theme custom-enabled-themes)
(progn
(load-theme dark-theme t)
(mf/set-bell-color)
(mf/mlscroll-setup)
(set-frame-parameter nil 'alpha-background 93)
(message "Switched to dark theme"))
(progn
(load-theme light-theme t)
(mf/set-bell-color)
(mf/mlscroll-setup)
(set-frame-parameter nil 'alpha-background 100)
(message "Switched to light theme")))))
The bar above the Mini-Buffer near bottom of an emacs window is called the modeline. It is configured via the mode-line-format value. https://www.reddit.com/r/emacs/comments/mmqjjw/how_rightalign_items_in_modeline/
;; (setq-default mode-line-format
;; '("%e" evil-mode-line-tag mode-line-front-space
;; (:propertize
;; ("" mode-line-mule-info mode-line-client mode-line-modified mode-line-remote)
;; display
;; (min-width
;; (5.0)))
;; mode-line-frame-identification mode-line-buffer-identification " " mode-line-position
;; (vc-mode vc-mode)
;; " " mode-line-modes mode-line-misc-info mode-line-end-spaces))
;;; Alignment.
;; Fill functions are from <https://github.com/milkypostman/powerline>.
;; (defvar ml-text-scale-factor 1.0
;; "Scale of mode-line font size to default font size, as a float.
;; This is needed to make sure that text is properly aligned.")
;; (defun ml-fill-to-center (reserve face)
;; "Return empty space to the center, leaving RESERVE space on the right."
;; (when ml-text-scale-factor
;; (setq reserve (* ml-text-scale-factor reserve)))
;; (propertize " "
;; 'display `((space :align-to (- (+ center (.5 . right-margin))
;; ,reserve
;; (.5 . left-margin))))
;; 'face face))
;; (defun ml-fill-to-right (reserve face)
;; "Return empty space, leaving RESERVE space on the right."
;; (when ml-text-scale-factor
;; (setq reserve (* ml-text-scale-factor reserve)))
;; (when (and window-system (eq 'right (get-scroll-bar-mode)))
;; (setq reserve (- reserve 2))) ; Powerline uses 3 here, but my scrollbars are narrower.
;; (propertize " "
;; 'display `((space :align-to (- (+ right right-fringe right-margin)
;; ,reserve)))
;; 'face face))
;; (defun ml-render-2-part (left right &optional fill-face)
;; (concat left
;; (ml-fill-to-right (string-width (format-mode-line right)) fill-face)
;; right))
;; (defun ml-render-3-part (left center right &optional fill-face)
;; (concat left
;; (ml-fill-to-center (/ (string-width (format-mode-line center)) 2.0) fill-face)
;; center
;; (ml-fill-to-right (string-width (format-mode-line right)) fill-face)
;; right))
;; (defun my-mode-line-format ()
;; "Construct the mode-line with custom alignment."
;; (let* ((left (format-mode-line
;; '("%e" evil-mode-line-tag mode-line-front-space
;; (:propertize ("" mode-line-mule-info mode-line-client mode-line-modified mode-line-remote)
;; display (min-width (5.0)))
;; mode-line-frame-identification mode-line-buffer-identification " " mode-line-position
;; (vc-mode vc-mode))))
;; (right (format-mode-line
;; '(" " mode-line-modes)))
;; (misc (format-mode-line
;; 'mode-line-misc-info)))
;; (concat left
;; (ml-fill-to-right (+ (string-width right) (string-width misc)) nil)
;; right
;; misc)))
;; (setq-default mode-line-format '((:eval (my-mode-line-format))))
Package | Description |
---|---|
Diminish | Hide selected modes from modeline |
mlscroll | Scroll indicator for modeline |
- Set Vim layer indicator faces
- Flash Mode-Line instead of ring bell
;------- Modeline -------\
(use-package diminish
:config
(diminish 'hs-minor-mode)
(diminish 'visual-line-mode)
(diminish 'eldoc-mode)
(diminish 'abbrev-mode))
(use-package mlscroll
;; :defer (unless (display-graphic-p))
:hook (server-after-make-frame . mlscroll-mode)
:config
(defun mf/mlscroll-setup ()
"Set mlscroll faces to doom colors."
(interactive)
(setq mlscroll-out-color (doom-color 'bg)
mlscroll-in-color (doom-color 'fg)))
(mlscroll-mode 1)
(mf/mlscroll-setup))
(with-eval-after-load 'evil
(setq evil-normal-state-tag
(propertize " <N> " 'face '((:background "DarkGoldenrod2" :foreground "black")))
evil-emacs-state-tag
(propertize " <E> " 'face '((:background "SkyBlue2" :foreground "black")))
evil-insert-state-tag
(propertize " <I> " 'face '((:background "chartreuse3" :foreground "black")))
evil-replace-state-tag
(propertize " <R> " 'face '((:background "chocolate" :foreground "black")))
evil-motion-state-tag
(propertize " <M> " 'face '((:background "plum3" :foreground "black")))
evil-visual-state-tag
(propertize " <V> " 'face '((:background "gray" :foreground "black")))
evil-operator-state-tag
(propertize " <O> " 'face '((:background "sandy brown" :foreground "black")))))
(with-eval-after-load 'doom-themes
(setq ring-bell-function
(lambda ()
(let ((orig-fg (face-foreground 'mode-line)))
;; (set-face-foreground 'mode-line "#000")
(set-face-foreground 'mode-line my-bell-color)
;; (set-face-foreground 'mode-line "#fd5300")
(run-with-idle-timer 0.1 nil
(lambda (fg) (set-face-foreground 'mode-line fg))
orig-fg)))))
Thank you
- Daviwil & System Crafters; Videos series, shownotes, IRC
- Daniel Mendler @ Minad; Many integrated light weight modular emacs packages
- Doom & Spacemacs; Config framework projects
Also https://gitlab.com/dwt1/configuring-emacs https://protesilaos.com/emacs/dotemacs https://github.com/hrs/dotfiles/blob/main/emacs/.config/emacs/configuration.org
windows nt