2020-01-21
This commit is contained in:
parent
3514f0b408
commit
92e86ff0ca
752
config.org
752
config.org
|
@ -8,13 +8,21 @@
|
|||
user-mail-address "acdw@acdw.net")
|
||||
#+end_src
|
||||
|
||||
** Where I am
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq calendar-location-name "Baton Rouge, LA"
|
||||
calendar-latitude 30.4
|
||||
calendar-longitude -91.1)
|
||||
#+end_src
|
||||
|
||||
* Look and feel
|
||||
|
||||
** Frames
|
||||
|
||||
*** Initial frame setup
|
||||
:PROPERTIES:
|
||||
:header-args: :noweb-ref initial-frame-setup
|
||||
:header-args: :noweb-ref early-init-frame
|
||||
:END:
|
||||
|
||||
I tangle this section to =early-init.el=, since that's evaluated
|
||||
|
@ -50,6 +58,16 @@ of unstyled content" thing.
|
|||
(horizontal-scroll-bar-mode -1)
|
||||
#+end_src
|
||||
|
||||
**** Resizing
|
||||
|
||||
I don't want the frame to resize when I change fonts and stuff, and I
|
||||
want it to resize by pixels -- we /are/ using a GUI, after all.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq-default frame-inhibit-implied-resize t
|
||||
frame-resize-pixelwise t)
|
||||
#+end_src
|
||||
|
||||
*** Frame titles
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
|
@ -276,10 +294,14 @@ At the end of this function, it removes itself from
|
|||
removes itself from that hook."
|
||||
(interactive)
|
||||
(set-face-from-alternatives 'default nil
|
||||
'(:family "Input Mono"
|
||||
'(:family "Iosevka Acdw"
|
||||
:slant normal
|
||||
:weight normal
|
||||
:height 110)
|
||||
:height 105)
|
||||
'(:family "Iosevka Extended"
|
||||
:slant normal
|
||||
:weight normal
|
||||
:height 105)
|
||||
'(:family "Consolas"
|
||||
:slant normal
|
||||
:weight normal
|
||||
|
@ -288,7 +310,7 @@ At the end of this function, it removes itself from
|
|||
(set-face-attribute 'fixed-pitch nil :inherit 'default)
|
||||
;; variable-pitch is different
|
||||
(set-face-from-alternatives 'variable-pitch nil
|
||||
'(:family "Input Sans"
|
||||
'(:family "DejaVu Sans"
|
||||
:slant normal
|
||||
:weight normal)
|
||||
'(:family "Georgia"
|
||||
|
@ -317,6 +339,53 @@ underline below all the text.
|
|||
(setq-default x-underline-at-descent-line t)
|
||||
#+end_src
|
||||
|
||||
** Theming
|
||||
|
||||
*** Modus themes
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref packages
|
||||
(straight-use-package 'modus-themes)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default modus-themes-slanted-constructs t
|
||||
modus-themes-bold-constructs t
|
||||
modus-themes-region 'bg-only
|
||||
modus-themes-org-blocks 'grayscale
|
||||
modus-themes-headings '((1 . line)
|
||||
(t . t))
|
||||
modus-themes-scale-headings nil)
|
||||
#+end_src
|
||||
|
||||
*** Change themes based on time of day
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref functions
|
||||
(defun acdw/run-with-sun (sunrise-command sunset-command)
|
||||
"Run commands at sunrise and sunset."
|
||||
(let* ((times-regex (rx (* nonl)
|
||||
(: (any ?s ?S) "unrise") " "
|
||||
(group (repeat 1 2 digit) ":"
|
||||
(repeat 1 2 digit)
|
||||
(: (any ?a ?A ?p ?P) (any ?m ?M)))
|
||||
(* nonl)
|
||||
(: (any ?s ?S) "unset") " "
|
||||
(group (repeat 1 2 digit) ":"
|
||||
(repeat 1 2 digit)
|
||||
(: (any ?a ?A ?p ?P) (any ?m ?M)))
|
||||
(* nonl)))
|
||||
(ss (sunrise-sunset))
|
||||
(_m (string-match times-regex ss))
|
||||
(sunrise-time (match-string 1 ss))
|
||||
(sunset-time (match-string 2 ss)))
|
||||
(run-at-time sunrise-time (* 60 60 24) sunrise-command)
|
||||
(run-at-time sunset-time (* 60 60 24) sunset-command)))
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(acdw/run-with-sun #'modus-themes-load-operandi
|
||||
#'modus-themes-load-vivendi)
|
||||
#+end_src
|
||||
|
||||
* Interactivity
|
||||
|
||||
** Dialogs and alerts
|
||||
|
@ -468,6 +537,14 @@ with that.
|
|||
(recentf-mode +1)
|
||||
#+end_src
|
||||
|
||||
I also want to ignore the =no-littering-var-directory= and
|
||||
=no-littering-etc-directory=, since those aren't useful.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref no-littering
|
||||
(add-to-list 'recentf-exclude no-littering-var-directory)
|
||||
(add-to-list 'recentf-exclude no-littering-etc-directory)
|
||||
#+end_src
|
||||
|
||||
*** Save the recentf list periodically
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref functions
|
||||
|
@ -500,6 +577,7 @@ the user is looking at something else.
|
|||
#+begin_src emacs-lisp :noweb-ref functions
|
||||
(defun when-unfocused (func &rest args)
|
||||
"Run FUNC, with ARGS, iff all frames are out of focus."
|
||||
(require 'seq)
|
||||
(when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list)))
|
||||
(apply func args)))
|
||||
#+end_src
|
||||
|
@ -546,16 +624,559 @@ Notepad can handle UNIX line endings, so I don't want to hear it.
|
|||
|
||||
** Keep =~/.emacs.d= clean :package:
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref packages :noweb yes
|
||||
(straight-use-package 'no-littering)
|
||||
(require 'no-littering)
|
||||
(with-eval-after-load 'no-littering
|
||||
<<no-littering>>
|
||||
) ; end of no-littering
|
||||
#+end_src
|
||||
|
||||
** Backups
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default backup-by-copying t
|
||||
;; Don't delete old versions
|
||||
delete-old-versions -1
|
||||
;; Make numeric backups unconditionally
|
||||
version-control t
|
||||
;; Also backup files covered by version control
|
||||
vc-make-backup-files t)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref no-littering
|
||||
(let ((dir (no-littering-expand-var-file-name "backup")))
|
||||
(make-directory dir :parents)
|
||||
(setq-default backup-directory-alist
|
||||
`((".*" . ,dir))))
|
||||
#+end_src
|
||||
|
||||
** Autosaves :package:
|
||||
|
||||
I don't use the =auto-save= system, preferring instead to use
|
||||
Bozhidar Batsov's [[https://github.com/bbatsov/super-save][super-save]] package.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default auto-save-default nil)
|
||||
|
||||
(setq-default super-save-remote-files nil
|
||||
super-save-exclude '(".gpg")
|
||||
super-save-auto-save-when-idle t)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref packages
|
||||
(straight-use-package 'super-save)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref modes
|
||||
(super-save-mode +1)
|
||||
#+end_src
|
||||
|
||||
** Auto-revert files
|
||||
|
||||
I like to keep the buffers Emacs has in-memory in sync with the actual
|
||||
contents of the files the represent on-disk. Thus, we have
|
||||
=auto-revert-mode=.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default auto-revert-verbose nil)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref modes
|
||||
(global-auto-revert-mode +1)
|
||||
#+end_src
|
||||
|
||||
|
||||
* Editing
|
||||
|
||||
** Lines
|
||||
|
||||
*** Auto-fill vs. Visual-line
|
||||
|
||||
I've mostly been using visual-line mode, and it's been pretty good.
|
||||
There are some times, however, when lines are just ... really long,
|
||||
and they wrap weird or whatever. Not to mention, in Org mode,
|
||||
=visual-line-mode= screws up the bindings for line movement. So
|
||||
here's what I'm going to do.
|
||||
|
||||
1. Enable =visual-line-mode= with =text-mode=, but /not/ with
|
||||
=org-mode=.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(defun hook--visual-line-mode ()
|
||||
(unless (eq major-mode 'org-mode)
|
||||
(visual-line-mode +1)))
|
||||
|
||||
(add-hook 'text-mode-hook #'hook--visual-line-mode)
|
||||
#+end_src
|
||||
|
||||
2. Enable =auto-fill-mode= with =org-mode=.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(add-hook 'org-mode-hook #'auto-fill-mode)
|
||||
#+end_src
|
||||
|
||||
3. /Just/ in case ... let's "fix" =visual-line-mode= if we're in =org-mode=.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(defun hook--visual-line-fix-org-keys ()
|
||||
(when (derived-mode-p 'org-mode)
|
||||
(local-set-key (kbd "C-a") #'org-beginning-of-line)
|
||||
(local-set-key (kbd "C-e") #'org-end-of-line)
|
||||
(local-set-key (kbd "C-k") #'org-kill-line)))
|
||||
|
||||
(add-hook 'visual-line-mode-hook #'hook--visual-line-fix-org-keys)
|
||||
|
||||
#+end_src
|
||||
|
||||
I think that'll work -- I only care about line aesthetics with text.
|
||||
Programming modes should be /allowed/ to have long lines, regardless
|
||||
of how /terrible/ it is to have them.
|
||||
|
||||
*** Stay snappy with long-lined files
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref modes
|
||||
(when (fboundp 'global-so-long-mode)
|
||||
(global-so-long-mode +1))
|
||||
#+end_src
|
||||
|
||||
** Whitespace
|
||||
|
||||
*** Whitespace style
|
||||
|
||||
The =whitespace-style= defines what kinds of whitespace to clean up on
|
||||
=whitespace-cleanup=, as well as what to highlight (if that option is
|
||||
enabled).
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default whitespace-style '(empty ; remove blank lines at buffer edges
|
||||
indentation ; clean up indentation
|
||||
;; fix mixed spaces and tabs
|
||||
space-before-tab
|
||||
space-after-tab))
|
||||
#+end_src
|
||||
|
||||
*** Clean up whitespace on save
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(add-hook 'before-save-hook #'whitespace-cleanup)
|
||||
#+end_src
|
||||
|
||||
*** Don't use TABs
|
||||
|
||||
I was team TAB for a while, but I find them easier to avoid in Emacs.
|
||||
It manages my whitespace for me, anyway.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default indent-tabs-mode nil)
|
||||
#+end_src
|
||||
|
||||
** Killing & Yanking
|
||||
|
||||
*** Replace the selection when typing
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref modes
|
||||
(delete-selection-mode +1)
|
||||
#+end_src
|
||||
|
||||
*** Work better with the system clipboard
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default
|
||||
;; Save existing clipboard text to the kill ring before replacing it.
|
||||
save-interprogram-paste-before-kill t
|
||||
;; Update the X selection when rotating the kill ring.
|
||||
yank-pop-change-selection t
|
||||
;; Enable clipboards
|
||||
x-select-enable-clipboard t
|
||||
x-select-enable-primary t
|
||||
;; Copy a region when it's selected with the mouse
|
||||
mouse-drag-copy-region t)
|
||||
#+end_src
|
||||
|
||||
*** Don't append the same thing twice to the kill ring
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default kill-do-not-save-duplicates t)
|
||||
#+end_src
|
||||
|
||||
** Overwrite mode
|
||||
|
||||
*** Change the cursor
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(defun hook--overwrite-mode-change-cursor ()
|
||||
(setq cursor-type (if overwrite-mode t 'bar)))
|
||||
|
||||
(add-hook 'overwrite-mode-hook #'hook--overwrite-mode-change-cursor)
|
||||
#+end_src
|
||||
|
||||
** The Mark
|
||||
|
||||
*** Repeat popping the mark without repeating the prefix argument
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default set-mark-repeat-command-pop t)
|
||||
#+end_src
|
||||
|
||||
* Writing
|
||||
|
||||
** Word count :package:
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref packages
|
||||
(straight-use-package 'wc-mode)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(add-hook 'text-mode-hook #'wc-mode)
|
||||
#+end_src
|
||||
|
||||
* Programming
|
||||
|
||||
** Comments
|
||||
|
||||
*** Auto fill comments in programming modes
|
||||
|
||||
Okay, so I lied in the [[*Auto-fill vs. Visual-line][Auto-fill vs. Visual-line]] section. I /do/ want
|
||||
to auto-fill in programming modes, but /only/ the comments.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(defun hook--comment-auto-fill ()
|
||||
(setq-local comment-auto-fill-only-comments t)
|
||||
(auto-fill-mode +1))
|
||||
|
||||
(add-hook 'prog-mode-hook #'hook--comment-auto-fill)
|
||||
#+end_src
|
||||
|
||||
** Parentheses
|
||||
|
||||
*** Show parentheses
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref modes
|
||||
(show-paren-mode +1)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default show-paren-delay 0
|
||||
;; Show the matching paren if visible, else the whole expression
|
||||
show-paren-style 'mixed)
|
||||
#+end_src
|
||||
|
||||
** Executable scripts
|
||||
|
||||
This poorly-named function will make a file executable if it looks
|
||||
like a script (looking at the function definition, it looks like it
|
||||
checks for a shebang).
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(add-hook 'after-save-hook
|
||||
#'executable-make-buffer-file-executable-if-script-p)
|
||||
#+end_src
|
||||
|
||||
** Language-specific
|
||||
|
||||
*** Emacs Lisp
|
||||
|
||||
**** Don't limit the length of evaluated expressions
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default eval-expression-print-length nil
|
||||
eval-expression-print-level nil)
|
||||
#+end_src
|
||||
|
||||
**** Indent Elisp like Common Lisp
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref requires
|
||||
(require 'cl-lib)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default lisp-indent-function #'common-lisp-indent-function)
|
||||
#+end_src
|
||||
|
||||
|
||||
* Applications
|
||||
|
||||
Emacs is well-known for its ability to subsume one's entire computing
|
||||
life. There are a few /killer apps/ that make Emacs really shine.
|
||||
Here, I configure them and a few others.
|
||||
|
||||
My rubric for what makes a package an application, versus just a
|
||||
package, is mostly based on the way I feel about it. Don't expect to
|
||||
agree with all of my choices.
|
||||
|
||||
** Web browsing
|
||||
|
||||
*** Browse-url
|
||||
|
||||
I like using Firefox.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default browse-url-browser-function 'browse-url-firefox
|
||||
browse-url-new-window-flag t
|
||||
browse-url-firefox-new-window-is-tab t)
|
||||
#+end_src
|
||||
|
||||
At work, I need to tell Emacs where Firefox is.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref windows-specific
|
||||
(add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")
|
||||
#+end_src
|
||||
|
||||
** Dired
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(defun hook--dired-mode ()
|
||||
(hl-line-mode +1)
|
||||
(dired-hide-details-mode +1))
|
||||
|
||||
(add-hook 'dired-mode-hook #'hook--dired-mode)
|
||||
#+end_src
|
||||
|
||||
A note on =dired-listing-switches=: when I'm able to figure out how to
|
||||
move up a directory with a keybinding, I'll change =-a= to =-A=.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default dired-recursive-copies 'always
|
||||
dired-recursive-deletes 'always
|
||||
delete-by-moving-to-trash t
|
||||
dired-listing-switches "-alh")
|
||||
#+end_src
|
||||
|
||||
*** Expand subtrees :package:
|
||||
|
||||
Instead of opening each folder in its own buffer, =dired-subtree=
|
||||
enables me to open them in the same buffer, fancily indented.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref packages
|
||||
(straight-use-package 'dired-subtree)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref bindings
|
||||
(with-eval-after-load 'dired
|
||||
(define-key dired-mode-map "i" #'dired-subtree-toggle))
|
||||
#+end_src
|
||||
|
||||
*** Collapse singleton directories
|
||||
|
||||
If a directory only has one item in it, =dired-collapse= shows what
|
||||
that one item is.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref packages
|
||||
(straight-use-package 'dired-subtree)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref hooks
|
||||
(add-hook 'dired-mode-hook #'dired-collapse-mode)
|
||||
#+end_src
|
||||
|
||||
** Org mode
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref packages
|
||||
(straight-use-package 'org)
|
||||
|
||||
(with-eval-after-load 'org
|
||||
(require 'org-tempo)
|
||||
(require 'ox-md))
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(setq-default
|
||||
;; Where to look for Org files
|
||||
org-directory "~/org" ; this is the default
|
||||
;; Fontify stuff
|
||||
org-hide-emphasis-markers t
|
||||
org-fontify-whole-heading-line t
|
||||
org-fontify-done-headline t
|
||||
org-fontify-quote-and-verse-blocks t
|
||||
org-src-fontify-natively t
|
||||
org-ellipsis "…"
|
||||
org-pretty-entities t
|
||||
;; Source blocks
|
||||
org-src-tab-acts-natively t
|
||||
org-src-window-setup 'current-window ; could change this
|
||||
org-confirm-babel-evaluate nil
|
||||
;; Behavior
|
||||
org-adapt-indentation nil ; don't indent things
|
||||
org-catch-invisible-edits 'smart ; let's try this
|
||||
org-special-ctrl-a/e t
|
||||
org-special-ctrl-k t
|
||||
;; Exporting
|
||||
org-export-headline-levels 8)
|
||||
#+end_src
|
||||
|
||||
*** Org templates
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref settings
|
||||
(with-eval-after-load 'org-tempo
|
||||
(dolist (cell '(("el" . "src emacs-lisp")
|
||||
("cr" . "src emacs-lisp :noweb-ref requires")
|
||||
("cf" . "src emacs-lisp :noweb-ref functions")
|
||||
("cs" . "src emacs-lisp :noweb-ref settings")
|
||||
("cm" . "src emacs-lisp :noweb-ref modes")
|
||||
("cl" . "src emacs-lisp :noweb-ref linux-specific")
|
||||
("cw" . "src emacs-lisp :noweb-ref windows-specific")
|
||||
("cp" . "src emacs-lisp :noweb-ref packages")
|
||||
("ch" . "src emacs-lisp :noweb-ref hooks")
|
||||
("cb" . "src emacs-lisp :noweb-ref bindings")
|
||||
("cnl" . "src emacs-lisp :noweb-ref no-littering")))
|
||||
(add-to-list 'org-structure-template-alist cell)))
|
||||
#+end_src
|
||||
|
||||
*** Org Return: DWIM :unpackaged:
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref functions
|
||||
(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))))
|
||||
|
||||
(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)))))
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref bindings
|
||||
(with-eval-after-load 'org
|
||||
(define-key org-mode-map (kbd "RET") #'unpackaged/org-return-dwim))
|
||||
#+end_src
|
||||
|
||||
|
||||
* Package management :package:
|
||||
:PROPERTIES:
|
||||
:header-args: :noweb-ref package-bootstrap
|
||||
:header-args: :noweb-ref early-init-package
|
||||
:END:
|
||||
|
||||
Emacs is the /extensible/ editor, and that means I want to use
|
||||
third-party packages. Of course, first I have to /manage/ those
|
||||
packages. I use the excellent =straight.el=.
|
||||
|
||||
** TODO Update the PATH
|
||||
** Update the PATH
|
||||
|
||||
PATH handling on Emacs is a little complicated. There's the regular
|
||||
environment variable =$PATH=, which we all know and love, and then
|
||||
Emacs has its own special =exec-path= on /top/ of that. From my
|
||||
research, it looks like Emacs uses =exec-path= for itself, and =$PATH=
|
||||
for any shells or other processes it spawns. They don't /have/ to be
|
||||
the same, but luckily for us, Emacs sets =exec-path= from =$PATH= on
|
||||
initialization, so when I add stuff to =exec-path= to, say, run git, I
|
||||
can just change =$PATH= right back to the expanded =exec-path= without
|
||||
any data loss. Here's what all that looks like.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(let ((win-app-dir "~/Applications"))
|
||||
(dolist (path (list
|
||||
;; Windows
|
||||
(expand-file-name "Git/bin" win-app-dir)
|
||||
(expand-file-name "Git/usr/bin" win-app-dir)
|
||||
(expand-file-name "Git/mingw64/bin" win-app-dir)
|
||||
;; Linux
|
||||
(expand-file-name "bin"
|
||||
user-emacs-directory)
|
||||
(expand-file-name "~/bin")
|
||||
(expand-file-name "~/.local/bin")
|
||||
(expand-file-name "~/Scripts")
|
||||
))
|
||||
(when (file-exists-p path)
|
||||
(add-to-list 'exec-path path :append))))
|
||||
|
||||
;; Set $PATH
|
||||
(setenv "PATH" (mapconcat #'identity exec-path path-separator))
|
||||
#+end_src
|
||||
|
||||
*** References
|
||||
|
||||
- [[https://emacs.stackexchange.com/questions/550/exec-path-and-path][exec-path and $PATH (StackExchange)]]
|
||||
- [[https://utoi.tistory.com/entry/Difference-Between-Emacss-%E2%80%9Cgetenv-PATH%E2%80%9D-and-%E2%80%9Cexec-path%E2%80%9D][Difference between Emacs's "(getenv PATH)" and "exec-path" (U&I)]]
|
||||
- [[https://emacs.stackexchange.com/questions/27326/gui-emacs-sets-the-exec-path-only-from-windows-environment-variable-but-not-from][GUI Emacs sets the exec-path only from Windows environment variable
|
||||
but not from .emacs file (StackExchange)]]
|
||||
|
||||
** Disable =package.el=
|
||||
|
||||
|
@ -594,6 +1215,7 @@ directly. If it errors (it tends to on Windows), I'll directly clone
|
|||
the repo using git, /then/ run the bootstrap code.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(when (executable-find "git")
|
||||
(unless (ignore-errors (acdw/bootstrap-straight))
|
||||
(let ((msg "Straight.el didn't bootstrap correctly. Cloning directly"))
|
||||
(message "%s..." msg)
|
||||
|
@ -604,7 +1226,7 @@ the repo using git, /then/ run the bootstrap code.
|
|||
(expand-file-name "straight/repos/straight.el"
|
||||
user-emacs-directory))
|
||||
(message "%s...Done." msg)
|
||||
(acdw/bootstrap-straight)))
|
||||
(acdw/bootstrap-straight))))
|
||||
#+end_src
|
||||
|
||||
* System-specific
|
||||
|
@ -615,9 +1237,13 @@ settings and written some ancillary scripts.
|
|||
|
||||
** Determine where I am
|
||||
:PROPERTIES:
|
||||
:header-args: :noweb-ref functions
|
||||
:header-args: :noweb-ref when-at
|
||||
:END:
|
||||
|
||||
This macro needs to go into =init.el=, /before/ loading =config.el= --
|
||||
because I've used the =when-at= form in the =:tangle= directive for
|
||||
the scripts in this section.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defmacro when-at (conditions &rest commands)
|
||||
"Run COMMANDS, or let the user know, when at a specific place.
|
||||
|
@ -663,7 +1289,7 @@ Here's a wrapper script that'll start =emacs --daemon= if there isn't
|
|||
one, and then launch =emacsclient= with the arguments. Install it to
|
||||
your =$PATH= somewhere.
|
||||
|
||||
#+begin_src sh :shebang "#!/bin/sh" :tangle (when-at :home "~/bin/em")
|
||||
#+begin_src sh :shebang "#!/bin/sh" :tangle (if (eq system-type 'gnu/linux) "~/bin/em" "")
|
||||
if ! emacsclient -nc "$@"; then
|
||||
emacs --daemon
|
||||
emacsclient -nc "$@"
|
||||
|
@ -678,7 +1304,7 @@ your =$PATH= somewhere.
|
|||
I haven't really tested this yet, but it should allow me to open other
|
||||
files and things in Emacs. From [[https://www.taingram.org/blog/emacs-client.html][taingram]].
|
||||
|
||||
#+begin_src conf-desktop :tangle (when-at :home "~/.local/share/applications/emacsclient.desktop")
|
||||
#+begin_src conf-desktop :tangle (if (eq system-type 'gnu/linux) "~/.local/share/applications/emacsclient.desktop" "")
|
||||
[Desktop Entry]
|
||||
Name=Emacs Client
|
||||
GenericName=Text Editor
|
||||
|
@ -713,10 +1339,10 @@ section come from [[https://github.com/termitereform/JunkPile/blob/master/emacs-
|
|||
|
||||
**** Common variables
|
||||
|
||||
#+NAME: w32-bat-common
|
||||
#+begin_src bat
|
||||
#+begin_src bat :noweb-ref w32-bat-common
|
||||
set HOME=%~dp0..\..
|
||||
set EMACS=%HOME%\Applications\Emacs\bin\runemacs.exe
|
||||
chdir %HOME%
|
||||
#+end_src
|
||||
|
||||
**** Emacs Daemon
|
||||
|
@ -725,7 +1351,7 @@ Either run this once at startup, or put a shortcut of it in the
|
|||
Startup folder:
|
||||
=%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup=.
|
||||
|
||||
#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Daemon.cmd")
|
||||
#+begin_src bat :tangle (if (eq system-type 'windows-nt) "~/Applications/cmd/Emacs Daemon.cmd" "")
|
||||
<<w32-bat-common>>
|
||||
%EMACS% --daemon
|
||||
#+end_src
|
||||
|
@ -737,7 +1363,7 @@ run =runemacs.exe=.
|
|||
|
||||
*This is the main shortcut for running Emacs.*
|
||||
|
||||
#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs.cmd")
|
||||
#+begin_src bat :tangle (if (eq system-type 'windows-nt) "~/Applications/cmd/Emacs.cmd" "")
|
||||
<<w32-bat-common>>
|
||||
set EMACSC=%HOME%\Applications\Emacs\bin\emacsclientw.exe
|
||||
"%EMACSC%" -n -c -a "%EMACS%" %*
|
||||
|
@ -747,7 +1373,7 @@ set EMACSC=%HOME%\Applications\Emacs\bin\emacsclientw.exe
|
|||
|
||||
This runs Emacs with the factory settings.
|
||||
|
||||
#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Safe Start.cmd")
|
||||
#+begin_src bat :tangle (if (eq system-type 'windows-nt) "~/Applications/cmd/Emacs Safe Start.cmd" "")
|
||||
<<w32-bat-common>>
|
||||
"%EMACS%" -Q %*
|
||||
#+end_src
|
||||
|
@ -756,7 +1382,7 @@ This runs Emacs with the factory settings.
|
|||
|
||||
This runs Emacs with the =--debug-init= option enabled.
|
||||
|
||||
#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Debug.cmd")
|
||||
#+begin_src bat :tangle (if (eq system-type 'windows-nt) "~/Applications/cmd/Emacs Debug.cmd" "")
|
||||
<<w32-bat-common>>
|
||||
"%EMACS%" --debug-init %*
|
||||
#+end_src
|
||||
|
@ -794,20 +1420,25 @@ my config here /logically/, while keeping the generated file organized
|
|||
;;; REQUIRES
|
||||
<<requires>>
|
||||
;;; PACKAGES
|
||||
;; straight.el depends on git, which /should be/ find-able by the PATH
|
||||
;; manipulation in early-init.el. Just in case, though, we'll check
|
||||
;; that we can find git.
|
||||
(when (executable-find "git")
|
||||
<<packages>>
|
||||
)
|
||||
;;; FUNCTIONS
|
||||
<<functions>>
|
||||
;;; SETTINGS
|
||||
<<settings>>
|
||||
;;; MODES
|
||||
<<modes>>
|
||||
;;; SYSTEM-DEPENDENT SETTINGS
|
||||
(when-at :home
|
||||
<<linux-specific>>
|
||||
)
|
||||
) ; end when-at :home
|
||||
(when-at :work
|
||||
<<windows-specific>>
|
||||
)
|
||||
) ; end when-at :work
|
||||
;;; MODES
|
||||
<<modes>>
|
||||
;;; HOOKS
|
||||
<<hooks>>
|
||||
;;; BINDINGS
|
||||
|
@ -836,6 +1467,14 @@ The classic Emacs initiation file.
|
|||
(setq-default load-prefer-newer t)
|
||||
#+end_src
|
||||
|
||||
**** =when-at=
|
||||
|
||||
See [[*Determine where I am][the definition above]] for rationale as to why this is here.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
<<when-at>>
|
||||
#+end_src
|
||||
|
||||
**** Load the config
|
||||
|
||||
I keep most of my config in =config.el=, which is tangled directly
|
||||
|
@ -877,46 +1516,13 @@ Beginning with 27.1, Emacs also loads an =early-init.el= file, before
|
|||
the package manager or the UI code. The Info says we should put as
|
||||
little as possible in this file, so I only have what I need.
|
||||
|
||||
**** Don't byte-compile this file
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
;; early-init.el -*- no-byte-compile: t; -*-
|
||||
<<disclaimer>>
|
||||
#+end_src
|
||||
|
||||
**** Package management
|
||||
|
||||
Since =early-init.el= loads before the built-in package manager
|
||||
initializes, I disable it and bootstrap my package manager of choice,
|
||||
=straight.el=.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
<<package-bootstrap>>
|
||||
#+end_src
|
||||
|
||||
**** Don't resize the frame when loading fonts
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq-default frame-inhibit-implied-resize t)
|
||||
#+end_src
|
||||
|
||||
**** Resize frame by pixels
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq-default frame-resize-pixelwise t)
|
||||
#+end_src
|
||||
|
||||
**** Shoe-horned from elsewhere in =config.org=
|
||||
|
||||
A fundamental tension of literal programming is logical versus
|
||||
programmatic ordering. I understand that's a problem it's meant to
|
||||
solve but hey, maybe I'm not quite there yet. I feel that having this
|
||||
weird shoe-horning of other bits of my config here, in a backwater
|
||||
heading in an appendix, isn't quite the future I wanted. But it's
|
||||
what I have for now.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
<<initial-frame-setup>>
|
||||
;; BOOTSTRAP PACKAGE MANAGEMENT
|
||||
<<early-init-package>>
|
||||
;; SETUP FRAME
|
||||
<<early-init-frame>>
|
||||
#+end_src
|
||||
|
||||
** License
|
||||
|
@ -924,7 +1530,7 @@ what I have for now.
|
|||
:header-args: :tangle LICENSE
|
||||
:END:
|
||||
|
||||
Copyright © 2020 Case Duckworth <acdw@acdw.net>
|
||||
Copyright © 2020 Case Duckworth <acdw@acdw.net>
|
||||
|
||||
This work is free. You can redistribute it and/or modify it under the
|
||||
terms of the Do What the Fuck You Want To Public License, Version 2,
|
||||
|
@ -954,33 +1560,3 @@ It's highly likely that the WTFPL is completely incompatible with the
|
|||
GPL, for what should be fairly obvious reasons. To that, I say:
|
||||
|
||||
*SUE ME, RMS!*
|
||||
|
||||
** Make it easier to edit =config.org= :noexport:
|
||||
|
||||
Because I use a lot of =:noweb-ref= directives in this file, editing
|
||||
it can be annoying -- I need some nice templates. Run this code block
|
||||
with =C-c C-c=.
|
||||
|
||||
#+begin_src emacs-lisp :results output silent
|
||||
(require 'org-tempo)
|
||||
|
||||
(dolist (cell '(("el" . "src emacs-lisp")
|
||||
("cr" . "src emacs-lisp :noweb-ref requires")
|
||||
("cf" . "src emacs-lisp :noweb-ref functions")
|
||||
("cs" . "src emacs-lisp :noweb-ref settings")
|
||||
("cm" . "src emacs-lisp :noweb-ref modes")
|
||||
("cl" . "src emacs-lisp :noweb-ref linux-specific")
|
||||
("cw" . "src emacs-lisp :noweb-ref windows-specific")
|
||||
("cp" . "src emacs-lisp :noweb-ref packages")
|
||||
("ch" . "src emacs-lisp :noweb-ref hooks")
|
||||
("cb" . "src emacs-lisp :noweb-ref bindings")))
|
||||
(add-to-list 'org-structure-template-alist cell))
|
||||
#+end_src
|
||||
|
||||
** Local variables :noexport:
|
||||
|
||||
# Local variables:
|
||||
# org-adapt-indentation: nil
|
||||
# lisp-indent-function: 'common-lisp-indent-function
|
||||
# eval: (auto-fill-mode +1)
|
||||
# End:
|
||||
|
|
|
@ -1,7 +1,25 @@
|
|||
;; early-init.el -*- no-byte-compile: t; -*-
|
||||
;; This file is automatically tangled from config.org.
|
||||
;; Hand edits will be overwritten!
|
||||
;; BOOTSTRAP PACKAGE MANAGEMENT
|
||||
(let ((win-app-dir "~/Applications"))
|
||||
(dolist (path (list
|
||||
;; Windows
|
||||
(expand-file-name "Git/bin" win-app-dir)
|
||||
(expand-file-name "Git/usr/bin" win-app-dir)
|
||||
(expand-file-name "Git/mingw64/bin" win-app-dir)
|
||||
;; Linux
|
||||
(expand-file-name "bin"
|
||||
user-emacs-directory)
|
||||
(expand-file-name "~/bin")
|
||||
(expand-file-name "~/.local/bin")
|
||||
(expand-file-name "~/Scripts")
|
||||
))
|
||||
(when (file-exists-p path)
|
||||
(add-to-list 'exec-path path :append))))
|
||||
|
||||
;; Set $PATH
|
||||
(setenv "PATH" (mapconcat #'identity exec-path path-separator))
|
||||
(setq package-enable-at-startup nil)
|
||||
(defun acdw/bootstrap-straight ()
|
||||
"Bootstrap straight.el."
|
||||
|
@ -21,6 +39,7 @@
|
|||
(goto-char (point-max))
|
||||
(eval-print-last-sexp)))
|
||||
(load bootstrap-file nil 'nomessage)))
|
||||
(when (executable-find "git")
|
||||
(unless (ignore-errors (acdw/bootstrap-straight))
|
||||
(let ((msg "Straight.el didn't bootstrap correctly. Cloning directly"))
|
||||
(message "%s..." msg)
|
||||
|
@ -31,12 +50,8 @@
|
|||
(expand-file-name "straight/repos/straight.el"
|
||||
user-emacs-directory))
|
||||
(message "%s...Done." msg)
|
||||
(acdw/bootstrap-straight)))
|
||||
|
||||
(setq-default frame-inhibit-implied-resize t)
|
||||
|
||||
(setq-default frame-resize-pixelwise t)
|
||||
|
||||
(acdw/bootstrap-straight))))
|
||||
;; SETUP FRAME
|
||||
(add-to-list 'default-frame-alist
|
||||
'(tool-bar-lines . 0))
|
||||
|
||||
|
@ -51,3 +66,5 @@
|
|||
|
||||
(scroll-bar-mode -1)
|
||||
(horizontal-scroll-bar-mode -1)
|
||||
(setq-default frame-inhibit-implied-resize t
|
||||
frame-resize-pixelwise t)
|
||||
|
|
25
init.el
25
init.el
|
@ -4,6 +4,31 @@
|
|||
|
||||
(setq-default load-prefer-newer t)
|
||||
|
||||
(defmacro when-at (conditions &rest commands)
|
||||
"Run COMMANDS, or let the user know, when at a specific place.
|
||||
|
||||
CONDITIONS are one of `:work', `:home', or a list beginning with
|
||||
those and other conditions to check. COMMANDS are only run if
|
||||
all CONDITIONS are met.
|
||||
|
||||
If COMMANDS is empty or nil, simply return the result of CONDITIONS."
|
||||
(declare (indent 1))
|
||||
(let ((at-work '(memq system-type '(ms-dos windows-nt)))
|
||||
(at-home '(memq system-type '(gnu gnu/linux gnu/kfreebsd))))
|
||||
(pcase conditions
|
||||
(:work (if commands `(when ,at-work ,@commands) at-work))
|
||||
(:home (if commands `(when ,at-home ,@commands) at-home))
|
||||
((guard (eq (car conditions) :work))
|
||||
(if commands
|
||||
`(when (and ,at-work ,@(cdr conditions))
|
||||
,@commands)
|
||||
`(and ,at-work ,@(cdr conditions))))
|
||||
((guard (eq (car conditions) :home))
|
||||
(if commands
|
||||
`(when (and ,at-home ,@(cdr conditions))
|
||||
,@commands)
|
||||
`(and ,at-work ,@(cdr conditions)))))))
|
||||
|
||||
(let* (;; Speed up init
|
||||
(gc-cons-threshold most-positive-fixnum)
|
||||
(file-name-handler-alist nil)
|
||||
|
|
Loading…
Reference in New Issue