From cfea700270a7de9cffea06de955288ecf24d9009 Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Sat, 2 Jan 2021 10:04:56 -0600 Subject: Update README --- README.md | 589 +++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 368 insertions(+), 221 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 02029dc..d6b2457 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Now, I'll *try* running it regular-style, ignoring the errors. If it doesn't work, I'll call git directly and clone the repo myself. (unless (ignore-errors (acdw/bootstrap-straight)) - (message "Straight.el didn't bootstrap correctly. Cloning directly...") + (message "%s" "Straight.el didn't bootstrap correctly. Cloning directly...") (call-process "git" nil (get-buffer-create "*bootstrap-straight-messages*") nil "clone" @@ -79,7 +79,10 @@ doesn't work, I'll call git directly and clone the repo myself. (acdw/bootstrap-straight)) -## Customize macro +## Customize macros + + +### Emulate use-package’s `:custom` (defmacro cuss (var val &optional docstring) "Basically, `:custom' from `use-package', but without `use-package'." @@ -89,76 +92,36 @@ doesn't work, I'll call git directly and clone the repo myself. ',var ,val)) -## Clean `.emacs.d` +### Emulate use-package’s `:custom-face`, but better - (straight-use-package 'no-littering) - (require 'no-littering) - - -## Look and feel + (defvar acdw--custom-faces () + "List of custom faces to run through acdw/set-custom-faces.") + + (defun acdw/set-custom-faces () + "Run `customize-set-faces' on `acdw--custom-faces'." + (message "%s" "Customizing faces...") + (apply #'custom-set-faces acdw--custom-faces)) + + (defun cussface (spec) + "Add SPEC to `acdw--custom-faces', and add a hook to run + `acdw/set-custom-faces' after init." + (add-to-list 'acdw--custom-faces spec) + (add-hook 'after-init-hook #'acdw/set-custom-faces)) -### Fonts +## Clean `.emacs.d` -1. Define fonts + (straight-use-package 'no-littering) + (require 'no-littering) - (defun set-face-from-alternatives (face fonts) - (catch :return - (dolist (font fonts) - (when (find-font (font-spec :family (car font))) - (apply #'set-face-attribute `(,face nil - :family ,(car font) - ,@(cdr font))) - (throw :return font))))) - - (defun acdw/setup-fonts () - "Setup fonts. This has to happen after the frame is setup for - the first time, so it should be added to `window-setup-hook'. It - removes itself from that hook." - (interactive) - (when (display-graphic-p) - (set-face-from-alternatives 'default - '(("Libertinus Mono" - :height 110) - ("Linux Libertine Mono O" - :height 110) - ("Go Mono" - :height 100) - ("Consolas" - :height 100))) - - (set-face-from-alternatives 'fixed-pitch - '(("Libertinus Mono" - :height 110) - ("Linux Libertine Mono O" - :height 110) - ("Go Mono" - :height 100) - ("Consolas" - :height 100))) - - (set-face-from-alternatives 'variable-pitch - '(("Libertinus Serif" - :height 120) - ("Linux Libertine O" - :height 120) - ("Georgia" - :height 110))) - - (remove-function after-focus-change-function #'acdw/setup-fonts))) - - (add-function :before after-focus-change-function #'acdw/setup-fonts) -2. Line spacing +### Don’t clutter `init.el` with customizations - (cuss line-spacing 0.1 - "Add 10% extra space below each line.") + (with-eval-after-load 'no-littering + (cuss custom-file (no-littering-expand-etc-file-name "custom.el"))) -3. Unicode Fonts - (straight-use-package 'unicode-fonts) - (require 'unicode-fonts) - (unicode-fonts-setup) +## Look and feel ### Cursor @@ -166,7 +129,7 @@ doesn't work, I'll call git directly and clone the repo myself. (cuss cursor-type 'bar "Show a vertical bar for the cursor.") - (cuss cursor-in-non-selected-windows 'hollow + (cuss cursor-in-non-selected-windows 'hbar "Show an empty box in inactive windows.") ;; Don't blink the cursor @@ -344,17 +307,68 @@ doesn't work, I'll call git directly and clone the repo myself. (load-theme 'modus-operandi t) -2. Change themes based on time of day - (cuss calendar-latitude 30.4515) - (cuss calendar-longitude -91.1871) +### Fonts + +1. Define fonts + + (defun set-face-from-alternatives (face fonts) + (catch :return + (dolist (font fonts) + (when (find-font (font-spec :family (car font))) + (apply #'set-face-attribute `(,face + nil + :family (car font) + ,@(cdr font))) + (throw :return font))))) + + (defun acdw/setup-fonts () + "Setup fonts. This has to happen after the frame is setup for + the first time, so it should be added to `window-setup-hook'. It + removes itself from that hook." + (interactive) + (when (display-graphic-p) + (set-face-from-alternatives 'default + '(("Input Mono" + :height 105) + ("Go Mono" + :height 100) + ("Consolas" + :height 100))) - (straight-use-package 'circadian) + (set-face-from-alternatives 'fixed-pitch + '(("Input Mono") + ("Go Mono") + ("Consolas"))) - (cuss circadian-themes '((:sunrise . modus-operandi) - (:sunset . modus-vivendi))) + (set-face-from-alternatives 'variable-pitch + '(("Input Serif") + ("Georgia"))) - (circadian-setup) + (remove-function after-focus-change-function #'acdw/setup-fonts))) + + (add-function :before after-focus-change-function #'acdw/setup-fonts) + +2. Custom faces + + (cussface '(font-lock-comment-face + ((t (:inherit (custom-comment italic variable-pitch)))))) + +3. Line spacing + + (cuss line-spacing 0.1 + "Add 10% extra space below each line.") + +4. Underlines + + (cuss x-underline-at-descent-line t + "Draw the underline at the same place as the descent line.") + +5. Unicode Fonts + + (straight-use-package 'unicode-fonts) + (require 'unicode-fonts) + (unicode-fonts-setup) ## Interactivity @@ -374,13 +388,18 @@ doesn't work, I'll call git directly and clone the repo myself. (cuss read-buffer-completion-ignore-case t) (cuss read-file-name-completion-ignore-case t) -3. Selectrum +3. Minibuffer recursivity + + (cuss enable-recursive-minibuffers t) + (minibuffer-depth-indicate-mode +1) + +4. Selectrum (straight-use-package 'selectrum) (require 'selectrum) (selectrum-mode +1) -4. Prescient +5. Prescient (straight-use-package 'prescient) (require 'prescient) @@ -390,7 +409,7 @@ doesn't work, I'll call git directly and clone the repo myself. (require 'selectrum-prescient) (selectrum-prescient-mode +1) -5. Consult +6. Consult (straight-use-package '(consult :host github @@ -402,27 +421,27 @@ doesn't work, I'll call git directly and clone the repo myself. :repo "minad/consult")) (require 'consult-selectrum) - (define-key ctl-x-map "b" #'consult-buffer) - (define-key ctl-x-map (kbd "C-r") #'consult-buffer) - (define-key ctl-x-map "4b" #'consult-buffer-other-window) - (define-key ctl-x-map "5b" #'consult-buffer-other-frame) + (with-eval-after-load 'consult + (define-key ctl-x-map "b" #'consult-buffer) + (define-key ctl-x-map (kbd "C-r") #'consult-buffer) + (define-key ctl-x-map "4b" #'consult-buffer-other-window) + (define-key ctl-x-map "5b" #'consult-buffer-other-frame) - (define-key goto-map "o" #'consult-outline) - (define-key goto-map "g" #'consult-line) - (define-key goto-map (kbd "M-g") #'consult-line) - (define-key goto-map "l" #'consult-line) - (define-key goto-map "m" #'consult-mark) - (define-key goto-map "k" #'consult-global-mark) - (define-key goto-map "i" #'consult-imenu) - (define-key goto-map "e" #'consult-error) + (define-key goto-map "o" #'consult-outline) + (define-key goto-map "g" #'consult-line) + (define-key goto-map (kbd "M-g") #'consult-line) + (define-key goto-map "l" #'consult-line) + (define-key goto-map "m" #'consult-mark) + (define-key goto-map "i" #'consult-imenu) + (define-key goto-map "e" #'consult-error) - (global-set-key (kbd "M-y") #'consult-yank-pop) + (global-set-key (kbd "M-y") #'consult-yank-pop) - (define-key help-map "a" #'consult-apropos) + (define-key help-map "a" #'consult-apropos) - (fset 'multi-occur #'consult-multi-occur) + (fset 'multi-occur #'consult-multi-occur)) -6. Marginalia +7. Marginalia (straight-use-package '(marginalia :host github @@ -436,6 +455,11 @@ doesn't work, I'll call git directly and clone the repo myself. (marginalia-mode +1) +### Completion + + (global-set-key (kbd "M-/") #'hippie-expand) + + ## Keyboard @@ -457,6 +481,22 @@ doesn't work, I'll call git directly and clone the repo myself. (run-hooks 'acdw/map-defined-hook) +## Mouse + + +### Preserve screen position when scrolling with the mouse wheel + +from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_tipstricketc_thread/ghg2c9d/). + + (advice-add 'mwheel-scroll :around #'me/mwheel-scroll) + + (defun me/mwheel-scroll (original &rest arguments) + "Like `mwheel-scroll' but preserve screen position. + See `scroll-preserve-screen-position'." + (let ((scroll-preserve-screen-position :always)) + (apply original arguments))) + + ## Persistence @@ -637,11 +677,22 @@ doesn't work, I'll call git directly and clone the repo myself. ### Searching & Replacing - (straight-use-package 'visual-regexp) - (require 'visual-regexp) - - (with-eval-after-load 'visual-regexp - (global-set-key (kbd "M-C-%") #'vr/query-replace)) +1. Replace with Anzu + + (straight-use-package 'anzu) + (require 'anzu) + + ;; show search count in the modeline + (global-anzu-mode +1) + + (cuss anzu-replace-to-string-separator " → " + "What to separate the search from the replacement.") + + (global-set-key [remap query-replace] #'anzu-query-replace) + (global-set-key [remap query-replace-regexp] #'anzu-query-replace-regexp) + + (define-key isearch-mode-map [remap isearch-query-replace] #'anzu-isearch-query-replace) + (define-key isearch-mode-map [remap isearch-query-replace-regexp] #'anzu-isearch-query-replace-regexp) # Programming @@ -731,7 +782,11 @@ This has to be done *before* loading the package. It's included in `visual-fill (global-set-key [left-margin mouse-wheel-down-event] #'mwheel-scroll) (global-set-key [left-margin mouse-wheel-up-event] #'mwheel-scroll) (global-set-key [left-margin wheel-down] #'mwheel-scroll) - (global-set-key [left-margin wheel-up] #'mwheel-scroll)) + (global-set-key [left-margin wheel-up] #'mwheel-scroll) + (global-set-key [right-margin mouse-4] #'mwheel-scroll) + (global-set-key [right-margin mouse-5] #'mwheel-scroll) + (global-set-key [left-margin mouse-4] #'mwheel-scroll) + (global-set-key [left-margin mouse-5] #'mwheel-scroll)) ### Load the package @@ -753,6 +808,11 @@ This has to be done *before* loading the package. It's included in `visual-fill ## Typographical niceties +### Variable pitch in text-modes + + (add-hook 'text-mode-hook #'variable-pitch-mode) + + ### Typo mode (straight-use-package 'typo) @@ -783,147 +843,225 @@ I’ve put org mode under Applications, as opposed to Writing, because it’s m (cuss org-fontify-whole-heading-line t) (cuss org-fontify-quote-and-verse-blocks t) (cuss org-pretty-entities t) - (cuss org-num-mode +1) (cuss org-src-tab-acts-natively t) (cuss org-src-fontify-natively t) (cuss org-src-window-setup 'current-window) (cuss org-confirm-babel-evaluate nil) (cuss org-directory "~/Org") + (cuss org-ellipsis "…") +1. Tags -### Org Agenda + (cuss org-tags-column 0 + "Show tags directly after the headline. + This is the best-looking option with variable-pitch fonts.") + + (cussface + '(org-tag + ((t + (:height 0.8 :weight normal :slant italic :foreground "grey40" :inherit + (variable-pitch)))))) - (cuss org-agenda-files (no-littering-expand-etc-file-name "agenda-files")) - - (if (and (stringp org-agenda-files) - (not (file-exists-p org-agenda-files))) - (with-temp-buffer (write-file org-agenda-files))) - - (define-key acdw/map (kbd "C-a") #'org-agenda) +### General -### [A better return in Org mode](http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/) +1. [Org Return: DWIM](https://github.com/alphapapa/unpackaged.el#org-return-dwim) - (require 'org-inlinetask) - - (defun scimax/org-return (&optional ignore) - "Add new list item, heading or table row with RET. - A double return on an empty element deletes it. - Use a prefix arg to get regular RET." - (interactive "P") - (if ignore - (org-return) - (cond + (defun unpackaged/org-element-descendant-of (type element) + "Return non-nil if ELEMENT is a descendant of TYPE. + TYPE should be an element type, like `item' or `paragraph'. + ELEMENT should be a list like that returned by `org-element-context'." + ;; MAYBE: Use `org-element-lineage'. + (when-let* ((parent (org-element-property :parent element))) + (or (eq type (car parent)) + (unpackaged/org-element-descendant-of type parent)))) + + ;;;###autoload + (defun unpackaged/org-return-dwim (&optional default) + "A helpful replacement for `org-return'. With prefix, call `org-return'. + + On headings, move point to position after entry content. In + lists, insert a new item or end the list, with checkbox if + appropriate. In tables, insert a new row or end the table." + ;; Inspired by John Kitchin: http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/ + (interactive "P") + (if default + (org-return) + (cond + ;; Act depending on context around point. + + ;; NOTE: I prefer RET to not follow links, but by uncommenting this block, links will be + ;; followed. + + ;; ((eq 'link (car (org-element-context))) + ;; ;; Link: Open it. + ;; (org-open-at-point-global)) + + ((org-at-heading-p) + ;; Heading: Move to position after entry content. + ;; NOTE: This is probably the most interesting feature of this function. + (let ((heading-start (org-entry-beginning-position))) + (goto-char (org-entry-end-position)) + (cond ((and (org-at-heading-p) + (= heading-start (org-entry-beginning-position))) + ;; Entry ends on its heading; add newline after + (end-of-line) + (insert "\n\n")) + (t + ;; Entry ends after its heading; back up + (forward-line -1) + (end-of-line) + (when (org-at-heading-p) + ;; At the same heading + (forward-line) + (insert "\n") + (forward-line -1)) + ;; FIXME: looking-back is supposed to be called with more arguments. + (while (not (looking-back (rx (repeat 3 (seq (optional blank) "\n"))) nil)) + (insert "\n")) + (forward-line -1))))) + + ((org-at-item-checkbox-p) + ;; Checkbox: Insert new item with checkbox. + (org-insert-todo-heading nil)) + + ((org-in-item-p) + ;; Plain list. Yes, this gets a little complicated... + (let ((context (org-element-context))) + (if (or (eq 'plain-list (car context)) ; First item in list + (and (eq 'item (car context)) + (not (eq (org-element-property :contents-begin context) + (org-element-property :contents-end context)))) + (unpackaged/org-element-descendant-of 'item context)) ; Element in list item, e.g. a link + ;; Non-empty item: Add new item. + (org-insert-item) + ;; Empty item: Close the list. + ;; TODO: Do this with org functions rather than operating on the text. Can't seem to find the right function. + (delete-region (line-beginning-position) (line-end-position)) + (insert "\n")))) + + ((when (fboundp 'org-inlinetask-in-task-p) + (org-inlinetask-in-task-p)) + ;; Inline task: Don't insert a new heading. + (org-return)) + + ((org-at-table-p) + (cond ((save-excursion + (beginning-of-line) + ;; See `org-table-next-field'. + (cl-loop with end = (line-end-position) + for cell = (org-element-table-cell-parser) + always (equal (org-element-property :contents-begin cell) + (org-element-property :contents-end cell)) + while (re-search-forward "|" end t))) + ;; Empty row: end the table. + (delete-region (line-beginning-position) (line-end-position)) + (org-return)) + (t + ;; Non-empty row: call `org-return'. + (org-return)))) + (t + ;; All other cases: call `org-return'. + (org-return))))) + + (with-eval-after-load 'org + (define-key org-mode-map (kbd "RET") #'unpackaged/org-return-dwim)) + +2. Insert blank lines around headers + + from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#ensure-blank-lines-between-headings-and-before-contents). - ((eq 'line-break (car (org-element-context))) - (org-return t)) + ;;;###autoload + (defun unpackaged/org-fix-blank-lines (&optional prefix) + "Ensure that blank lines exist between headings and between headings and their contents. + With prefix, operate on whole buffer. Ensures that blank lines + exist after each headings's drawers." + (interactive "P") + (org-map-entries (lambda () + (org-with-wide-buffer + ;; `org-map-entries' narrows the buffer, which prevents us + ;; from seeing newlines before the current heading, so we + ;; do this part widened. + (while (not (looking-back "\n\n" nil)) + ;; Insert blank lines before heading. + (insert "\n"))) + (let ((end (org-entry-end-position))) + ;; Insert blank lines before entry content + (forward-line) + (while (and (org-at-planning-p) + (< (point) (point-max))) + ;; Skip planning lines + (forward-line)) + (while (re-search-forward org-drawer-regexp end t) + ;; Skip drawers. You might think that `org-at-drawer-p' + ;; would suffice, but for some reason it doesn't work + ;; correctly when operating on hidden text. This + ;; works, taken from `org-agenda-get-some-entry-text'. + (re-search-forward "^[ \t]*:END:.*\n?" end t) + (goto-char (match-end 0))) + (unless (or (= (point) (point-max)) + (org-at-heading-p) + (looking-at-p "\n")) + (insert "\n")))) + t (if prefix + nil + 'tree))) - ;; Open links like usual, unless point is at the end of a line. - ;; and if at beginning of line, just press enter. - ((or (and (eq 'link (car (org-element-context))) (not (eolp))) - (bolp)) - (org-return)) + 1. Add a before-save-hook - ;; It doesn't make sense to add headings in inline tasks. Thanks Anders - ;; Johansson! - ((org-inlinetask-in-task-p) - (org-return)) + (defun cribbed/org-mode-fix-blank-lines () + (when (eq major-mode 'org-mode) + (let ((current-prefix-arg 4)) ; Emulate C-u + (call-interactively 'unpackaged/org-fix-blank-lines)))) + + (add-hook 'before-save-hook #'cribbed/org-mode-fix-blank-lines) + + +### Org Agenda + + (cuss org-agenda-files + (let ((list)) + (dolist (file '(;; add more files to this list + "home.org" + "work.org") + list) + (push (expand-file-name file org-directory) list)))) - ;; checkboxes too - ((org-at-item-checkbox-p) - (org-insert-todo-heading nil)) + (define-key acdw/map (kbd "C-a") #'org-agenda) - ;; lists end with two blank lines, so we need to make sure we are also not - ;; at the beginning of a line to avoid a loop where a new entry gets - ;; created with only one blank line. - ((org-in-item-p) - (if (save-excursion (beginning-of-line) (org-element-property :contents-begin (org-element-context))) - (org-insert-heading) - (beginning-of-line) - (delete-region (line-beginning-position) (line-end-position)) - (org-return))) + (cuss org-todo-keywords + '((sequence "RECUR(r)" "TODO(t)" "|" "DONE(d)") + (sequence "|" "CANCELLED(c)"))) + + +### TODO Capture + + +## Git + + (straight-use-package 'magit) - ;; org-heading - ((org-at-heading-p) - (if (not (string= "" (org-element-property :title (org-element-context)))) - (progn (org-end-of-meta-data) - (org-insert-heading-respect-content) - (outline-show-entry)) - (beginning-of-line) - (setf (buffer-substring - (line-beginning-position) (line-end-position)) ""))) + (define-key acdw/map "g" #'magit-status) + + +## Beancount mode + + (straight-use-package '(beancount-mode + :host github + :repo "beancount/beancount-mode")) + (require 'beancount) - ;; tables - ((org-at-table-p) - (if (-any? - (lambda (x) (not (string= "" x))) - (nth - (- (org-table-current-dline) 1) - (org-table-to-lisp))) - (org-return) - ;; empty row - (beginning-of-line) - (setf (buffer-substring - (line-beginning-position) (line-end-position)) "") - (org-return))) + (add-to-list 'auto-mode-alist '("\\.beancount\\'" . beancount-mode)) - ;; fall-through case - (t - (org-return))))) + (defun acdw/disable-aggressive-indent () + "Turn `aggressive-indent-mode' off for a buffer." + (aggressive-indent-mode -1)) + (add-hook 'beancount-mode-hook #'outline-minor-mode) + (add-hook 'beancount-mode-hook #'acdw/disable-aggressive-indent) - (define-key org-mode-map (kbd "RET") - 'scimax/org-return) - - -### Insert blank lines around headers - -from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#ensure-blank-lines-between-headings-and-before-contents). - - ;;;###autoload - (defun unpackaged/org-fix-blank-lines (&optional prefix) - "Ensure that blank lines exist between headings and between headings and their contents. - With prefix, operate on whole buffer. Ensures that blank lines - exist after each headings's drawers." - (interactive "P") - (org-map-entries (lambda () - (org-with-wide-buffer - ;; `org-map-entries' narrows the buffer, which prevents us - ;; from seeing newlines before the current heading, so we - ;; do this part widened. - (while (not (looking-back "\n\n" nil)) - ;; Insert blank lines before heading. - (insert "\n"))) - (let ((end (org-entry-end-position))) - ;; Insert blank lines before entry content - (forward-line) - (while (and (org-at-planning-p) - (< (point) (point-max))) - ;; Skip planning lines - (forward-line)) - (while (re-search-forward org-drawer-regexp end t) - ;; Skip drawers. You might think that `org-at-drawer-p' - ;; would suffice, but for some reason it doesn't work - ;; correctly when operating on hidden text. This - ;; works, taken from `org-agenda-get-some-entry-text'. - (re-search-forward "^[ \t]*:END:.*\n?" end t) - (goto-char (match-end 0))) - (unless (or (= (point) (point-max)) - (org-at-heading-p) - (looking-at-p "\n")) - (insert "\n")))) - t (if prefix - nil - 'tree))) - -1. Add a before-save-hook - - (defun cribbed/org-mode-fix-blank-lines () - (when (eq major-mode 'org-mode) - (let ((current-prefix-arg 4)) ; Emulate C-u - (call-interactively 'unpackaged/org-fix-blank-lines)))) - - (add-hook 'before-save-hook #'cribbed/org-mode-fix-blank-lines) + (define-key beancount-mode-map (kbd "M-n") #'outline-next-visible-heading) + (define-key beancount-mode-map (kbd "M-p") #'outline-previous-visible-heading) # Appendices @@ -968,7 +1106,7 @@ I realized I didn’t need `early-init.el`, since it really only set `load-prefe (when (file-newer-than-file-p config (expand-file-name "README.md" user-emacs-directory)) - (message "Exporting README.md...") + (message "%s" "Exporting README.md...") (require 'ox-md) (with-demoted-errors "Problem exporting README.md: %S" (org-md-export-to-markdown))) @@ -976,11 +1114,11 @@ I realized I didn’t need `early-init.el`, since it really only set `load-prefe (when (file-newer-than-file-p config (expand-file-name "config.el" user-emacs-directory)) - (message "Tangling config.org...") + (message "%s" "Tangling config.org...") (require 'org) (let ((inits (org-babel-tangle))) ;; byte-compile resulting files - (message "Byte-compiling...") + (message "%s" "Byte-compiling...") (dolist (f inits) (when (string-match "\\.el\\'" f) (byte-compile-file f (not disable-load))))))))))) @@ -991,7 +1129,7 @@ I realized I didn’t need `early-init.el`, since it really only set `load-prefe ### emacsdc -Here's a wrapper script that'll start `emacs –daemon` if there isn't +Here's a wrapper script that'll start `emacs --daemon` if there isn't one, and then launch `emacsclient` with the arguments. I'd recommend installing with either `ln -s bin/emacsdc $HOME/.local/bin/`, or adding `$HOME/.local/bin` to your `$PATH`. @@ -1004,9 +1142,18 @@ adding `$HOME/.local/bin` to your `$PATH`. ### Emacs.cmd -Here’s a wrapper script that’ll run Emacs on Windows, with a custom `$HOME`. I have mine setup like this: Emacs is downloaded from [the GNU mirror](https://mirrors.tripadvisor.com/gnu/emacs/windows/emacs-27/emacs-27.1-x86_64.zip) and unzipped to `~/Downloads/emacs/`. `Emacs.cmd` sets `$HOME` to `~/Downloads/emacshome/`, which is where `.emacs.d` is, and whatever else I might want to throw in there. +Here's a wrapper script that'll run Emacs on Windows, with a custom +`$HOME`. I have mine setup like this: Emacs is downloaded from [the +GNU mirror](https://mirrors.tripadvisor.com/gnu/emacs/windows/emacs-27/emacs-27.1-x86_64.zip) and unzipped to `~/Downloads/emacs/`. `Emacs.cmd` sets +`$HOME` to `~/Downloads/emacshome/`, which is where `.emacs.d` is, and +whatever else I might want to throw in there. set HOME=%~dp0..\..\emacshome + + REM Run "Quick Mode" + REM "%~dp0runemacs.exe" -Q %* + + REM Regular "%~dp0runemacs.exe" %* -- cgit 1.4.1-21-gabe81