From: rearman Date: Thu, 13 Jun 2024 19:34:23 +0000 (-0400) Subject: Change initialization meta X-Git-Url: https://git.earman.xyz/?a=commitdiff_plain;h=3f44e3b41c8f3174ceea5e810119e28dab9c6aaa;p=emacsinit.git Change initialization meta Avoid issues when doing a git pull that is not the first clone, having to play games with --[no]-assume-unchanged, etc. 1. Change init.org to config.org, and set up init.el to tangle that file. 2. Track early-init.el, so that it gets run on first startup. a. Keep the tangling section for this file in config.org for central editing. --- diff --git a/.gitignore b/.gitignore index e54eec0..2ef0788 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,8 @@ auto-save-list/ abbrev_defs bookmarks +config.el custom.el -early-init.el eln-cache/ elpa/ eshell/ diff --git a/README.org b/README.org index 4e5814b..60bfc2c 100644 --- a/README.org +++ b/README.org @@ -1,2 +1,2 @@ * README -This is my emacs init. See init.org for more. +This is my emacs init. See [[file:~/.emacs.d/config.org][config.org]] for more. diff --git a/config.org b/config.org new file mode 100644 index 0000000..ca79e6d --- /dev/null +++ b/config.org @@ -0,0 +1,1500 @@ +#+TITLE: Emacs Configuratione +#+PROPERTY: header-args:emacs-lisp :tangle yes :results silent :export code + +* Introduction +This is my emacs configuration. It is meant to be used across linux, windows, and BSD. I use windows only at work (Industrial Controls). I use emacs often as an advanced programmable calculator. + +Lots of inspiration taken from: +- [[https://depp.brause.cc/dotemacs/][depp.brause.cc/dotemacs/]] +- [[https://github.com/larstvei/dot-emacs][github.com/larstvei/dot-emacs]] +- [[https://github.com/sachac/.emacs.d][github.com/sachac/.emacs.d]] + +** A note on version checking +I keep my emacs installs at the latest release, so I don't worry about checking for versions in my init unless I happen to update on linux/BSD before the windows binaries are released. That being said, I am currently on version 29.3. +** Latinization +I believe that all scientific knowledge, and by extension computational knowledge, should be shared in Latin. That is to say I intend to facilitate Latin's return as the default language for global knowledge sharing. To be consistent, I will soon be translating as much of this file as possible into Latin. Monitus es. +* Meta Configuration +I have changed the meta. I no longer overwrite the init.el, instead opting to have the init.el tangle this file. +* Early init +This file was introduced in Emacs 27. I use it for speeding up init, removing all the UI stuff I don't want, etc. Maybe superfluous, but I do get startup times on the order of /0.015/ seconds on Windows. +** The normal header +There are no GNU Police (yet), but I feel nicer by adding this in. +#+BEGIN_SRC emacs-lisp :tangle ./early-init.el +;;; early-init.el -*- lexical-binding: t; -*- + +;; Haec pars Emacs non est. + +;; Code: +#+END_SRC + +** GC thrashing +Set the GC threshold to max during startup, then set it back to a value that is somewhat more sane than the default /800kb/. + +#+BEGIN_SRC emacs-lisp :tangle ./early-init.el +(setq gc-cons-threshold most-positive-fixnum + gc-cons-percentage 0.6) + +(add-hook 'after-init-hook #'(lambda () (setq gc-cons-threshold (* 1024 1024 25) + gc-cons-percentage 0.1))) +#+END_SRC + +** Basic UI preferences +I want no menus, no tool-bars, no blinking cursor, no messages when starting up, and to make resizing work properly. I just want the scratch buffer with a report on =emacs-init-time=. +#+BEGIN_SRC emacs-lisp :tangle ./early-init.el +(menu-bar-mode -1) +(tool-bar-mode -1) +(blink-cursor-mode -1) + +(setq inhibit-startup-screen t + inhibit-startup-buffer-menu t + server-client-instructions nil + frame-resize-pixelwise t + initial-scratch-message (message ";;; Emacs loaded in %s.\n\n" (emacs-init-time))) +#+END_SRC + +** Misc/odd issues +Avoid a weird issue on windows where opening emacs via an [[https://www.autohotkey.com/][AutoHotKey]] binding causes emacs to load in the AutoHotKey directory. + +#+BEGIN_SRC emacs-lisp :tangle ./early-init.el +(setq default-directory "~/") +#+END_SRC + +** The normal footer + +#+BEGIN_SRC emacs-lisp :tangle ./early-init.el +(provide 'early-init) +;;; hic terminatur early-init.el +#+END_SRC + +* Main init +** Header +#+BEGIN_SRC emacs-lisp +;;; config.el --- Quae configurare -*- lexical-binding: t; -*- + +;; Haec pars Emacs non est. + +;; Code: +#+END_SRC + +** Packages +Load packages first, so there is no question about dependencies later in the file. +*** Package Repositories +Non-gnu is in the defaults now, so I only need to add melpa. +#+BEGIN_SRC emacs-lisp +(require 'package) +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) +#+END_SRC + +*** Ledger-mode +Accounting +#+BEGIN_SRC emacs-lisp +(use-package ledger-mode + :ensure t + :defer t + :bind + ((:map ledger-mode-map ("C-c s" . ledger-sort-buffer)))) +#+END_SRC + +*** visual-fill-column +A godsend. Finally, I can have visual-line-mode without having to read lines that are 1980 pixels wide! Also set word wrap, and make the split for help do what I want on big screens. +#+BEGIN_SRC emacs-lisp +(use-package visual-fill-column + :ensure t + :config + (global-visual-line-mode 1) + :custom + (word-wrap t) + (visual-fill-column-enable-sensible-window-split t)) +#+END_SRC + +Also make a defun/binding to toggle it as needed. +#+BEGIN_SRC emacs-lisp +(defun re/toggle-visual-fill-column-mode () +"Toggles `visual-fill-column-mode." + (interactive) + (visual-fill-column-mode 'toggle)) + +(keymap-global-set "C-c v" 're/toggle-visual-fill-column-mode) + +#+END_SRC + +*** corfu +I used =company-mode= for a long time. I tried corfu and haven't looked back. It is smaller, and does everything I was doing with company. + +**** Main Corfu +The basics for corfu. Auto popup after one letter, enable globally. +#+BEGIN_SRC emacs-lisp +(use-package corfu + :ensure t + :custom + (corfu-auto t) + (corfu-auto-delay 0) + (corfu-auto-prefix 1) + :config + (global-corfu-mode)) +#+END_SRC + +**** corfu-popupinfo +This comes with base corfu, but is configured separately. +#+BEGIN_SRC emacs-lisp +(use-package corfu-popupinfo + :ensure nil ; Part of corfu + :after corfu + :hook (corfu-mode . corfu-popupinfo-mode) + :custom + (corfu-popupinfo-delay '(nil . 0.01)) + (corfu-popupinfo-hide nil) + :config + (corfu-popupinfo-mode)) + ;; :bind + ;; ((:map corfu-map ("C-h" . corfu-popupinfo-toggle)))) +#+END_SRC + +*** expand-region +Seldom used, but nothing else does it. +#+BEGIN_SRC emacs-lisp +(use-package expand-region :ensure t) +(keymap-global-set "C-=" 'er/expand-region) +#+END_SRC + +*** magit +I use magit occasionally. I put this sparse configuration here mostly for a speed boost, by making magit only load when I explicitly call for it. +#+BEGIN_SRC emacs-lisp +(use-package magit + :ensure t + :config + (message "Magit Loaded") + :bind + ((:map ctl-x-map ("g" . magit-status)))) +#+END_SRC + +*** Recentf +#+BEGIN_SRC emacs-lisp +(use-package recentf + :ensure t + :config + (recentf-mode 1)) + +(keymap-global-set "C-c r" 'recentf-open) +#+END_SRC + +*** openwith +I need to open binary files with their own editor. Disgusting. +#+BEGIN_SRC emacs-lisp +(use-package openwith + :ensure t + :custom + (openwith-associations (list + (list (openwith-make-extension-regexp + '("xls" "xlsx" "doc" "docx" + "ppt" "odt" "ods" "odg" "odp")) + "LibreOffice" + '(file)) + (list (openwith-make-extension-regexp + '("adpro")) + "ProductivitySuite" + '(file)))) + :config + (openwith-mode t)) +#+END_SRC + +*** acme-mouse +Not a package in the strict sense, just a .el file loaded as a git submodule - forked from [[https://github.com/akrito/acme-mouse/]] to [[https://github.com/rearman/acme-mouse/]] and modified to meet changes to the old =cl= package, and to fix the ~mouse-3~ search function. Also see the [[id:451a20e6-73a0-4d55-aeaa-e795980a6974][Maus]] section. +#+BEGIN_SRC emacs-lisp +(add-to-list 'load-path (concat user-emacs-directory "acme-mouse/")) +(require 'acme-mouse) +#+END_SRC + +*** AUCTeX +Starting to do some work with LaTeX, surprised this is not in base, but org is. +#+BEGIN_SRC emacs-lisp +(use-package auctex + :ensure t + :defer t) +#+END_SRC + +*** SLIME +Lisp me...sometimes. +#+BEGIN_SRC emacs-lisp +(let ((slime-help "~/quicklisp/slime-helper.el")) + (when (file-exists-p slime-help) + (load (expand-file-name slime-help)) + (setq inferior-lisp-program "sbcl") + (use-package slime + :ensure t + :custom + (slime-net-coding-system 'utf-8-unix)) + (when (file-exists-p "~/lisp/sbcl.core-for-slime") + (setq slime-lisp-implementations + '((sbcl ("sbcl" "--core" "sbcl.core-for-slime") + :directory "~/lisp")))) + (add-hook 'slime-mode-hook + (lambda () + (unless (slime-connected-p) + (save-excursion (slime))))))) +#+END_SRC + +** Non-Package customization +This section has '/base/' emacs customization. All the general stuff. +*** Defaults +I want these things every time, or at least setting them this way worked when a regular =setq= didn't. +#+BEGIN_SRC emacs-lisp +(setq-default indicate-empty-lines t + fill-column 80 + cursor-type 'bar + cursor-in-non-selected-windows 'hollow) +#+END_SRC +*** Help +Set up apropos to be more useful. +#+BEGIN_SRC emacs-lisp +(setq apropos-do-all t) +#+END_SRC + +*** UTF-8 +Force emacs to use UTF-8 so I avoid prompts on save. +#+BEGIN_SRC emacs-lisp +(set-language-environment 'utf-8) +(set-default-coding-systems 'utf-8) +(set-keyboard-coding-system 'utf-8-unix) +(set-terminal-coding-system 'utf-8-unix) +#+END_SRC + +*** Backup/Autosave +I originally had some autosave items in here, but the defaults appeared to be doing basically what I wanted anyway. +**** Backups +Make backups for vc-controlled files, don't clobber symlinks, and put everything into =~/emacs-backups/=. +#+BEGIN_SRC emacs-lisp +(setq vc-make-backup-files t + backup-by-copying t + backup-directory-alist `((".*" . "~/emacs-backups/"))) +#+END_SRC + +**** Old versions +Keep 10 versions, 5 'old' and 5 'new'. Delete anything older. +#+BEGIN_SRC emacs-lisp +(setq delete-old-versions t + kept-new-versions 5 + kept-old-versions 5) +#+END_SRC + +*** File handling +**** Final Newline +I want to avoid ever seeing an error about missing newlines at the end of a file. +#+BEGIN_SRC emacs-lisp +(setq require-final-newline t) +#+END_SRC + +**** Auto Revert +When files (or folders in dired) change on disk, and there are no changes in the open buffer, revert to the on-disk version. +#+BEGIN_SRC emacs-lisp +(global-auto-revert-mode t) +(setq global-auto-revert-non-file-buffers t) +#+END_SRC + +**** Segfault recovery +These are directly from [[https://depp.brause.cc/dotemacs/][depp.brause.cc/dotemacs/]]. They are intended to make Emacs drop changes and die when a segfault happens, rather than attempt to save potentially corrupted data. +#+BEGIN_SRC emacs-lisp +(setq attempt-stack-overflow-recovery nil + attempt-orderly-shutdown-on-fatal-signal nil) +#+END_SRC + +**** Whitespace and chmod on save +I want to strip all trailing whitespace on save, and I want to make all shell scripts executable at the same time. +#+BEGIN_SRC emacs-lisp +(add-hook 'before-save-hook 'whitespace-cleanup) +(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p) +#+END_SRC + +*** Minibuffer interaction +I don't want emacs to beep or blink at me, I want y/n instead of the default yes/no, I don't care for clicking on things in the minibuffer, I like seeing things echoed almost immediately, for keystrokes and eldoc. I want eldoc to stick to one line. I want history to only show me unique commands, and I want case-insensitive buffer switching. +#+BEGIN_SRC emacs-lisp +(setq ring-bell-function 'ignore + use-short-answers t + use-file-dialog nil + echo-keystrokes 0.1 + eldoc-idle-delay 0 + eldoc-echo-area-use-multiline-p nil + read-buffer-completion-ignore-case t + history-delete-duplicates t) +#+END_SRC + +*** Buffer interaction +**** General +***** midnight-mode +Close unused buffers after 3 days. +#+BEGIN_SRC emacs-lisp +(midnight-mode t) +#+END_SRC + +***** delete-selection-mode +Overwrite selection when active, like every other editor since Sam. +#+BEGIN_SRC emacs-lisp +(delete-selection-mode t) +#+END_SRC + +***** Don't disable any functions. +#+BEGIN_SRC emacs-lisp +(setq disabled-command-function nil) +#+END_SRC + +***** Inter-program kill-ring +Save pastes from elsewhere into the kill-ring, and don't ask me about killing processes when I kill a buffer. +#+BEGIN_SRC emacs-lisp +(setq save-interprogram-paste-before-kill t + confirm-kill-processes nil) +#+END_SRC + +**** Windmove +:PROPERTIES: +:ID: 1c8d7229-796f-446a-8ae8-247cd6164a12 +:END: +I originally had custom defuns and bindings to do this, but then I found out it was built in... +#+BEGIN_SRC emacs-lisp +(windmove-default-keybindings 'control) +(setq windmove-wrap-around t + windmove-create-window t) +#+END_SRC + +**** Maus +:PROPERTIES: +:ID: 451a20e6-73a0-4d55-aeaa-e795980a6974 +:END: +Don't follow links with mouse-1, so I can select without having to use the keyboard (when I want to). +#+BEGIN_SRC emacs-lisp +(setq mouse-1-click-follows-link nil) +#+END_SRC + +*** Buffer looks +**** Prettify Symbols +I want nice symbols to look at +#+BEGIN_SRC emacs-lisp +(setq prettify-symbols-alist '(("lambda" . 955) + ("delta" . 120517) + ("epsilon" . 120518) + ("->" . 8594) + ("<=" . 8804) + (">=" . 8805))) +(global-prettify-symbols-mode t) +#+END_SRC + +**** Visual Line Mode indicators +Show arrows when a line wraps +#+BEGIN_SRC emacs-lisp +(setq-default visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow)) +#+END_SRC + +**** Scroll Bars +Put my scroll bars where I like them. +#+BEGIN_SRC emacs-lisp +(set-scroll-bar-mode 'left) +#+END_SRC + +*** Parens +When I'm on a beginning/ending paren, I find the default of only highlighting the parens too hard to see, and highlighting the whole thing too garish. Therefore, this setup tries to underline the expression, with minimal highlighting. + +Show matching parens immediately, and "highlight" the whole expression. +#+BEGIN_SRC emacs-lisp +(setq show-paren-delay 0 + show-paren-style 'expression) +#+END_SRC + +Make the paren "highlight" the same color as the background, with no overwrite of foreground color, and add underline. +#+BEGIN_SRC emacs-lisp +(set-face-attribute 'show-paren-match nil + :foreground 'unspecified + :background 'unspecified + :underline t) +#+END_SRC + +*** Modeline +Funny name for the frame +#+BEGIN_SRC emacs-lisp +(setq frame-title-format "Poor Man's LispM") +#+END_SRC + +Show me column number and filesize +#+BEGIN_SRC emacs-lisp +(column-number-mode t) +(size-indication-mode t) +#+END_SRC + +*** C-Style +Please use Tabs in C files, I'm BEGGING. Absolutely ridiculous that there's no simple variable to select Tabs ONLY for indentation. +#+BEGIN_SRC emacs-lisp +(defun re/c-lineup-arglist-tabs-only (ignored) + "Line up argument lists by tabs, not spaces. Stolen from https://kernel.org/doc/html/v4.10/process/coding-style.html" + (let* ((anchor (c-langelem-pos c-syntactic-element)) + (column (c-langelem-2nd-pos c-syntactic-element)) + (offset (- (1+ column) anchor)) + (steps (floor offset c-basic-offset))) + (* (max steps 1) + c-basic-offset))) + +(add-hook 'c-mode-common-hook + (lambda () + ;; Add kernel style + (c-add-style + "linux-tabs-only" + '("linux" + (c-offsets-alist + (arglist-cont-nonempty + c-lineup-gcc-asm-reg + re/c-lineup-arglist-tabs-only)))))) + +(add-hook 'c-mode-hook + (lambda () + (setq indent-tabs-mode t) + (setq show-trailing-whitespace t) + (setq c-backspace-function 'backward-delete-char) ;; don't expand my tabs, just delete them. + (c-set-style "linux-tabs-only"))) +#+END_SRC + +*** Windows-Specific +Use =recycle bin=, DON'T use =AltGr=, and tell emacs where =diff= is. +#+BEGIN_SRC emacs-lisp +(when (equal system-type 'windows-nt) + (setq delete-by-moving-to-trash t + ediff-diff-program "\"c:/Program Files/Git/usr/bin/diff.exe\"" + ediff-diff3-program "\"c:/Program Files/Git/usr/bin/diff3.exe\"" + diff-command "\"c:/Program Files/Git/usr/bin/diff.exe\"" + w32-recognize-altgr 'nil)) +#+END_SRC + +** Defuns and Bindings +I have quite a few math and work-related defuns, and fewer editing ones. Inversely, I have more editing related bindings than work-related ones. This makes sense, considering my usage patterns. +*** Editing +Most of these are to re-create something from vim/readline/sam/acme. Some are just helper functions or wrappers. +**** Visiting Files +Bind ~find-file-at-point~ and ~bookmark-jump-other-window~. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-x M-f" 'find-file-at-point) +(keymap-global-set "C-x r B" 'bookmark-jump-other-window) +#+END_SRC + +**** Undo/redo +I like putting redo on ~C-\~. Easier for me to remember than the ~C-M-_~ default. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-\\" 'undo-redo) +#+END_SRC + +**** Renaming Files +I took this from [[https://whattheemacsd.com][whattheemacsd.com]]. It is occasionally handy. +#+BEGIN_SRC emacs-lisp +(defun re/rename-current-buffer-file () + "Renames the current buffer and the file it is visiting." + (interactive) + (let ((name (buffer-name)) + (filename (buffer-file-name))) + (if (not (and filename (file-exists-p filename))) + (error "Buffer '%s' is not visiting a file!" name) + (let ((new-name (read-file-name "New name: " filename))) + (if (get-buffer new-name) + (error "A buffer named '%s' already exists!" new-name) + (rename-file filename new-name 1) + (rename-buffer new-name) + (set-visited-file-name new-name) + (set-buffer-modified-p nil) + (message "File '%s' successfully renamed to '%s'" + name (file-name-nondirectory new-name))))))) + +(keymap-global-set "C-x C-r" 're/rename-current-buffer-file) +#+END_SRC +**** Buffer Menu +Usually I want the buffer menu in the same window I am already on. Occasionally I want it in a different window. Bind accordingly. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-x C-b" 'buffer-menu) +(keymap-global-set "C-x M-b" 'buffer-menu-other-window) +#+END_SRC + +**** Switch to Scratch +I often want to bring up the scratch buffer in my current window, and sometimes I want only one window that is the scratch buffer. Emacs 29 added the ~scratch-buffer~ function, so one less defun needed here. +#+BEGIN_SRC emacs-lisp +(defun re/scratch-only () + "Bring up the scratch buffer as the only visible buffer." + (interactive) + (scratch-buffer) + (delete-other-windows)) + +(keymap-global-set "" 'scratch-buffer) +(keymap-global-set "S-" 're/scratch-only) +#+END_SRC + +**** Line joining +The ~M-^~ binding is handy, but usually I want the ed/sam/vi join function, which pulls the next line up into the current line. I bind this to ~M-j~. +#+BEGIN_SRC emacs-lisp +(defun re/backward-join-line () + "A wrapper for join-line to make it go in the right direction." + (interactive) + (join-line 0)) + +(keymap-global-set "M-j" 're/backward-join-line) +#+END_SRC + +**** Line opening +The default behavior of =open-line= is ridiculous. It acheives the same function as hitting =RET=. I don't want to split the current line, I want to OPEN a new one, and usually go to it. These wrappers remedy that. + +#+BEGIN_SRC emacs-lisp +(defun re/open-line-below (n) + "Creates a new empty line below the current line and moves to it." + (interactive "*p") + (end-of-line) + (open-line n) + (call-interactively (next-line)) + (indent-for-tab-command)) + +(defun re/open-line-above (n) + "Creates a new empty line above the current line." + (interactive "*p") + (beginning-of-line) + (open-line n) + (indent-for-tab-command)) +#+END_SRC + +I Bind the previous functions to =C-o= and =M-o=. + +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-o" 're/open-line-below) +(keymap-global-set "M-o" 're/open-line-above) +#+END_SRC + +**** Line sorting +Stolen from [[https:github.com/magnars/emacsd-reboot/blob/main/settings/editing.el]] +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-c s" 'sort-lines) +#+END_SRC + +**** Commenting +I stole this directly from [[https://depp.brause.cc/dotemacs][depp.brause.cc/dotemacs]]. Very good, simple solution. +#+BEGIN_SRC emacs-lisp +(defun re/comment-dwim () + "Comment region if active, otherwise comment line. +Stolen from https://depp.brause.cc/dotemacs" + (interactive) + (if (use-region-p) + (comment-or-uncomment-region (region-beginning) (region-end)) + (comment-or-uncomment-region (line-beginning-position) + (line-end-position)))) + +(keymap-global-set "M-;" 're/comment-dwim) +#+END_SRC + +**** Killing +***** Kill Whole Line +Bind =kill-whole-line= to =C-S-K= for something somewhat pnemonic. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-S-K" 'kill-whole-line) +#+END_SRC + +***** Zap up to char +Bind =C-z= to zap-up-to-char, sice zap-to-char is on =M-z=. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-z" 'zap-up-to-char) +#+END_SRC + +***** UNIX C-w, C-u, and C-h +=C-w= is very much engrained for killing back one word, as is =C-u= for killing back to the beginning of the line, and =C-h= for one character back. [[http://unix-kb.cat-v.org/][These have been standard bindings since TENEX...]] +****** =C-w= +I didn't want to re-bind =C-w= away from =kill-region=, so I made it do both. +#+BEGIN_SRC emacs-lisp +(defun re/kill-bword-or-region () + "Kill region if active, otherwise kill back one word." + (interactive) + (if (use-region-p) + (call-interactively 'kill-region) + (call-interactively 'backward-kill-word))) + +(keymap-global-set "C-w" 're/kill-bword-or-region) +#+END_SRC + +****** =C-u= +There is no pre-made function to kill backward to the beginning of line from point, so I made one that passes the correct argument to =kill-line=, and bound it to =C-u=. +#+BEGIN_SRC emacs-lisp +(defun re/backward-kill-line () + "Kill back to beginning of line from point." + (interactive) + (kill-line 0)) + +(keymap-global-set "C-u" 're/backward-kill-line) +#+END_SRC + +Since =C-u= is =universal-argument=, I put that functionality on =M-'=. + +#+BEGIN_SRC emacs-lisp +(keymap-global-set "M-'" 'universal-argument) +#+END_SRC + +****** =C-h= +We already have =F1= for help. Use this setup instead of ~key-translate~ because that doesn't work when running the daemon. +#+BEGIN_SRC emacs-lisp +(keymap-set key-translation-map "C-h" "") +#+END_SRC + +**** Moving +***** Home/End +I want =Home= and =End= to take me to the top and bottom of the file. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "" 'beginning-of-buffer) +(keymap-global-set "" 'end-of-buffer) +#+END_SRC + +***** Beginning of line +****** ~smart-beginning-of-line~ +I have the infamous =smart-beginning-of-line= command here. +#+BEGIN_SRC emacs-lisp +(defun re/smart-beginning-of-line () + "Move point to first non-whitespace character or beginning-of-line. +If point was already at that position, move point to beginning of +line. Stolen from BrettWitty's dotemacs github repo." + (interactive "^") + (let ((oldpos (point))) + (back-to-indentation) + (and (= oldpos (point)) + (beginning-of-line)))) +#+END_SRC +****** Play nice with ~visual-line-mode~ +I had issues with ~smart-beginning-of-line~ in ~visual-line-mode~, so ~smart-beginning-of-visual-line~ was created. It implements part of ~back-to-indentation~, but with changes to use ~beginning-of-visual-line~ instead of ~beginning-of-line~. +#+BEGIN_SRC emacs-lisp +(defun re/smart-beginning-of-visual-line () + "Move point to first non-whitespace character or beginning-of-line. +If point was already at that position, move point to beginning of +line. Stolen from BrettWitty's dotemacs github repo. Modified to +work in visual-line-mode. Re-implementing `back-to-indentation' +as a visual-line respecter." + (interactive "^") + (let ((oldpos (point))) + (beginning-of-visual-line 1) + (skip-syntax-forward " " (line-end-position)) + (backward-prefix-chars) + (and (= oldpos (point)) + (beginning-of-visual-line)))) +#+END_SRC +****** Re-mappings +Remap =move-beginning-of-line=, then remap =beginning-of-visual-line= when going into =visual-line-mode=. A simple remap would not work for =visual-line-mode=, so I explicitly set =C-a=. +#+BEGIN_SRC emacs-lisp +(global-set-key [remap move-beginning-of-line] 're/smart-beginning-of-line) +(add-hook 'visual-line-mode-hook + (lambda () + (keymap-global-set "C-a" 're/smart-beginning-of-visual-line))) +#+END_SRC +***** Line Numbers on move only +I don't want line numbers in the margin unless I am actively trying to go to a line. I override =goto-line= with this function, which shows line numbers, asks me where I want to go, and then hides line numbers. +#+BEGIN_SRC emacs-lisp +(defun re/goto-line () + "Show line numbers before going to line, then hide them again." + (interactive) + (display-line-numbers-mode 1) + (call-interactively 'goto-line) + (display-line-numbers-mode -1)) + +(global-set-key [remap goto-line] 're/goto-line) +#+END_SRC +***** Other window or split window +I ripped this defun and binding from [[https://github.com/lem-project/lem][lem]]. Can't live without it now. Does similar things as [[id:1c8d7229-796f-446a-8ae8-247cd6164a12][Windmove]], but without having to specify a direction. +#+BEGIN_SRC emacs-lisp +(defun re/other-window-or-split-window (&optional window) + (interactive) + (if (= (count-windows) 1) + (funcall split-window-preferred-function window) + (other-window 1))) + +(keymap-global-set "C-M-o" 're/other-window-or-split-window) +#+END_SRC +**** Search and Replace +***** Search with region +#+BEGIN_SRC emacs-lisp +(defun re/isearch-forward-use-region () + (interactive) + (when (use-region-p) + (add-to-history 'search-ring (buffer-substring (region-beginning) + (region-end))) + (deactivate-mark)) + (call-interactively 'isearch-forward)) + +(defun re/isearch-backward-use-region () + (interactive) + (when (use-region-p) + (add-to-history 'search-ring (buffer-substring (region-beginning) + (region-end))) + (deactivate-mark)) + (call-interactively 'isearch-backward)) +#+END_SRC + +***** Bindings +I made these bindings to put my more-used commands on better keys, and swap them with the less-used ones. Also add bindings for ~isearch-*-regexp~. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "M-s ." 'isearch-forward-thing-at-point) +(keymap-global-set "M-s M-." 'isearch-forward-symbol-at-point) +(keymap-global-set "M-%" 'replace-regexp) +(keymap-global-set "C-%" 'replace-string) +(keymap-global-set "C-s" 're/isearch-forward-use-region) +(keymap-global-set "C-r" 're/isearch-backward-use-region) +(keymap-global-set "C-S-S" 'isearch-forward-regexp) +(keymap-global-set "C-S-R" 'isearch-backward-regexp) +#+END_SRC +**** Insert Key +I keep accidentally enabling ~overwrite-mode~, so disable the ~insert~ key +#+BEGIN_SRC emacs-lisp +(keymap-global-set "" nil) +#+END_SRC + +*** Elisp/Eval bindings +**** Eval Region +Some old Emacs-like editor (Edwin?) used this binding, so I put it in here. Less used than the =C-M-x= =eval-defun= binding, but occasionally nice to have. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-M-z" 'eval-region) +#+END_SRC + +**** Send on Close-Paren +:PROPERTIES: +:ID: 325c01c5-b877-4281-adff-ea956bdb5f2c +:END: +I wanted something like what the Genera environment has, where putting in a final close-paren will send the command, without having to hit enter. This is a general command, used by [[id:325c01c5-b877-4281-adff-ea956bdb5f2c][Eshell]] and [[id:664ba0e7-0826-4868-9480-e1338a6e9f63][Ielm]]. +#+BEGIN_SRC emacs-lisp +(defun re/send-on-close-paren (executor) + "Generalizes sending an execute on close paren. +When a sexp is complete - that is when parens balance as you type - execute it." + (interactive) + (insert-char ?\)) + (when (= 0 (car (syntax-ppss))) + (call-interactively executor))) +#+END_SRC + +*** *NIX +These defuns are here so that I can use doas/sudo over tramp to edit /local/ files requiring root permissions. Doas for BSD, Sudo for Linux, nothing for Windows. +#+BEGIN_SRC emacs-lisp +(unless (equal system-type 'windows-nt) + (if(equal system-type 'berkeley-unix) + (defun doas () + "Use TRAMP to reopen the current buffer as root using doas." + (interactive) + (when buffer-file-name + (find-alternate-file + (concat "/doas:root@localhost:" + buffer-file-name)))) + (defun sudo () + "Use TRAMP to reopen the current buffer as root using sudo." + (interactive) + (when buffer-file-name + (find-alternate-file + (concat "/doas:root@localhost:" + buffer-file-name)))))) +#+END_SRC + +*** Windows +If you've ever had the /pleasure/ of using Aveva (*Formerly WonderWare*) version 2020, you'll understand. +#+BEGIN_SRC emacs-lisp +(when (equal system-type 'windows-nt) + (defun re/unfuck-aveva-license () + "Remove the offending xml files. +Use this when aveva can't find ass with both hands." + (interactive) + (let ((xml1 "c:/ProgramData/AVEVA/Licensing/License API2/Data/LocalAcquireInfo.xml") + (xml2 "c:/ProgramData/AVEVA/Licensing/License API2/Data/LocalBackEndAcquireInfo.xml")) + (when (file-exists-p xml1) (delete-file xml1)) + (when (file-exists-p xml2) (delete-file xml2))))) +#+END_SRC + +*** Math +General Math defuns, often used in later defuns. +**** Exponentiation +I'm tired of writing out ='expt=, and I want to use the same notation every other programming language does. +#+BEGIN_SRC emacs-lisp +(defalias '^ 'expt) +#+END_SRC + +**** Square, Cube, and Inv +Define square, cube, and inv for brevity of common usages. +#+BEGIN_SRC emacs-lisp +(defun square (x) + "Calculate the square of a value." + (^ x 2)) + +(defun cube (x) + "Calculate the cube of a value." + (^ x 3)) + +(defun inv (x) + "Calculate the inverse of a value." + (/ 1 (float x))) +#+END_SRC + +*** Unit Conversions +The rest of the world decided to self-castrate because some French guys told them things Definitely Made More Sense if everything was divisible by 10. I'm convinced the average Frenchman simply couldn't grasp fractions, and that's why he came up with this crap. What's 1/3 of a meter? What's 1/3 of a yard? And 1/3 of a foot? How likely are you to need to divide a measurement by 3 when you're building something? Maybe the [[https://dozenal.org/][Dozenal]] people were right all along. Anyway, I'm now forced to convert into proper units daily because of this grave error. +#+BEGIN_SRC emacs-lisp +(defun mm->in (mm) + "Convert milimeters to inches." + (/ mm 25.4)) + +(defun in->mm (in) + "Convert inches to milimeters." + (* in 25.4)) + +(defun k->c (tempk) + "Convert degrees Kelvin to degrees Celsius." + (- tempk 273.15)) + +(defun c->k (tempc) + "Convert degrees Celsius to degrees Kelvin." + (+ tempc 273.15)) + +(defun c->f (tempc) + "Convert degrees Celsius to degrees Fahrenheit." + (+ (* tempc 1.8) 32.0)) + +(defun f->c (tempf) + "Convert degrees Fahrenheit to degrees Celsius." + (/ (- tempf 32.0) 1.8)) + +(defun k->f (tempk) + "Convert degrees Kelvin to degrees Fahrenheit. +Applies `c->f' to `k->c'." + (c->f (k->c tempk))) + +(defun f->k (tempf) + "Convert degrees Fahrenheit to degrees Kelvin. +Applies `c->k' to `f->c'." + (c->k (f->c tempf))) +#+END_SRC + +*** Electrical +These defuns are all about electronics. Effective impedance, amps to volts, and back again. +**** Effective-impedance +#+BEGIN_SRC emacs-lisp +(defun eff-imp (r1 &optional r2) + "Calculate the effective input impedance, given two resistances. +For use in `amps->volts' and related. The handling of only one +resistance given is done here, instead of doing it in every +function that uses this." + (if (eq nil r2) + r1 + (inv (+ (inv r1) (inv r2))))) +#+END_SRC + +**** Amps to volts +#+BEGIN_SRC emacs-lisp +(defun amps->volts (amps r1 &optional r2) + "Calculate the voltage, given amperage and impedance. +Multiplies the amperage by the effective impedance calculated +with `eff-imp'." + (* amps (eff-imp r1 r2))) +#+END_SRC + +**** Volts to amps +#+BEGIN_SRC emacs-lisp +(defun volts->amps (volts r1 &optional r2) + "Calculate the amperage, given voltage and impedance. +Divides the voltage by the effective impedance calculated with +`eff-imp'." + (/ volts (eff-imp r1 r2))) +#+END_SRC + +*** PLC +The nitty-gritty. These defuns build on the previous ones to help me do various calculations related to analog signals and how they interact with [[https://en.wikipedia.org/wiki/Programmable_logic_controller][PLCs]], also called PACs. Counts, volts, amps, bit-resolutions, and relating them to each other. +**** Max counts +#+BEGIN_SRC emacs-lisp +(defun max-counts (resolution) + "Calculate the max count for a PLC analog, given card's bit-resolution." + (- (^ 2 resolution) 1)) +#+END_SRC + +**** Volts to counts +#+BEGIN_SRC emacs-lisp +(defun volts->counts (vmax vin resolution) + "Convert a voltage signal to a PLC count. +Calculates a ratio of vin/vmax, then scales by `max-counts'." + (* (/ (float vin) vmax) (max-counts resolution))) +#+END_SRC + +**** Counts to volts +#+BEGIN_SRC emacs-lisp +(defun counts->volts (vmax cin resolution) + "Convert a PLC count to a voltage. +Calculates a ratio of cin/`max-counts', then multiplies by vmax." + (* (/ (float cin) (max-counts resolution)) vmax)) +#+END_SRC + +**** Amps to counts +#+BEGIN_SRC emacs-lisp +(defun amps->counts (vmax amps resolution r1 &optional r2) + "Convert a current signal to PLC Counts. +Converts the amperage to a voltage using `amps->volts' (with r1 +and optional r2), then applies `volts->counts' to the resulting +voltage, vmax, and resolution." + (volts->counts vmax (amps->volts amps r1 r2) resolution)) +#+END_SRC + +**** Count range +#+BEGIN_SRC emacs-lisp +(defun count-range (upper lower vmax resolution &optional r1 r2) + "Given an upper and lower signal, return the list of upper and lower PLC counts. +With a current signal, use r1 and maybe r2 to +calculate `amps->counts'. Otherwise ignore r1/r2 and calculate +`volts->counts'." + (if (eq nil r1) + (list (volts->counts vmax upper resolution) + (volts->counts vmax lower resolution)) + (list (amps->counts vmax upper resolution r1 r2) + (amps->counts vmax lower resolution r1 r2)))) +#+END_SRC + +**** Scaling +#+BEGIN_SRC emacs-lisp +(defun divisor (raw-max raw-min scaled-max scaled-min) + "Calculate 1/slope given PLC Max/Min and Eng. Max/Min." + (/ (float (- raw-max raw-min)) (- scaled-max scaled-min))) + +(defun offset (raw-max raw-min scaled-max scaled-min) + "Calculate offset given PLC Max/Min and Eng. Max/Min." + (- scaled-min (/ raw-min (divisor raw-max raw-min scaled-max scaled-min)))) + +(defun final (analog-input divisor offset) + "Calculate the scaled value of an input." + (+ (/ analog-input divisor) offset)) + +(defun scale (raw-max raw-min scaled-max scaled-min &optional analog-input) + "Calculate the divisor, offset, and maybe final value, given the parameters." + (let* ((div (divisor raw-max raw-min scaled-max scaled-min)) + (os (offset raw-max raw-min scaled-max scaled-min))) + (if (eq nil analog-input) + (list div os) + (list div os (final analog-input div os))))) +#+END_SRC + +*** Refrigeration +More nitty-gritty. These are for calculating specific refrigeration-related things. Somewhat specialized. +**** CFM +#+BEGIN_SRC emacs-lisp +(defun cfm-circ (fpm radius) + "Calculate the CFM of a circular duct. +Inputs are feet/minute and radius (in)." + (list (* float-pi fpm (square (/ radius 12.0))))) + +(defun cfm-rect (fpm width height) + "Calculate the CFM of a rectangular duct. +Inputs are feet/minute, width (in) and height (in)." + (list (* fpm (/ width 12.0) (/ height 12.0)))) +#+END_SRC + +**** Saturated Water Pressure +#+BEGIN_SRC emacs-lisp +(defun sat-water-press (temp) + "Calculate the saturated water pressure at a temp (F)." + (+ .0182795 + (* temp .001029904) + (* (square temp) 0.00002579408) + (* (cube temp) (* 2.400493 (^ 10 -7))) + (* (^ temp 4) (* 8.100939 (^ 10 -10))) + (* (^ temp 5) (* 3.256805 (^ 10 -11))) + (* (^ temp 6) (* -1.001922 (^ 10 -13))) + (* (^ temp 7) (* 2.44161 (^ 10 -16))))) +#+END_SRC + +**** Humidity Ratio +#+BEGIN_SRC emacs-lisp +(defun hum-ratio (humidity swp) + "Calulate the humidity ratio. +Takes humidity in %RH, and a Saturated Water Pressure." + (let ((hum-press (* (/ humidity 100.0) swp))) + (/ (* hum-press 0.62198) (- 14.7 hum-press)))) +#+END_SRC + +**** Grains of water per lb of air +#+BEGIN_SRC emacs-lisp +(defun gn-water-per-lb (humidity temp) + "Calculate the grains of water per lb of air. +Takes humidity in %RH, and temp in F." + (* 7000 (hum-ratio humidity (sat-water-press temp)))) +#+END_SRC + +** org configuration +My (now-sprawling) org configuration +*** Startup options +Start folded, and show stars as indentation. +#+BEGIN_SRC emacs-lisp +(setq org-startup-folded t + org-startup-indented t) +#+END_SRC + +*** Basics +Don't split my line, just make a new one, follow links with return, export tables as csvs, set the default export backends, and use an absolute path for other links (while shortening home to ~). +#+BEGIN_SRC emacs-lisp +(setq org-M-RET-may-split-line nil + org-return-follows-link t + org-table-export-default-format "orgtbl-to-csv" + org-export-backends '(ascii html latex md) + org-link-file-path-type 'absolute) +#+END_SRC + +*** TO-DO options +Select with single key, enforce sub-tasks, only change the color of the keyword. +#+BEGIN_SRC emacs-lisp +(setq org-use-fast-todo-selection 'expert + org-fast-tag-selection-single-key 'expert + org-enforce-todo-dependencies t + org-enforce-todo-checkbox-dependencies t + org-fontify-done-headline nil + org-fontify-todo-headline nil) +#+END_SRC + +*** Navigation +Make the =C-c C-j= binding more useful. +#+BEGIN_SRC emacs-lisp +(setq org-goto-interface 'outline-path-completion + org-outline-path-complete-in-steps nil + org-goto-max-level 20) +#+END_SRC + +*** Special keys & subtree yanking +Org special keys - do logical things with =C-a/e/k=, and adjust subtree level when yanking. +#+BEGIN_SRC emacs-lisp +(setq org-special-ctrl-a/e t + org-special-ctrl-k t + org-yank-adjusted-subtrees t) +#+END_SRC + +*** File Opening +Don't open links in another window, just use the current one. +#+BEGIN_SRC emacs-lisp +(setq org-link-frame-setup '((file . find-file))) +#+END_SRC + +*** Directories +Tell org where everything is +#+BEGIN_SRC emacs-lisp +(setq org-directory "~/org" + org-agenda-files '("~/org") + org-default-notes-file "~/org/refile.org" + org-journal-file "~/org/journal.org") +#+END_SRC + +*** Refile +Let me refile anywhere, use outline paths, confirm when creating parent nodes. +#+BEGIN_SRC emacs-lisp +(setq org-refile-targets '((nil :maxlevel . 9) + (org-agenda-files :maxlevel . 9)) + org-refile-use-outline-path 'file + org-refile-allow-creating-parent-nodes 'confirm) +#+END_SRC + +*** Keywords +Set up some more todo keywords +#+BEGIN_SRC emacs-lisp +(setq org-todo-keywords '((sequence "TODO(t)" + "WAITING(w@/!)" + "IN-PROGRESS(i!)" + "APPT(a!)" + "|" + "DELEGATED(l@)" + "DONE(d!/@)" + "CANCELLED(c@)"))) +#+END_SRC + +*** Tag Filtering +Add some much-used tags with shortcuts. +#+BEGIN_SRC emacs-lisp +(setq org-tag-alist '((:startgroup . nil) + ("need" . ?n) + ("standard" . ?s) + ("wisdom" . ?w) + (:endgroup . nil))) +#+END_SRC + +*** Agenda +**** General options +Go back to previous view on quit, always start on current day, warn me for 30 days of a deadline, use the current window for the agenda, and don't show tags, but show full heirarchy. +#+BEGIN_SRC emacs-lisp +(setq org-agenda-restore-windows-after-quit t + org-agenda-start-on-weekday 0 + org-agenda-span 14 + org-deadline-warning-days 30 + org-agenda-window-setup 'current-window + org-agenda-remove-tags t + org-agenda-prefix-format '((agenda . " %:c %b %?-12t% s") + (todo . " %:c % b") + (tags . " %:c % b") + (search . " %:c % b"))) +#+END_SRC + +**** Custom View +Set up the agenda view. Access it with ~C-c a SPC~, [[id:3281906e-1f44-4abb-9f9d-0a0a39221752][or ~F2~]]. +#+BEGIN_SRC emacs-lisp +(setq org-agenda-custom-commands '((" " "Agenda" + (;(agenda "" nil) + (tags "need" + ((org-agenda-overriding-header "Needed Items"))) + (tags-todo "-REFILE+TODO=\"IN-PROGRESS\"" + ((org-agenda-overriding-header "In Progress"))) + (tags "REFILE" + ((org-agenda-overriding-header "Tasks to Refile"))) + (tags-todo "-TODO=\"WAITING\"-TODO=\"IN-PROGRESS\"-standard-REFILE" + ((org-agenda-overriding-header "Filed Tasks"))) + (tags-todo "TODO=\"WAITING\"-REFILE" + ((org-agenda-overriding-header "Holding"))) + (tags-todo "standard" + ((org-agenda-overriding-header "Changes to Standard"))))))) +#+END_SRC + +**** Custom Agenda on Single key +Stolen from [[https://emacs.stackexchange.com/questions/864/how-to-bind-a-key-to-a-specific-agenda-command-list-in-org-mode][Stack Exchange]] +#+BEGIN_SRC emacs-lisp +(defun re/org-agenda-show-custom (&optional arg) + "Show my custom agenda." + (interactive "P") + (org-agenda arg " ")) +#+END_SRC + +Do it again for main agenda +#+BEGIN_SRC emacs-lisp +(defun re/org-show-agenda (&optional arg) + "Show the main agenda" + (interactive "P") + (org-agenda arg "a")) +#+END_SRC + +**** Column View +Set up the format for column view. +#+BEGIN_SRC emacs-lisp +(setq org-columns-default-format "%50ITEM(Task) %10CLOCKSUM %16TIMESTAMP_IA" + org-agenda-start-with-log-mode t) +#+END_SRC + +**** Clock settings +Resume clocking when emacs restarts, save&load running clock and history on exit/startup, resume last task on clock-in if clock is open, resume active clock without prompt, include current clocking task in reports, and make the clocktable look nice. +#+BEGIN_SRC emacs-lisp +(org-clock-persistence-insinuate) + +(setq org-clock-persist t + org-clock-in-resume t + org-clock-persist-query-resume nil + org-clock-report-include-clocking-task t + org-pretty-entities t) +#+END_SRC + +*** Capture Templates +:PROPERTIES: +:ID: a10ca34b-c61c-4ca5-96a0-62b0dfe1ed05 +:END: +Capture Templates per my proclivities. +#+BEGIN_SRC emacs-lisp +(setq org-capture-templates '(("n" "Note" entry (file org-default-notes-file) + "* %?" + :clock-in t + :clock-resume t) + ("t" "TODO" entry (file org-default-notes-file) + "* TODO %?\n%U\n" + :clock-in t + :clock-resume t) + ("m" "Meeting" entry (file+olp+datetree org-journal-file) + "* %? :meeting:\n%t\n** Notes\n** Action Items" + :time-prompt t) + ("s" "Semi-Weekly PLC Meeting" entry (file+olp+datetree org-journal-file) + "* Semi-Weekly PLC Meeting :plc:semiweekly:meeting:%^g \n%t\n** Notes\n** Action Items" + :clock-in t + :clock-resume t) + ("a" "Appointment" entry (file+olp+datetree org-journal-file) + "* %? :appt:\n%t" + :time-prompt t) + ("j" "Journal" entry (file+olp+datetree org-journal-file) + "* %?\n%U\n"))) +#+END_SRC + +*** Abbreviations & Snippets +**** Abbrev-Mode settings +Start up =abbrev-mode= for org +#+BEGIN_SRC emacs-lisp +(add-hook 'org-mode-hook #'abbrev-mode) +(setq abbrev-file-name (expand-file-name "abbrev_defs" user-emacs-directory) + save-abbrevs 'silently) +#+END_SRC + +**** Skeletons +***** General source Block +#+BEGIN_SRC emacs-lisp +(define-skeleton skel-org-block + "Insert an org source code block" + "" + "#+BEGIN_SRC " + _ - "\n\n" + "#+END_SRC\n") +#+END_SRC + +***** Emacs Lisp source Block +#+BEGIN_SRC emacs-lisp +(define-skeleton skel-org-block-elisp + "Insert an org emacs lisp block" + "" + "#+BEGIN_SRC emacs-lisp\n" + _ - \n + "#+END_SRC\n") +#+END_SRC + +***** Facility properties block +#+BEGIN_SRC emacs-lisp +(define-skeleton skel-facility-properties + "Insert the org title and filetags for a new facility." + "" + "#+TITLE: " + _ - \n + "#+FILETAGS: customer city state pm sm ee ce aka c#\n\n" + "* System Notes\n" + "* PLC [/]\n" + "* Wonderware [/]\n" + "* Commissioning [/]\n") +#+END_SRC + +***** Person properties block +#+BEGIN_SRC emacs-lisp +(define-skeleton skel-person-properties + "Insert the org title and filetags for a person." + "" + "#+TITLE: @" + _ - \n + "#+FILETAGS: company position\n" + "#+EMAIL:\n" + "#+OFFICE:\n" + "#+CELL:\n") +#+END_SRC + +***** Workorder properties block +#+BEGIN_SRC emacs-lisp +(define-skeleton skel-workorder-properties + "Insert the org title and filetags for a workorder" + "" + "#+TITLE: Workorder " + _ - \n + "#+FILETAGS: wo# workorder customer city state topics\n") +#+END_SRC + +**** Bind the snippets (in the =abbrev-file-name= file) +#+BEGIN_SRC emacs-lisp :tangle ./abbrev_defs +;;-*-coding: utf-8;-*- +(define-abbrev-table 'org-mode-abbrev-table + '(("ssrc" "" skel-org-block) + ("selisp" "" skel-org-block-elisp) + ("sfac" "" skel-facility-properties) + ("sper" "" skel-person-properties) + ("swo" "" skel-workorder-properties))) +#+END_SRC + +*** Auto-archive +A function to automatically archive *DONE* items in an org file. I sometimes use this as an after-save-hook header declaration as such: +#+BEGIN_SRC emacs-lisp :tangle no +-*- after-save-hook: (re/org-auto-archive) -*- +#+END_SRC + +#+BEGIN_SRC emacs-lisp +(defun re/org-auto-archive () + "Automatically archive completed tasks in an org file. +Intended for use as an after-save-hook." + (interactive) + (org-map-entries + (lambda () + (org-archive-subtree) + (setq org-map-continue-from (org-element-property :begin (org-element-at-point)))) + "TODO=\"DONE\"|TODO=\"CANCELLED\"|TODO=\"DELEGATED\"" + 'file) + (save-buffer)) +#+END_SRC + +Also add that defun to =safe-local-variables= so that emacs will run it. +#+BEGIN_SRC emacs-lisp +(setq safe-local-variable-values '((after-save-hook re/org-auto-archive))) +#+END_SRC + +*** Auto-Generate IDs +**** On Capture +Generate an ID when I link to someting. +#+BEGIN_SRC emacs-lisp +(setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id) +#+END_SRC + +**** Existing File +Automatically generate unique IDs if not already created. Stolen from [[https://stackoverflow.com/questions/13340616/assign-ids-to-every-entry-in-org-mode][Stack Overflow]] +#+BEGIN_SRC emacs-lisp +(defun re/org-auto-generate-ids-in-file () + "Add ID properties to all headlines in the current + file which do not already have one." + (interactive) + (org-map-entries 'org-id-get-create)) +#+END_SRC + +Don't run this on save of any org-mode file like we used to. (no longer tangling this block). +#+BEGIN_SRC emacs-lisp :tangle no +(add-hook 'org-mode-hook + (lambda () + (add-hook 'before-save-hook 're/org-auto-generate-ids-in-file nil 'local))) +#+END_SRC + +*** Tangling +**** Settings +Don't make a new window for source-code edits, and keep indentation consistent. +#+BEGIN_SRC emacs-lisp +(setq org-src-window-setup 'current-window + org-src-preserve-indentation t + org-src-fontify-natively t) +#+END_SRC + +**** Auto-tangle this file +Make a function to tangle this file, and run it on save. +#+BEGIN_SRC emacs-lisp +(defun re/tangle-init () + "Tangle and compile init.org. +Stolen from https://github.com/larstvei/dot-emacs." + (when (equal (buffer-file-name) + (expand-file-name (concat user-emacs-directory "config.org"))) + (let ((prog-mode-hook nil)) + (org-babel-tangle)))) + +(add-hook 'after-save-hook 're/tangle-init) +#+END_SRC + +*** Bindings +**** Global +:PROPERTIES: +:ID: 3281906e-1f44-4abb-9f9d-0a0a39221752 +:END: +The usual bindings. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-c l" 'org-store-link) +(keymap-global-set "C-c a" 'org-agenda) +(keymap-global-set "C-c c" 'org-capture) +(keymap-global-set "C-c b" 'org-switchb) +(keymap-global-set "" 're/org-agenda-show-custom) +(keymap-global-set "" 're/org-show-agenda) +#+END_SRC + +**** Mode-Specific +Give me logical in/out-denting on the easier binding, since I use that more often. +#+BEGIN_SRC emacs-lisp +(add-hook 'org-mode-hook + (lambda () + (keymap-set org-mode-map "M-" 'org-shiftmetaright) + (keymap-set org-mode-map "M-" 'org-shiftmetaleft) + (keymap-set org-mode-map "M-S-" 'org-metaright) + (keymap-set org-mode-map "M-S-" 'org-metaleft))) +#+END_SRC + +** Dired configuration +Make dired use the same switches I prefer for =ls=, give me a simpler listing, and default to using its current buffer for visiting a file, rather than creating a new one. +#+BEGIN_SRC emacs-lisp +(setq dired-listing-switches "-al") + +(add-hook 'dired-mode-hook + (lambda () + (dired-hide-details-mode t) + (keymap-set dired-mode-map + "RET" 'dired-find-alternate-file))) +#+END_SRC + +** Eshell configuration +:PROPERTIES: +:ID: 700392e5-d07b-474f-baa9-f563b4a6197f +:END: +Here are the various customizations I have for eshell. +*** Binding to start eshell +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-c e" 'eshell) +#+END_SRC + +*** Make it play nice with corfu +#+BEGIN_SRC emacs-lisp +(add-hook 'eshell-mode-hook (lambda () + ;; (setq-local corfu-auto nil) + (corfu-mode))) +#+END_SRC + +*** Send on Close-Paren +I wanted something like what the Genera environment has, where putting in a final close-paren will send the command, without having to hit enter. See [[id:325c01c5-b877-4281-adff-ea956bdb5f2c][Send on Close-Paren]]. +#+BEGIN_SRC emacs-lisp +(defun re/eshell-send-on-close-paren () + "Makes eshell act somewhat like genera. +Makes a closing paren execute the sexp." + (interactive) + (re/send-on-close-paren 'eshell-send-input)) +#+END_SRC + +*** Quit or delete-char +I want =C-d= to end the shell if it is on an empty line, otherwise act normally. +#+BEGIN_SRC emacs-lisp +(defun eshell-quit-or-delete-char (arg) + "Delete char if at one, quit eshell if on empty prompt. +Stolen from https://depp.brause.cc/dotemacs" + (interactive "p") + (if (and (eolp) (looking-back eshell-prompt-regexp 0 t)) + (eshell-life-is-too-much) ; https://emacshorrors.com/post/life-is-too-much + (delete-char arg))) +#+END_SRC + +*** Bind the defuns +I have only been able to get these to work when they are within an add-hook lambda. +#+BEGIN_SRC emacs-lisp +(add-hook 'eshell-mode-hook + (lambda () + (keymap-set eshell-mode-map ")" 're/eshell-send-on-close-paren) + (keymap-set eshell-mode-map "C-d" 'eshell-quit-or-delete-char))) +#+END_SRC + +** ielm configuration +:PROPERTIES: +:ID: e7a7b861-8f63-4036-9f68-59fb954a7561 +:END: +I wanted something more like a standard lisp REPL in emacs. Found =ielm=. +*** Send on Close-Paren +I wanted something like what the Genera environment has, where putting in a final close-paren will send the command, without having to hit enter. See [[id:325c01c5-b877-4281-adff-ea956bdb5f2c][Send on Close-Paren]]. +#+BEGIN_SRC emacs-lisp +(defun re/ielm-send-on-close-paren () + "Makes ielm act somewhat like genera. +Makes a closing paren execute the sexp." + (interactive) + (re/send-on-close-paren 'ielm-send-input)) +#+END_SRC + +*** Persistent command history +**** Read History +#+BEGIN_SRC emacs-lisp +(defun re/ielm-init-history () + "Stolen from https://n16f.net/blog/making-ielm-more-comfortable." + (let ((path (expand-file-name "ielm/history" user-emacs-directory))) + (make-directory (file-name-directory path) t) + (setq-local comint-input-ring-file-name path)) + (setq-local comint-input-ring-size 10000 + comint-input-ignoredups t) + (comint-read-input-ring)) + +(add-hook 'ielm-mode-hook 're/ielm-init-history) +#+END_SRC + +**** Write History +#+BEGIN_SRC emacs-lisp +(defun re/ielm-write-history (&rest _args) + "Stolen from https://n16f.net/blog/making-ielm-more-comfortable." + (with-file-modes #o600 + (comint-write-input-ring))) + +(advice-add 'ielm-send-input :after 're/ielm-write-history) +#+END_SRC + +*** Bindings +~C-l~ to clear buffer, send on close paren. +#+BEGIN_SRC emacs-lisp +(keymap-global-set "C-c i" 'ielm) +(add-hook 'ielm-mode-hook + (lambda () + (keymap-set inferior-emacs-lisp-mode-map "C-l" 'comint-clear-buffer) + (keymap-set inferior-emacs-lisp-mode-map ")" 're/ielm-send-on-close-paren))) +#+END_SRC + +** Customize system +I do not use the customize system. I don't want to see it if I don't have to. +#+BEGIN_SRC emacs-lisp +(setq custom-file (expand-file-name "custom.el" user-emacs-directory)) +(when (not (file-exists-p custom-file)) + (make-empty-file custom-file)) + +(load custom-file) +#+END_SRC + +** Footer +#+BEGIN_SRC emacs-lisp +;;; hic terminatur config.el +#+END_SRC diff --git a/early-init.el b/early-init.el new file mode 100644 index 0000000..fd4d732 --- /dev/null +++ b/early-init.el @@ -0,0 +1,26 @@ +;;; early-init.el -*- lexical-binding: t; -*- + +;; Haec pars Emacs non est. + +;; Code: + +(setq gc-cons-threshold most-positive-fixnum + gc-cons-percentage 0.6) + +(add-hook 'after-init-hook #'(lambda () (setq gc-cons-threshold (* 1024 1024 25) + gc-cons-percentage 0.1))) + +(menu-bar-mode -1) +(tool-bar-mode -1) +(blink-cursor-mode -1) + +(setq inhibit-startup-screen t + inhibit-startup-buffer-menu t + server-client-instructions nil + frame-resize-pixelwise t + initial-scratch-message (message ";;; Emacs loaded in %s.\n\n" (emacs-init-time))) + +(setq default-directory "~/") + +(provide 'early-init) +;;; hic terminatur early-init.el diff --git a/init.el b/init.el index af7613b..2af87ae 100644 --- a/init.el +++ b/init.el @@ -1,10 +1,10 @@ -;;; This file replaces itself with the real config at first run -;; We Can't tangle without org! +;;; init.el --- Quae configurare -*- lexical-binding: t; -*- + +;; Haec pars Emacs non est. + +;; Code: + (require 'org) -;; Open the config... -(find-file (concat user-emacs-directory "init.org")) -;; Tangle it... -(org-babel-tangle) -;; Load it. -(load-file (concat user-emacs-directory "early-init.el")) -(load-file (concat user-emacs-directory "init.el")) + +(org-babel-load-file (concat user-emacs-directory "config.org")) +;;; hic terminatur init.el diff --git a/init.org b/init.org deleted file mode 100644 index f5b919d..0000000 --- a/init.org +++ /dev/null @@ -1,1539 +0,0 @@ -#+TITLE: Emacs Configuratione -#+PROPERTY: header-args:emacs-lisp :tangle yes :results silent :export code - -* Introduction -This is my emacs configuration. It is meant to be used across linux, windows, and BSD. I use windows only at work (Industrial Controls). I use emacs often as an advanced programmable calculator. - -Lots of inspiration taken from: -- [[https://depp.brause.cc/dotemacs/][depp.brause.cc/dotemacs/]] -- [[https://github.com/larstvei/dot-emacs][github.com/larstvei/dot-emacs]] -- [[https://github.com/sachac/.emacs.d][github.com/sachac/.emacs.d]] - -** A note on version checking -I keep my emacs installs at the latest release, so I don't worry about checking for versions in my init unless I happen to update on linux/BSD before the windows binaries are released. That being said, I am currently on version 29.3. -** Latinization -I believe that all scientific knowledge, and by extension computational knowledge, should be shared in Latin. That is to say I intend to facilitate Latin's return as the default language for global knowledge sharing. To be consistent, I will soon be translating as much of this file as possible into Latin. Monitus es. -* Meta Configuration -I have taken this mostly whole-hog from [[https://github.com/larstvei/dot-emacs][github.com/larstvei/dot-emacs]]. The idea is that this bare-bones init.el is available when the repo is pulled in, but gets overwritten on emacs' first run. Emacs will need to be re-started after that initial run, since =early-init.el= will be created, and some packages will be installed. -** Init.el -This is the repo's =init.el= file, which bootstraps the real =init.el=. -#+BEGIN_SRC emacs-lisp :tangle no -;;; This file replaces itself with the real config at first run -;; We Can't tangle without org! -(require 'org) -;; Open the config... -(find-file (concat user-emacs-directory "init.org")) -;; Tangle it... -(org-babel-tangle) -;; Load it. -(load-file (concat user-emacs-directory "early-init.el")) -(load-file (concat user-emacs-directory "init.el")) -#+END_SRC - -** Git init.el tracking -*** Disable Tracking -There is no reason to track the =init.el= that is generated. Run the following command to make git ignore the generated file, but keep the dummy init. -#+BEGIN_SRC sh :tangle no -git update-index --assume-unchanged init.el -#+END_SRC - -*** Enable Tracking -If changes to the dummy-init are needed, track those by running -#+BEGIN_SRC sh :tangle no -git update-index --no-assume-unchanged init.el -#+END_SRC - -* Early init -This file was introduced in Emacs 27. I use it for speeding up init, removing all the UI stuff I don't want, etc. Maybe superfluous, but I do get startup times on the order of /0.015/ seconds on Windows. - -** The normal header -There are no GNU Police (yet), but I feel nicer by adding this in. -#+BEGIN_SRC emacs-lisp :tangle ./early-init.el -;;; early-init.el -*- lexical-binding: t; -*- - -;; Haec pars Emacs non est. - -;; Code: -#+END_SRC - -** GC thrashing -Set the GC threshold to max during startup, then set it back to a value that is somewhat more sane than the default /800kb/. - -#+BEGIN_SRC emacs-lisp :tangle ./early-init.el -(setq gc-cons-threshold most-positive-fixnum - gc-cons-percentage 0.6) - -(add-hook 'after-init-hook #'(lambda () (setq gc-cons-threshold (* 1024 1024 25) - gc-cons-percentage 0.1))) -#+END_SRC - -** Basic UI preferences -I want no menus, no tool-bars, no blinking cursor, no messages when starting up, and to make resizing work properly. I just want the scratch buffer with a report on =emacs-init-time=. -#+BEGIN_SRC emacs-lisp :tangle ./early-init.el -(menu-bar-mode -1) -(tool-bar-mode -1) -(blink-cursor-mode -1) - -(setq inhibit-startup-screen t - inhibit-startup-buffer-menu t - server-client-instructions nil - frame-resize-pixelwise t - initial-scratch-message (message ";;; Emacs loaded in %s.\n\n" (emacs-init-time))) -#+END_SRC - -** Misc/odd issues -Avoid a weird issue on windows where opening emacs via an [[https://www.autohotkey.com/][AutoHotKey]] binding causes emacs to load in the AutoHotKey directory. - -#+BEGIN_SRC emacs-lisp :tangle ./early-init.el -(setq default-directory "~/") -#+END_SRC - -** The normal footer - -#+BEGIN_SRC emacs-lisp :tangle ./early-init.el -(provide 'early-init) -;;; hic terminatur early-init.el -#+END_SRC - -* Main init -** Header - -#+BEGIN_SRC emacs-lisp -;;; init.el --- Quae configurare -*- lexical-binding: t; -*- - -;; Haec pars Emacs non est. - -;; Code: -#+END_SRC - -** Packages -Load packages first, so there is no question about dependencies later in the file. -*** Package Repositories -Non-gnu is in the defaults now, so I only need to add melpa. -#+BEGIN_SRC emacs-lisp -(require 'package) -(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) -#+END_SRC - -*** almost-mono-themes -Exactly what they say they are! -#+BEGIN_SRC emacs-lisp -(use-package almost-mono-themes - :ensure t - :config - (load-theme 'almost-mono-white t)) -#+END_SRC - -*** Packages I don't want on my work computers -I don't need these on a windows PC. -#+BEGIN_SRC emacs-lisp -(unless (equal system-type 'windows-nt) - (use-package ledger-mode - :ensure t - :bind - ((:map ledger-mode-map ("C-c s" . ledger-sort-buffer))))) -#+END_SRC - -*** visual-fill-column -A godsend. Finally, I can have visual-line-mode without having to read lines that are 1980 pixels wide! Also set word wrap, and make the split for help do what I want on big screens. -#+BEGIN_SRC emacs-lisp -(use-package visual-fill-column - :ensure t - :config - (global-visual-line-mode 1) - :custom - (word-wrap t) - (visual-fill-column-enable-sensible-window-split t)) -#+END_SRC - -Also make a defun/binding to toggle it as needed. -#+BEGIN_SRC emacs-lisp -(defun re/toggle-visual-fill-column-mode () -"Toggles `visual-fill-column-mode." - (interactive) - (visual-fill-column-mode 'toggle)) - -(keymap-global-set "C-c v" 're/toggle-visual-fill-column-mode) - -#+END_SRC - -*** corfu -I used =company-mode= for a long time. I tried corfu and haven't looked back. It is smaller, and does everything I was doing with company. - -**** Main Corfu -The basics for corfu. Auto popup after one letter, enable globally. -#+BEGIN_SRC emacs-lisp -(use-package corfu - :ensure t - :custom - (corfu-auto t) - (corfu-auto-delay 0) - (corfu-auto-prefix 1) - :config - (global-corfu-mode)) -#+END_SRC - -**** corfu-popupinfo -This comes with base corfu, but is configured separately. -#+BEGIN_SRC emacs-lisp -(use-package corfu-popupinfo - :ensure nil ; Part of corfu - :after corfu - :hook (corfu-mode . corfu-popupinfo-mode) - :custom - (corfu-popupinfo-delay '(nil . 0.01)) - (corfu-popupinfo-hide nil) - :config - (corfu-popupinfo-mode)) - ;; :bind - ;; ((:map corfu-map ("C-h" . corfu-popupinfo-toggle)))) -#+END_SRC - -*** expand-region -Seldom used, but nothing else does it. -#+BEGIN_SRC emacs-lisp -(use-package expand-region :ensure t) -(keymap-global-set "C-=" 'er/expand-region) -#+END_SRC - -*** magit -I use magit occasionally. I put this sparse configuration here mostly for a speed boost, by making magit only load when I explicitly call for it. -#+BEGIN_SRC emacs-lisp -(use-package magit - :ensure t - :config - (message "Magit Loaded") - :bind - ((:map ctl-x-map ("g" . magit-status)))) -#+END_SRC - -*** Recentf -#+BEGIN_SRC emacs-lisp -(use-package recentf - :ensure t - :config - (recentf-mode 1)) - -(keymap-global-set "C-c r" 'recentf-open) -#+END_SRC - -*** openwith -I need to open binary files with their own editor. Disgusting. -#+BEGIN_SRC emacs-lisp -(use-package openwith - :ensure t - :config - (openwith-mode t)) - -(setq openwith-associations (list - (list (openwith-make-extension-regexp - '("xls" "xlsx" "doc" "docx" - "ppt" "odt" "ods" "odg" "odp")) - "LibreOffice" - '(file)) - (list (openwith-make-extension-regexp - '("adpro")) - "ProductivitySuite" - '(file)))) -#+END_SRC - -*** acme-mouse -Not a package in the strict sense, just a .el file loaded as a git submodule - forked from [[https://github.com/akrito/acme-mouse/]] to [[https://github.com/rearman/acme-mouse/]] and modified to meet changes to the old =cl= package, and to fix the ~mouse-3~ search function. Also see the [[id:451a20e6-73a0-4d55-aeaa-e795980a6974][Maus]] section. -#+BEGIN_SRC emacs-lisp -(add-to-list 'load-path (concat user-emacs-directory "acme-mouse/")) -(require 'acme-mouse) -#+END_SRC - -*** AUCTeX -Starting to do some work with LaTeX, surprised this is not in base, but org is. -#+BEGIN_SRC emacs-lisp -(use-package auctex - :ensure t - :defer t) -#+END_SRC - -*** SLIME -Lisp me...sometimes. -#+BEGIN_SRC emacs-lisp -(let ((slime-help "~/quicklisp/slime-helper.el")) - (when (file-exists-p slime-help) - (load (expand-file-name slime-help)) - (setq inferior-lisp-program "sbcl") - (use-package slime - :ensure t - :custom - (slime-net-coding-system 'utf-8-unix)) - (when (file-exists-p "~/lisp/sbcl.core-for-slime") - (setq slime-lisp-implementations - '((sbcl ("sbcl" "--core" "sbcl.core-for-slime") - :directory "~/lisp")))) - (add-hook 'slime-mode-hook - (lambda () - (unless (slime-connected-p) - (save-excursion (slime))))))) -#+END_SRC - -** Non-Package customization -This section has '/base/' emacs customization. All the general stuff. -*** Defaults -I want these things every time, or at least setting them this way worked when a regular =setq= didn't. -#+BEGIN_SRC emacs-lisp -(setq-default indicate-empty-lines t - fill-column 80 - cursor-type 'bar - cursor-in-non-selected-windows 'hollow) -#+END_SRC -*** Help -Set up apropos to be more useful. -#+BEGIN_SRC emacs-lisp -(setq apropos-do-all t) -#+END_SRC - -*** UTF-8 -Force emacs to use UTF-8 so I avoid prompts on save. -#+BEGIN_SRC emacs-lisp -(set-language-environment 'utf-8) -(set-default-coding-systems 'utf-8) -(set-keyboard-coding-system 'utf-8-unix) -(set-terminal-coding-system 'utf-8-unix) -#+END_SRC - -*** Backup/Autosave -I originally had some autosave items in here, but the defaults appeared to be doing basically what I wanted anyway. -**** Backups -Make backups for vc-controlled files, don't clobber symlinks, and put everything into =~/emacs-backups/=. -#+BEGIN_SRC emacs-lisp -(setq vc-make-backup-files t - backup-by-copying t - backup-directory-alist `((".*" . "~/emacs-backups/"))) -#+END_SRC - -**** Old versions -Keep 10 versions, 5 'old' and 5 'new'. Delete anything older. -#+BEGIN_SRC emacs-lisp -(setq delete-old-versions t - kept-new-versions 5 - kept-old-versions 5) -#+END_SRC - -*** File handling -**** Final Newline -I want to avoid ever seeing an error about missing newlines at the end of a file. -#+BEGIN_SRC emacs-lisp -(setq require-final-newline t) -#+END_SRC - -**** Auto Revert -When files (or folders in dired) change on disk, and there are no changes in the open buffer, revert to the on-disk version. -#+BEGIN_SRC emacs-lisp -(global-auto-revert-mode t) -(setq global-auto-revert-non-file-buffers t) -#+END_SRC - -**** Segfault recovery -These are directly from [[https://depp.brause.cc/dotemacs/][depp.brause.cc/dotemacs/]]. They are intended to make Emacs drop changes and die when a segfault happens, rather than attempt to save potentially corrupted data. -#+BEGIN_SRC emacs-lisp -(setq attempt-stack-overflow-recovery nil - attempt-orderly-shutdown-on-fatal-signal nil) -#+END_SRC - -**** Whitespace and chmod on save -I want to strip all trailing whitespace on save, and I want to make all shell scripts executable at the same time. -#+BEGIN_SRC emacs-lisp -(add-hook 'before-save-hook 'whitespace-cleanup) -(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p) -#+END_SRC - -*** Minibuffer interaction -I don't want emacs to beep or blink at me, I want y/n instead of the default yes/no, I don't care for clicking on things in the minibuffer, I like seeing things echoed almost immediately, for keystrokes and eldoc. I want eldoc to stick to one line. I want history to only show me unique commands, and I want case-insensitive buffer switching. -#+BEGIN_SRC emacs-lisp -(setq ring-bell-function 'ignore - use-short-answers t - use-file-dialog nil - echo-keystrokes 0.1 - eldoc-idle-delay 0 - eldoc-echo-area-use-multiline-p nil - read-buffer-completion-ignore-case t - history-delete-duplicates t) -#+END_SRC - -*** Buffer interaction -**** General -***** midnight-mode -Close unused buffers after 3 days. -#+BEGIN_SRC emacs-lisp -(midnight-mode t) -#+END_SRC - -***** delete-selection-mode -Overwrite selection when active, like every other editor since Sam. -#+BEGIN_SRC emacs-lisp -(delete-selection-mode t) -#+END_SRC - -***** Don't disable any functions. -#+BEGIN_SRC emacs-lisp -(setq disabled-command-function nil) -#+END_SRC - -***** Inter-program kill-ring -Save pastes from elsewhere into the kill-ring, and don't ask me about killing processes when I kill a buffer. -#+BEGIN_SRC emacs-lisp -(setq save-interprogram-paste-before-kill t - confirm-kill-processes nil) -#+END_SRC - -**** Windmove -:PROPERTIES: -:ID: 1c8d7229-796f-446a-8ae8-247cd6164a12 -:END: -I originally had custom defuns and bindings to do this, but then I found out it was built in... -#+BEGIN_SRC emacs-lisp -(windmove-default-keybindings 'control) -(setq windmove-wrap-around t - windmove-create-window t) -#+END_SRC - -**** Maus -:PROPERTIES: -:ID: 451a20e6-73a0-4d55-aeaa-e795980a6974 -:END: -Don't follow links with mouse-1, so I can select without having to use the keyboard (when I want to). -#+BEGIN_SRC emacs-lisp -(setq mouse-1-click-follows-link nil) -#+END_SRC - -*** Buffer looks -**** Prettify Symbols -I want nice symbols to look at -#+BEGIN_SRC emacs-lisp -(setq prettify-symbols-alist '(("lambda" . 955) - ("delta" . 120517) - ("epsilon" . 120518) - ("->" . 8594) - ("<=" . 8804) - (">=" . 8805))) -(global-prettify-symbols-mode t) -#+END_SRC - -**** Visual Line Mode indicators -Show arrows when a line wraps -#+BEGIN_SRC emacs-lisp -(setq-default visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow)) -#+END_SRC - -**** Scroll Bars -Put my scroll bars where I like them. -#+BEGIN_SRC emacs-lisp -(set-scroll-bar-mode 'left) -#+END_SRC - -*** Parens -When I'm on a beginning/ending paren, I find the default of only highlighting the parens too hard to see, and highlighting the whole thing too garish. Therefore, this setup tries to underline the expression, with minimal highlighting. - -Show matching parens immediately, and "highlight" the whole expression. -#+BEGIN_SRC emacs-lisp -(setq show-paren-delay 0 - show-paren-style 'expression) -#+END_SRC - -Make the paren "highlight" the same color as the background, with no overwrite of foreground color, and add underline. -#+BEGIN_SRC emacs-lisp -(set-face-attribute 'show-paren-match nil - :foreground 'unspecified - :background 'unspecified - :underline t) -#+END_SRC - -*** Modeline -Funny name for the frame -#+BEGIN_SRC emacs-lisp -(setq frame-title-format "Poor Man's LispM") -#+END_SRC - -Show me column number and filesize -#+BEGIN_SRC emacs-lisp -(column-number-mode t) -(size-indication-mode t) -#+END_SRC - -*** C-Style -Please use Tabs in C files, I'm BEGGING. Absolutely ridiculous that there's no simple variable to select Tabs ONLY for indentation. -#+BEGIN_SRC emacs-lisp -(defun re/c-lineup-arglist-tabs-only (ignored) - "Line up argument lists by tabs, not spaces. Stolen from https://kernel.org/doc/html/v4.10/process/coding-style.html" - (let* ((anchor (c-langelem-pos c-syntactic-element)) - (column (c-langelem-2nd-pos c-syntactic-element)) - (offset (- (1+ column) anchor)) - (steps (floor offset c-basic-offset))) - (* (max steps 1) - c-basic-offset))) - -(add-hook 'c-mode-common-hook - (lambda () - ;; Add kernel style - (c-add-style - "linux-tabs-only" - '("linux" - (c-offsets-alist - (arglist-cont-nonempty - c-lineup-gcc-asm-reg - re/c-lineup-arglist-tabs-only)))))) - -(add-hook 'c-mode-hook - (lambda () - (setq indent-tabs-mode t) - (setq show-trailing-whitespace t) - (setq c-backspace-function 'backward-delete-char) ;; don't expand my tabs, just delete them. - (c-set-style "linux-tabs-only"))) -#+END_SRC - -*** Windows-Specific -Use =recycle bin=, DON'T use =AltGr=, and tell emacs where =diff= is. -#+BEGIN_SRC emacs-lisp -(when (equal system-type 'windows-nt) - (setq delete-by-moving-to-trash t - ediff-diff-program "\"c:/Program Files/Git/usr/bin/diff.exe\"" - ediff-diff3-program "\"c:/Program Files/Git/usr/bin/diff3.exe\"" - diff-command "\"c:/Program Files/Git/usr/bin/diff.exe\"" - w32-recognize-altgr 'nil)) -#+END_SRC - -** Defuns and Bindings -I have quite a few math and work-related defuns, and fewer editing ones. Inversely, I have more editing related bindings than work-related ones. This makes sense, considering my usage patterns. -*** Editing -Most of these are to re-create something from vim/readline/sam/acme. Some are just helper functions or wrappers. -**** Visiting Files -Bind ~find-file-at-point~ and ~bookmark-jump-other-window~. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-x M-f" 'find-file-at-point) -(keymap-global-set "C-x r B" 'bookmark-jump-other-window) -#+END_SRC - -**** Undo/redo -I like putting redo on ~C-\~. Easier for me to remember than the ~C-M-_~ default. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-\\" 'undo-redo) -#+END_SRC - -**** Renaming Files -I took this from [[https://whattheemacsd.com][whattheemacsd.com]]. It is occasionally handy. -#+BEGIN_SRC emacs-lisp -(defun re/rename-current-buffer-file () - "Renames the current buffer and the file it is visiting." - (interactive) - (let ((name (buffer-name)) - (filename (buffer-file-name))) - (if (not (and filename (file-exists-p filename))) - (error "Buffer '%s' is not visiting a file!" name) - (let ((new-name (read-file-name "New name: " filename))) - (if (get-buffer new-name) - (error "A buffer named '%s' already exists!" new-name) - (rename-file filename new-name 1) - (rename-buffer new-name) - (set-visited-file-name new-name) - (set-buffer-modified-p nil) - (message "File '%s' successfully renamed to '%s'" - name (file-name-nondirectory new-name))))))) - -(keymap-global-set "C-x C-r" 're/rename-current-buffer-file) -#+END_SRC -**** Buffer Menu -Usually I want the buffer menu in the same window I am already on. Occasionally I want it in a different window. Bind accordingly. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-x C-b" 'buffer-menu) -(keymap-global-set "C-x M-b" 'buffer-menu-other-window) -#+END_SRC - -**** Switch to Scratch -I often want to bring up the scratch buffer in my current window, and sometimes I want only one window that is the scratch buffer. Emacs 29 added the ~scratch-buffer~ function, so one less defun needed here. -#+BEGIN_SRC emacs-lisp -(defun re/scratch-only () - "Bring up the scratch buffer as the only visible buffer." - (interactive) - (scratch-buffer) - (delete-other-windows)) - -(keymap-global-set "" 'scratch-buffer) -(keymap-global-set "S-" 're/scratch-only) -#+END_SRC - -**** Line joining -The ~M-^~ binding is handy, but usually I want the ed/sam/vi join function, which pulls the next line up into the current line. I bind this to ~M-j~. -#+BEGIN_SRC emacs-lisp -(defun re/backward-join-line () - "A wrapper for join-line to make it go in the right direction." - (interactive) - (join-line 0)) - -(keymap-global-set "M-j" 're/backward-join-line) -#+END_SRC - -**** Line opening -The default behavior of =open-line= is ridiculous. It acheives the same function as hitting =RET=. I don't want to split the current line, I want to OPEN a new one, and usually go to it. These wrappers remedy that. - -#+BEGIN_SRC emacs-lisp -(defun re/open-line-below (n) - "Creates a new empty line below the current line and moves to it." - (interactive "*p") - (end-of-line) - (open-line n) - (call-interactively (next-line)) - (indent-for-tab-command)) - -(defun re/open-line-above (n) - "Creates a new empty line above the current line." - (interactive "*p") - (beginning-of-line) - (open-line n) - (indent-for-tab-command)) -#+END_SRC - -I Bind the previous functions to =C-o= and =M-o=. - -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-o" 're/open-line-below) -(keymap-global-set "M-o" 're/open-line-above) -#+END_SRC - -**** Line sorting -Stolen from [[https:github.com/magnars/emacsd-reboot/blob/main/settings/editing.el]] -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-c s" 'sort-lines) -#+END_SRC - -**** Commenting -I stole this directly from [[https://depp.brause.cc/dotemacs][depp.brause.cc/dotemacs]]. Very good, simple solution. -#+BEGIN_SRC emacs-lisp -(defun re/comment-dwim () - "Comment region if active, otherwise comment line. -Stolen from https://depp.brause.cc/dotemacs" - (interactive) - (if (use-region-p) - (comment-or-uncomment-region (region-beginning) (region-end)) - (comment-or-uncomment-region (line-beginning-position) - (line-end-position)))) - -(keymap-global-set "M-;" 're/comment-dwim) -#+END_SRC - -**** Killing -***** Kill Whole Line -Bind =kill-whole-line= to =C-S-K= for something somewhat pnemonic. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-S-K" 'kill-whole-line) -#+END_SRC - -***** Zap up to char -Bind =C-z= to zap-up-to-char, sice zap-to-char is on =M-z=. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-z" 'zap-up-to-char) -#+END_SRC - -***** UNIX C-w, C-u, and C-h -=C-w= is very much engrained for killing back one word, as is =C-u= for killing back to the beginning of the line, and =C-h= for one character back. [[http://unix-kb.cat-v.org/][These have been standard bindings since TENEX...]] -****** =C-w= -I didn't want to re-bind =C-w= away from =kill-region=, so I made it do both. -#+BEGIN_SRC emacs-lisp -(defun re/kill-bword-or-region () - "Kill region if active, otherwise kill back one word." - (interactive) - (if (use-region-p) - (call-interactively 'kill-region) - (call-interactively 'backward-kill-word))) - -(keymap-global-set "C-w" 're/kill-bword-or-region) -#+END_SRC - -****** =C-u= -There is no pre-made function to kill backward to the beginning of line from point, so I made one that passes the correct argument to =kill-line=, and bound it to =C-u=. -#+BEGIN_SRC emacs-lisp -(defun re/backward-kill-line () - "Kill back to beginning of line from point." - (interactive) - (kill-line 0)) - -(keymap-global-set "C-u" 're/backward-kill-line) -#+END_SRC - -Since =C-u= is =universal-argument=, I put that functionality on =M-'=. - -#+BEGIN_SRC emacs-lisp -(keymap-global-set "M-'" 'universal-argument) -#+END_SRC - -****** =C-h= -We already have =F1= for help. Use this setup instead of ~key-translate~ because that doesn't work when running the daemon. -#+BEGIN_SRC emacs-lisp -(keymap-set key-translation-map "C-h" "") -#+END_SRC - -**** Moving -***** Home/End -I want =Home= and =End= to take me to the top and bottom of the file. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "" 'beginning-of-buffer) -(keymap-global-set "" 'end-of-buffer) -#+END_SRC - -***** Beginning of line -****** ~smart-beginning-of-line~ -I have the infamous =smart-beginning-of-line= command here. -#+BEGIN_SRC emacs-lisp -(defun re/smart-beginning-of-line () - "Move point to first non-whitespace character or beginning-of-line. -If point was already at that position, move point to beginning of -line. Stolen from BrettWitty's dotemacs github repo." - (interactive "^") - (let ((oldpos (point))) - (back-to-indentation) - (and (= oldpos (point)) - (beginning-of-line)))) -#+END_SRC -****** Play nice with ~visual-line-mode~ -I had issues with ~smart-beginning-of-line~ in ~visual-line-mode~, so ~smart-beginning-of-visual-line~ was created. It implements part of ~back-to-indentation~, but with changes to use ~beginning-of-visual-line~ instead of ~beginning-of-line~. -#+BEGIN_SRC emacs-lisp -(defun re/smart-beginning-of-visual-line () - "Move point to first non-whitespace character or beginning-of-line. -If point was already at that position, move point to beginning of -line. Stolen from BrettWitty's dotemacs github repo. Modified to -work in visual-line-mode. Re-implementing `back-to-indentation' -as a visual-line respecter." - (interactive "^") - (let ((oldpos (point))) - (beginning-of-visual-line 1) - (skip-syntax-forward " " (line-end-position)) - (backward-prefix-chars) - (and (= oldpos (point)) - (beginning-of-visual-line)))) -#+END_SRC -****** Re-mappings -Remap =move-beginning-of-line=, then remap =beginning-of-visual-line= when going into =visual-line-mode=. A simple remap would not work for =visual-line-mode=, so I explicitly set =C-a=. -#+BEGIN_SRC emacs-lisp -(global-set-key [remap move-beginning-of-line] 're/smart-beginning-of-line) -(add-hook 'visual-line-mode-hook - (lambda () - (keymap-global-set "C-a" 're/smart-beginning-of-visual-line))) -#+END_SRC -***** Line Numbers on move only -I don't want line numbers in the margin unless I am actively trying to go to a line. I override =goto-line= with this function, which shows line numbers, asks me where I want to go, and then hides line numbers. -#+BEGIN_SRC emacs-lisp -(defun re/goto-line () - "Show line numbers before going to line, then hide them again." - (interactive) - (display-line-numbers-mode 1) - (call-interactively 'goto-line) - (display-line-numbers-mode -1)) - -(global-set-key [remap goto-line] 're/goto-line) -#+END_SRC -***** Other window or split window -I ripped this defun and binding from [[https://github.com/lem-project/lem][lem]]. Can't live without it now. Does similar things as [[id:1c8d7229-796f-446a-8ae8-247cd6164a12][Windmove]], but without having to specify a direction. -#+BEGIN_SRC emacs-lisp -(defun re/other-window-or-split-window (&optional window) - (interactive) - (if (= (count-windows) 1) - (funcall split-window-preferred-function window) - (other-window 1))) - -(keymap-global-set "C-M-o" 're/other-window-or-split-window) -#+END_SRC -**** Search and Replace -***** Search with region -#+BEGIN_SRC emacs-lisp -(defun re/isearch-forward-use-region () - (interactive) - (when (use-region-p) - (add-to-history 'search-ring (buffer-substring (region-beginning) - (region-end))) - (deactivate-mark)) - (call-interactively 'isearch-forward)) - -(defun re/isearch-backward-use-region () - (interactive) - (when (use-region-p) - (add-to-history 'search-ring (buffer-substring (region-beginning) - (region-end))) - (deactivate-mark)) - (call-interactively 'isearch-backward)) -#+END_SRC - -***** Bindings -I made these bindings to put my more-used commands on better keys, and swap them with the less-used ones. Also add bindings for ~isearch-*-regexp~. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "M-s ." 'isearch-forward-thing-at-point) -(keymap-global-set "M-s M-." 'isearch-forward-symbol-at-point) -(keymap-global-set "M-%" 'replace-regexp) -(keymap-global-set "C-%" 'replace-string) -(keymap-global-set "C-s" 're/isearch-forward-use-region) -(keymap-global-set "C-r" 're/isearch-backward-use-region) -(keymap-global-set "C-S-S" 'isearch-forward-regexp) -(keymap-global-set "C-S-R" 'isearch-backward-regexp) -#+END_SRC -**** Insert Key -I keep accidentally enabling ~overwrite-mode~, so disable the ~insert~ key -#+BEGIN_SRC emacs-lisp -(keymap-global-set "" nil) -#+END_SRC - -*** Elisp/Eval bindings -**** Eval Region -Some old Emacs-like editor (Edwin?) used this binding, so I put it in here. Less used than the =C-M-x= =eval-defun= binding, but occasionally nice to have. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-M-z" 'eval-region) -#+END_SRC - -**** Send on Close-Paren -:PROPERTIES: -:ID: 325c01c5-b877-4281-adff-ea956bdb5f2c -:END: -I wanted something like what the Genera environment has, where putting in a final close-paren will send the command, without having to hit enter. This is a general command, used by [[id:325c01c5-b877-4281-adff-ea956bdb5f2c][Eshell]] and [[id:664ba0e7-0826-4868-9480-e1338a6e9f63][Ielm]]. -#+BEGIN_SRC emacs-lisp -(defun re/send-on-close-paren (executor) - "Generalizes sending an execute on close paren. -When a sexp is complete - that is when parens balance as you type - execute it." - (interactive) - (insert-char ?\)) - (when (= 0 (car (syntax-ppss))) - (call-interactively executor))) -#+END_SRC - -*** *NIX -These defuns are here so that I can use doas/sudo over tramp to edit /local/ files requiring root permissions. Doas for BSD, Sudo for Linux, nothing for Windows. -#+BEGIN_SRC emacs-lisp -(unless (equal system-type 'windows-nt) - (if(equal system-type 'berkeley-unix) - (defun doas () - "Use TRAMP to reopen the current buffer as root using doas." - (interactive) - (when buffer-file-name - (find-alternate-file - (concat "/doas:root@localhost:" - buffer-file-name)))) - (defun sudo () - "Use TRAMP to reopen the current buffer as root using sudo." - (interactive) - (when buffer-file-name - (find-alternate-file - (concat "/doas:root@localhost:" - buffer-file-name)))))) -#+END_SRC - -*** Windows -If you've ever had the /pleasure/ of using Aveva (*Formerly WonderWare*) version 2020, you'll understand. -#+BEGIN_SRC emacs-lisp -(when (equal system-type 'windows-nt) - (defun re/unfuck-aveva-license () - "Remove the offending xml files. -Use this when aveva can't find ass with both hands." - (interactive) - (let ((xml1 "c:/ProgramData/AVEVA/Licensing/License API2/Data/LocalAcquireInfo.xml") - (xml2 "c:/ProgramData/AVEVA/Licensing/License API2/Data/LocalBackEndAcquireInfo.xml")) - (when (file-exists-p xml1) (delete-file xml1)) - (when (file-exists-p xml2) (delete-file xml2))))) -#+END_SRC - -*** Math -General Math defuns, often used in later defuns. -**** Exponentiation -I'm tired of writing out ='expt=, and I want to use the same notation every other programming language does. -#+BEGIN_SRC emacs-lisp -(defalias '^ 'expt) -#+END_SRC - -**** Square, Cube, and Inv -Define square, cube, and inv for brevity of common usages. -#+BEGIN_SRC emacs-lisp -(defun square (x) - "Calculate the square of a value." - (^ x 2)) - -(defun cube (x) - "Calculate the cube of a value." - (^ x 3)) - -(defun inv (x) - "Calculate the inverse of a value." - (/ 1 (float x))) -#+END_SRC - -*** Unit Conversions -The rest of the world decided to self-castrate because some French guys told them things Definitely Made More Sense if everything was divisible by 10. I'm convinced the average Frenchman simply couldn't grasp fractions, and that's why he came up with this crap. What's 1/3 of a meter? What's 1/3 of a yard? And 1/3 of a foot? How likely are you to need to divide a measurement by 3 when you're building something? Maybe the [[https://dozenal.org/][Dozenal]] people were right all along. Anyway, I'm now forced to convert into proper units daily because of this grave error. -#+BEGIN_SRC emacs-lisp -(defun mm->in (mm) - "Convert milimeters to inches." - (/ mm 25.4)) - -(defun in->mm (in) - "Convert inches to milimeters." - (* in 25.4)) - -(defun k->c (tempk) - "Convert degrees Kelvin to degrees Celsius." - (- tempk 273.15)) - -(defun c->k (tempc) - "Convert degrees Celsius to degrees Kelvin." - (+ tempc 273.15)) - -(defun c->f (tempc) - "Convert degrees Celsius to degrees Fahrenheit." - (+ (* tempc 1.8) 32.0)) - -(defun f->c (tempf) - "Convert degrees Fahrenheit to degrees Celsius." - (/ (- tempf 32.0) 1.8)) - -(defun k->f (tempk) - "Convert degrees Kelvin to degrees Fahrenheit. -Applies `c->f' to `k->c'." - (c->f (k->c tempk))) - -(defun f->k (tempf) - "Convert degrees Fahrenheit to degrees Kelvin. -Applies `c->k' to `f->c'." - (c->k (f->c tempf))) -#+END_SRC - -*** Electrical -These defuns are all about electronics. Effective impedance, amps to volts, and back again. -**** Effective-impedance -#+BEGIN_SRC emacs-lisp -(defun eff-imp (r1 &optional r2) - "Calculate the effective input impedance, given two resistances. -For use in `amps->volts' and related. The handling of only one -resistance given is done here, instead of doing it in every -function that uses this." - (if (eq nil r2) - r1 - (inv (+ (inv r1) (inv r2))))) -#+END_SRC - -**** Amps to volts -#+BEGIN_SRC emacs-lisp -(defun amps->volts (amps r1 &optional r2) - "Calculate the voltage, given amperage and impedance. -Multiplies the amperage by the effective impedance calculated -with `eff-imp'." - (* amps (eff-imp r1 r2))) -#+END_SRC - -**** Volts to amps -#+BEGIN_SRC emacs-lisp -(defun volts->amps (volts r1 &optional r2) - "Calculate the amperage, given voltage and impedance. -Divides the voltage by the effective impedance calculated with -`eff-imp'." - (/ volts (eff-imp r1 r2))) -#+END_SRC - -*** PLC -The nitty-gritty. These defuns build on the previous ones to help me do various calculations related to analog signals and how they interact with [[https://en.wikipedia.org/wiki/Programmable_logic_controller][PLCs]], also called PACs. Counts, volts, amps, bit-resolutions, and relating them to each other. -**** Max counts -#+BEGIN_SRC emacs-lisp -(defun max-counts (resolution) - "Calculate the max count for a PLC analog, given card's bit-resolution." - (- (^ 2 resolution) 1)) -#+END_SRC - -**** Volts to counts -#+BEGIN_SRC emacs-lisp -(defun volts->counts (vmax vin resolution) - "Convert a voltage signal to a PLC count. -Calculates a ratio of vin/vmax, then scales by `max-counts'." - (* (/ (float vin) vmax) (max-counts resolution))) -#+END_SRC - -**** Counts to volts -#+BEGIN_SRC emacs-lisp -(defun counts->volts (vmax cin resolution) - "Convert a PLC count to a voltage. -Calculates a ratio of cin/`max-counts', then multiplies by vmax." - (* (/ (float cin) (max-counts resolution)) vmax)) -#+END_SRC - -**** Amps to counts -#+BEGIN_SRC emacs-lisp -(defun amps->counts (vmax amps resolution r1 &optional r2) - "Convert a current signal to PLC Counts. -Converts the amperage to a voltage using `amps->volts' (with r1 -and optional r2), then applies `volts->counts' to the resulting -voltage, vmax, and resolution." - (volts->counts vmax (amps->volts amps r1 r2) resolution)) -#+END_SRC - -**** Count range -#+BEGIN_SRC emacs-lisp -(defun count-range (upper lower vmax resolution &optional r1 r2) - "Given an upper and lower signal, return the list of upper and lower PLC counts. -With a current signal, use r1 and maybe r2 to -calculate `amps->counts'. Otherwise ignore r1/r2 and calculate -`volts->counts'." - (if (eq nil r1) - (list (volts->counts vmax upper resolution) - (volts->counts vmax lower resolution)) - (list (amps->counts vmax upper resolution r1 r2) - (amps->counts vmax lower resolution r1 r2)))) -#+END_SRC - -**** Scaling -#+BEGIN_SRC emacs-lisp -(defun divisor (raw-max raw-min scaled-max scaled-min) - "Calculate 1/slope given PLC Max/Min and Eng. Max/Min." - (/ (float (- raw-max raw-min)) (- scaled-max scaled-min))) - -(defun offset (raw-max raw-min scaled-max scaled-min) - "Calculate offset given PLC Max/Min and Eng. Max/Min." - (- scaled-min (/ raw-min (divisor raw-max raw-min scaled-max scaled-min)))) - -(defun final (analog-input divisor offset) - "Calculate the scaled value of an input." - (+ (/ analog-input divisor) offset)) - -(defun scale (raw-max raw-min scaled-max scaled-min &optional analog-input) - "Calculate the divisor, offset, and maybe final value, given the parameters." - (let* ((div (divisor raw-max raw-min scaled-max scaled-min)) - (os (offset raw-max raw-min scaled-max scaled-min))) - (if (eq nil analog-input) - (list div os) - (list div os (final analog-input div os))))) -#+END_SRC - -*** Refrigeration -More nitty-gritty. These are for calculating specific refrigeration-related things. Somewhat specialized. -**** CFM -#+BEGIN_SRC emacs-lisp -(defun cfm-circ (fpm radius) - "Calculate the CFM of a circular duct. -Inputs are feet/minute and radius (in)." - (list (* float-pi fpm (square (/ radius 12.0))))) - -(defun cfm-rect (fpm width height) - "Calculate the CFM of a rectangular duct. -Inputs are feet/minute, width (in) and height (in)." - (list (* fpm (/ width 12.0) (/ height 12.0)))) -#+END_SRC - -**** Saturated Water Pressure -#+BEGIN_SRC emacs-lisp -(defun sat-water-press (temp) - "Calculate the saturated water pressure at a temp (F)." - (+ .0182795 - (* temp .001029904) - (* (square temp) 0.00002579408) - (* (cube temp) (* 2.400493 (^ 10 -7))) - (* (^ temp 4) (* 8.100939 (^ 10 -10))) - (* (^ temp 5) (* 3.256805 (^ 10 -11))) - (* (^ temp 6) (* -1.001922 (^ 10 -13))) - (* (^ temp 7) (* 2.44161 (^ 10 -16))))) -#+END_SRC - -**** Humidity Ratio -#+BEGIN_SRC emacs-lisp -(defun hum-ratio (humidity swp) - "Calulate the humidity ratio. -Takes humidity in %RH, and a Saturated Water Pressure." - (let ((hum-press (* (/ humidity 100.0) swp))) - (/ (* hum-press 0.62198) (- 14.7 hum-press)))) -#+END_SRC - -**** Grains of water per lb of air -#+BEGIN_SRC emacs-lisp -(defun gn-water-per-lb (humidity temp) - "Calculate the grains of water per lb of air. -Takes humidity in %RH, and temp in F." - (* 7000 (hum-ratio humidity (sat-water-press temp)))) -#+END_SRC - -** org configuration -My (now-sprawling) org configuration -*** Startup options -Start folded, and show stars as indentation. -#+BEGIN_SRC emacs-lisp -(setq org-startup-folded t - org-startup-indented t) -#+END_SRC - -*** Basics -Don't split my line, just make a new one, follow links with return, export tables as csvs, set the default export backends, and use an absolute path for other links (while shortening home to ~). -#+BEGIN_SRC emacs-lisp -(setq org-M-RET-may-split-line nil - org-return-follows-link t - org-table-export-default-format "orgtbl-to-csv" - org-export-backends '(ascii html latex md) - org-link-file-path-type 'absolute) -#+END_SRC - -*** TO-DO options -Select with single key, enforce sub-tasks, only change the color of the keyword. -#+BEGIN_SRC emacs-lisp -(setq org-use-fast-todo-selection 'expert - org-fast-tag-selection-single-key 'expert - org-enforce-todo-dependencies t - org-enforce-todo-checkbox-dependencies t - org-fontify-done-headline nil - org-fontify-todo-headline nil) -#+END_SRC - -*** Navigation -Make the =C-c C-j= binding more useful. -#+BEGIN_SRC emacs-lisp -(setq org-goto-interface 'outline-path-completion - org-outline-path-complete-in-steps nil - org-goto-max-level 20) -#+END_SRC - -*** Special keys & subtree yanking -Org special keys - do logical things with =C-a/e/k=, and adjust subtree level when yanking. -#+BEGIN_SRC emacs-lisp -(setq org-special-ctrl-a/e t - org-special-ctrl-k t - org-yank-adjusted-subtrees t) -#+END_SRC - -*** File Opening -Don't open links in another window, just use the current one. -#+BEGIN_SRC emacs-lisp -(setq org-link-frame-setup '((file . find-file))) -#+END_SRC - -*** Directories -Tell org where everything is -#+BEGIN_SRC emacs-lisp -(setq org-directory "~/org" - org-agenda-files '("~/org") - org-default-notes-file "~/org/refile.org" - org-journal-file "~/org/journal.org") -#+END_SRC - -*** Refile -Let me refile anywhere, use outline paths, confirm when creating parent nodes. -#+BEGIN_SRC emacs-lisp -(setq org-refile-targets '((nil :maxlevel . 9) - (org-agenda-files :maxlevel . 9)) - org-refile-use-outline-path 'file - org-refile-allow-creating-parent-nodes 'confirm) -#+END_SRC - -*** Keywords -Set up some more todo keywords -#+BEGIN_SRC emacs-lisp -(setq org-todo-keywords '((sequence "TODO(t)" - "WAITING(w@/!)" - "IN-PROGRESS(i!)" - "APPT(a!)" - "|" - "DELEGATED(l@)" - "DONE(d!/@)" - "CANCELLED(c@)"))) -#+END_SRC - -*** Tag Filtering -Add some much-used tags with shortcuts. -#+BEGIN_SRC emacs-lisp -(setq org-tag-alist '((:startgroup . nil) - ("need" . ?n) - ("standard" . ?s) - ("wisdom" . ?w) - (:endgroup . nil))) -#+END_SRC - -*** Agenda -**** General options -Go back to previous view on quit, always start on current day, warn me for 30 days of a deadline, use the current window for the agenda, and don't show tags, but show full heirarchy. -#+BEGIN_SRC emacs-lisp -(setq org-agenda-restore-windows-after-quit t - org-agenda-start-on-weekday 0 - org-agenda-span 14 - org-deadline-warning-days 30 - org-agenda-window-setup 'current-window - org-agenda-remove-tags t - org-agenda-prefix-format '((agenda . " %:c %b %?-12t% s") - (todo . " %:c % b") - (tags . " %:c % b") - (search . " %:c % b"))) -#+END_SRC - -**** Custom View -Set up the agenda view. Access it with ~C-c a SPC~, [[id:3281906e-1f44-4abb-9f9d-0a0a39221752][or ~F2~]]. -#+BEGIN_SRC emacs-lisp -(setq org-agenda-custom-commands '((" " "Agenda" - (;(agenda "" nil) - (tags "need" - ((org-agenda-overriding-header "Needed Items"))) - (tags-todo "-REFILE+TODO=\"IN-PROGRESS\"" - ((org-agenda-overriding-header "In Progress"))) - (tags "REFILE" - ((org-agenda-overriding-header "Tasks to Refile"))) - (tags-todo "-TODO=\"WAITING\"-TODO=\"IN-PROGRESS\"-standard-REFILE" - ((org-agenda-overriding-header "Filed Tasks"))) - (tags-todo "TODO=\"WAITING\"-REFILE" - ((org-agenda-overriding-header "Holding"))) - (tags-todo "standard" - ((org-agenda-overriding-header "Changes to Standard"))))))) -#+END_SRC - -**** Custom Agenda on Single key -Stolen from [[https://emacs.stackexchange.com/questions/864/how-to-bind-a-key-to-a-specific-agenda-command-list-in-org-mode][Stack Exchange]] -#+BEGIN_SRC emacs-lisp -(defun re/org-agenda-show-custom (&optional arg) - "Show my custom agenda." - (interactive "P") - (org-agenda arg " ")) -#+END_SRC - -Do it again for main agenda -#+BEGIN_SRC emacs-lisp -(defun re/org-show-agenda (&optional arg) - "Show the main agenda" - (interactive "P") - (org-agenda arg "a")) -#+END_SRC - -**** Column View -Set up the format for column view. -#+BEGIN_SRC emacs-lisp -(setq org-columns-default-format "%50ITEM(Task) %10CLOCKSUM %16TIMESTAMP_IA" - org-agenda-start-with-log-mode t) -#+END_SRC - -**** Clock settings -Resume clocking when emacs restarts, save&load running clock and history on exit/startup, resume last task on clock-in if clock is open, resume active clock without prompt, include current clocking task in reports, and make the clocktable look nice. -#+BEGIN_SRC emacs-lisp -(org-clock-persistence-insinuate) - -(setq org-clock-persist t - org-clock-in-resume t - org-clock-persist-query-resume nil - org-clock-report-include-clocking-task t - org-pretty-entities t) -#+END_SRC - -*** Capture Templates -:PROPERTIES: -:ID: a10ca34b-c61c-4ca5-96a0-62b0dfe1ed05 -:END: -Capture Templates per my proclivities. -#+BEGIN_SRC emacs-lisp -(setq org-capture-templates '(("n" "Note" entry (file org-default-notes-file) - "* %?" - :clock-in t - :clock-resume t) - ("t" "TODO" entry (file org-default-notes-file) - "* TODO %?\n%U\n" - :clock-in t - :clock-resume t) - ("m" "Meeting" entry (file+olp+datetree org-journal-file) - "* %? :meeting:\n%t\n** Notes\n** Action Items" - :time-prompt t) - ("s" "Semi-Weekly PLC Meeting" entry (file+olp+datetree org-journal-file) - "* Semi-Weekly PLC Meeting :plc:semiweekly:meeting:%^g \n%t\n** Notes\n** Action Items" - :clock-in t - :clock-resume t) - ("a" "Appointment" entry (file+olp+datetree org-journal-file) - "* %? :appt:\n%t" - :time-prompt t) - ("j" "Journal" entry (file+olp+datetree org-journal-file) - "* %?\n%U\n"))) -#+END_SRC - -*** Abbreviations & Snippets -**** Abbrev-Mode settings -Start up =abbrev-mode= for org -#+BEGIN_SRC emacs-lisp -(add-hook 'org-mode-hook #'abbrev-mode) -(setq abbrev-file-name (expand-file-name "abbrev_defs" user-emacs-directory) - save-abbrevs 'silently) -#+END_SRC - -**** Skeletons -***** General source Block -#+BEGIN_SRC emacs-lisp -(define-skeleton skel-org-block - "Insert an org source code block" - "" - "#+BEGIN_SRC " - _ - "\n\n" - "#+END_SRC\n") -#+END_SRC - -***** Emacs Lisp source Block -#+BEGIN_SRC emacs-lisp -(define-skeleton skel-org-block-elisp - "Insert an org emacs lisp block" - "" - "#+BEGIN_SRC emacs-lisp\n" - _ - \n - "#+END_SRC\n") -#+END_SRC - -***** Facility properties block -#+BEGIN_SRC emacs-lisp -(define-skeleton skel-facility-properties - "Insert the org title and filetags for a new facility." - "" - "#+TITLE: " - _ - \n - "#+FILETAGS: customer city state pm sm ee ce aka c#\n\n" - "* System Notes\n" - "* PLC [/]\n" - "* Wonderware [/]\n" - "* Commissioning [/]\n") -#+END_SRC - -***** Person properties block -#+BEGIN_SRC emacs-lisp -(define-skeleton skel-person-properties - "Insert the org title and filetags for a person." - "" - "#+TITLE: @" - _ - \n - "#+FILETAGS: company position\n" - "#+EMAIL:\n" - "#+OFFICE:\n" - "#+CELL:\n") -#+END_SRC - -***** Workorder properties block -#+BEGIN_SRC emacs-lisp -(define-skeleton skel-workorder-properties - "Insert the org title and filetags for a workorder" - "" - "#+TITLE: Workorder " - _ - \n - "#+FILETAGS: wo# workorder customer city state topics\n") -#+END_SRC - -**** Bind the snippets (in the =abbrev-file-name= file) -#+BEGIN_SRC emacs-lisp :tangle ./abbrev_defs -;;-*-coding: utf-8;-*- -(define-abbrev-table 'org-mode-abbrev-table - '(("ssrc" "" skel-org-block) - ("selisp" "" skel-org-block-elisp) - ("sfac" "" skel-facility-properties) - ("sper" "" skel-person-properties) - ("swo" "" skel-workorder-properties))) -#+END_SRC - -*** Auto-archive -A function to automatically archive *DONE* items in an org file. I sometimes use this as an after-save-hook header declaration as such: -#+BEGIN_SRC emacs-lisp :tangle no --*- after-save-hook: (re/org-auto-archive) -*- -#+END_SRC - -#+BEGIN_SRC emacs-lisp -(defun re/org-auto-archive () - "Automatically archive completed tasks in an org file. -Intended for use as an after-save-hook." - (interactive) - (org-map-entries - (lambda () - (org-archive-subtree) - (setq org-map-continue-from (org-element-property :begin (org-element-at-point)))) - "TODO=\"DONE\"|TODO=\"CANCELLED\"|TODO=\"DELEGATED\"" - 'file) - (save-buffer)) -#+END_SRC - -Also add that defun to =safe-local-variables= so that emacs will run it. -#+BEGIN_SRC emacs-lisp -(setq safe-local-variable-values '((after-save-hook re/org-auto-archive))) -#+END_SRC - -*** Auto-Generate IDs -**** On Capture -Generate an ID when I link to someting. -#+BEGIN_SRC emacs-lisp -(setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id) -#+END_SRC - -**** Existing File -Automatically generate unique IDs if not already created. Stolen from [[https://stackoverflow.com/questions/13340616/assign-ids-to-every-entry-in-org-mode][Stack Overflow]] -#+BEGIN_SRC emacs-lisp -(defun re/org-auto-generate-ids-in-file () - "Add ID properties to all headlines in the current - file which do not already have one." - (interactive) - (org-map-entries 'org-id-get-create)) -#+END_SRC - -Don't run this on save of any org-mode file like we used to. (no longer tangling this block). -#+BEGIN_SRC emacs-lisp :tangle no -(add-hook 'org-mode-hook - (lambda () - (add-hook 'before-save-hook 're/org-auto-generate-ids-in-file nil 'local))) -#+END_SRC - -*** Tangling -**** Settings -Don't make a new window for source-code edits, and keep indentation consistent. -#+BEGIN_SRC emacs-lisp -(setq org-src-window-setup 'current-window - org-src-preserve-indentation t - org-src-fontify-natively t) -#+END_SRC - -**** Auto-tangle init.org -Make a function to tangle this file, and run it on save. -#+BEGIN_SRC emacs-lisp -(defun re/tangle-init () - "Tangle and compile init.org. -Stolen from https://github.com/larstvei/dot-emacs." - (when (equal (buffer-file-name) - (expand-file-name (concat user-emacs-directory "init.org"))) - (let ((prog-mode-hook nil)) - (org-babel-tangle)))) - -(add-hook 'after-save-hook 're/tangle-init) -#+END_SRC - -*** Bindings -**** Global -:PROPERTIES: -:ID: 3281906e-1f44-4abb-9f9d-0a0a39221752 -:END: -The usual bindings. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-c l" 'org-store-link) -(keymap-global-set "C-c a" 'org-agenda) -(keymap-global-set "C-c c" 'org-capture) -(keymap-global-set "C-c b" 'org-switchb) -(keymap-global-set "" 're/org-agenda-show-custom) -(keymap-global-set "" 're/org-show-agenda) -#+END_SRC - -**** Mode-Specific -Give me logical in/out-denting on the easier binding, since I use that more often. -#+BEGIN_SRC emacs-lisp -(add-hook 'org-mode-hook - (lambda () - (keymap-set org-mode-map "M-" 'org-shiftmetaright) - (keymap-set org-mode-map "M-" 'org-shiftmetaleft) - (keymap-set org-mode-map "M-S-" 'org-metaright) - (keymap-set org-mode-map "M-S-" 'org-metaleft))) -#+END_SRC - -** Dired configuration -Make dired use the same switches I prefer for =ls=, give me a simpler listing, and default to using its current buffer for visiting a file, rather than creating a new one. -#+BEGIN_SRC emacs-lisp -(setq dired-listing-switches "-al") - -(add-hook 'dired-mode-hook - (lambda () - (dired-hide-details-mode t) - (keymap-set dired-mode-map - "RET" 'dired-find-alternate-file))) -#+END_SRC - -** Eshell configuration -:PROPERTIES: -:ID: 700392e5-d07b-474f-baa9-f563b4a6197f -:END: -Here are the various customizations I have for eshell. -*** Binding to start eshell -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-c e" 'eshell) -#+END_SRC - -*** Make it play nice with corfu -#+BEGIN_SRC emacs-lisp -(add-hook 'eshell-mode-hook (lambda () - ;; (setq-local corfu-auto nil) - (corfu-mode))) -#+END_SRC - -*** Send on Close-Paren -I wanted something like what the Genera environment has, where putting in a final close-paren will send the command, without having to hit enter. See [[id:325c01c5-b877-4281-adff-ea956bdb5f2c][Send on Close-Paren]]. -#+BEGIN_SRC emacs-lisp -(defun re/eshell-send-on-close-paren () - "Makes eshell act somewhat like genera. -Makes a closing paren execute the sexp." - (interactive) - (re/send-on-close-paren 'eshell-send-input)) -#+END_SRC - -*** Quit or delete-char -I want =C-d= to end the shell if it is on an empty line, otherwise act normally. -#+BEGIN_SRC emacs-lisp -(defun eshell-quit-or-delete-char (arg) - "Delete char if at one, quit eshell if on empty prompt. -Stolen from https://depp.brause.cc/dotemacs" - (interactive "p") - (if (and (eolp) (looking-back eshell-prompt-regexp 0 t)) - (eshell-life-is-too-much) ; https://emacshorrors.com/post/life-is-too-much - (delete-char arg))) -#+END_SRC - -*** Bind the defuns -I have only been able to get these to work when they are within an add-hook lambda. -#+BEGIN_SRC emacs-lisp -(add-hook 'eshell-mode-hook - (lambda () - (keymap-set eshell-mode-map ")" 're/eshell-send-on-close-paren) - (keymap-set eshell-mode-map "C-d" 'eshell-quit-or-delete-char))) -#+END_SRC - -** ielm configuration -:PROPERTIES: -:ID: e7a7b861-8f63-4036-9f68-59fb954a7561 -:END: -I wanted something more like a standard lisp REPL in emacs. Found =ielm=. -*** Send on Close-Paren -I wanted something like what the Genera environment has, where putting in a final close-paren will send the command, without having to hit enter. See [[id:325c01c5-b877-4281-adff-ea956bdb5f2c][Send on Close-Paren]]. -#+BEGIN_SRC emacs-lisp -(defun re/ielm-send-on-close-paren () - "Makes ielm act somewhat like genera. -Makes a closing paren execute the sexp." - (interactive) - (re/send-on-close-paren 'ielm-send-input)) -#+END_SRC - -*** Persistent command history -**** Read History -#+BEGIN_SRC emacs-lisp -(defun re/ielm-init-history () - "Stolen from https://n16f.net/blog/making-ielm-more-comfortable." - (let ((path (expand-file-name "ielm/history" user-emacs-directory))) - (make-directory (file-name-directory path) t) - (setq-local comint-input-ring-file-name path)) - (setq-local comint-input-ring-size 10000 - comint-input-ignoredups t) - (comint-read-input-ring)) - -(add-hook 'ielm-mode-hook 're/ielm-init-history) -#+END_SRC - -**** Write History -#+BEGIN_SRC emacs-lisp -(defun re/ielm-write-history (&rest _args) - "Stolen from https://n16f.net/blog/making-ielm-more-comfortable." - (with-file-modes #o600 - (comint-write-input-ring))) - -(advice-add 'ielm-send-input :after 're/ielm-write-history) -#+END_SRC - -*** Bindings -~C-l~ to clear buffer, send on close paren. -#+BEGIN_SRC emacs-lisp -(keymap-global-set "C-c i" 'ielm) -(add-hook 'ielm-mode-hook - (lambda () - (keymap-set inferior-emacs-lisp-mode-map "C-l" 'comint-clear-buffer) - (keymap-set inferior-emacs-lisp-mode-map ")" 're/ielm-send-on-close-paren))) -#+END_SRC - -** Customize system -I do not use the customize system. I don't want to see it if I don't have to. -#+BEGIN_SRC emacs-lisp -(setq custom-file (expand-file-name "custom.el" user-emacs-directory)) -(when (not (file-exists-p custom-file)) - (make-empty-file custom-file)) - -(load custom-file) -#+END_SRC - -** Footer -#+BEGIN_SRC emacs-lisp -;;; hic terminatur init.el -#+END_SRC