Convert to lower-case #+BEGIN_SRC blocks
While I was at it, I address some prose-specific comments like passive sentences and weasel words.
This commit is contained in:
parent
0e130dd024
commit
ffbd253e65
35 changed files with 1567 additions and 1616 deletions
|
@ -1,13 +1,12 @@
|
||||||
#+TITLE: My Emacs Configuration
|
#+TITLE: My Emacs Configuration
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2021-11-01 November
|
#+DATE: 2021-11-01 November
|
||||||
#+TAGS: emacs
|
|
||||||
|
|
||||||
My Emacs configuration, that I'm cheekily calling /hamacs/ is a literate programming model heavily inspired by my recent journey into [[https://www.youtube.com/watch?v=LKegZI9vWUU][Henrik Lissner's]] [[https://github.com/hlissner/doom-emacs][Doom Emacs]] and [[https://www.spacemacs.org/][Spacemacs]]. I used both extensively, but decided that I would /roll my own/ as Emacs people tend to be /control freaks/ (at least a little bit).
|
My Emacs configuration, that I'm cheekily calling /hamacs/ is a literate programming model heavily inspired by my recent journey into [[https://www.youtube.com/watch?v=LKegZI9vWUU][Henrik Lissner's]] [[https://github.com/hlissner/doom-emacs][Doom Emacs]] and [[https://www.spacemacs.org/][Spacemacs]]. I used both extensively, but decided that I would /roll my own/ as Emacs people tend to be /control freaks/ (at least a little bit).
|
||||||
|
|
||||||
The other advantage to rolling yer own is that you are more likely to /use/ what you add, leading to less bloat, and a more fun experience.
|
The other advantage to rolling yer own is that you may /use/ what you add, leading to less bloat, and a more fun experience.
|
||||||
|
|
||||||
Why yes, feel free to steal whatever you find interesting, as sharing is what makes our community great. Notice that functions and features that I have written begin with ~ha-~, however, everything else is either /stock Emacs/ or a /package/ that I download using [[https://github.com/raxod502/straight.el][straight]] (see [[file:bootstrap.org][bootstrap]] for how) and configured with [[https://github.com/jwiegley/use-package][use-package]] (see either [[https://ianyepan.github.io/posts/setting-up-use-package/][this introduction]] or [[https://www.emacswiki.org/emacs/UsePackage][this wiki page]] for details)... meaning that most blocks of code should /just work/ on its own.
|
Why yes, feel free to steal whatever you find interesting, as sharing is what makes our community great. Notice that functions and features that I have written begin with ~ha-~, but everything else is either /stock Emacs/ or a /package/ that I download using [[https://github.com/raxod502/straight.el][straight]] (see [[file:bootstrap.org][bootstrap]] for how) and configured with [[https://github.com/jwiegley/use-package][use-package]] (see either [[https://ianyepan.github.io/posts/setting-up-use-package/][this introduction]] or [[https://www.emacswiki.org/emacs/UsePackage][this wiki page]] for details)… meaning that most blocks of code should work on its own.
|
||||||
Hit me up with questions, =@howardabrams=. If you want to try this out, after installing Emacs, and cloning this repo, run:
|
Hit me up with questions, =@howardabrams=. If you want to try this out, after installing Emacs, and cloning this repo, run:
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
./initialize
|
./initialize
|
||||||
|
@ -17,7 +16,7 @@ This creates [[file:~/.emacs.d/init.el][~/.emacs.d/init.el]] that starts the pro
|
||||||
- [[file:bootstrap.org][bootstrap]] :: configures =straight= and loads basic libraries the rest of the code depends on. It then loads the following files in order:
|
- [[file:bootstrap.org][bootstrap]] :: configures =straight= and loads basic libraries the rest of the code depends on. It then loads the following files in order:
|
||||||
- [[file:ha-config.org][config]] :: contains /most/ of my configuration, setting up my sequence key menus, evil, etc.
|
- [[file:ha-config.org][config]] :: contains /most/ of my configuration, setting up my sequence key menus, evil, etc.
|
||||||
- [[file:ha-display.org][display]] :: sets up the visual aspects of an Emacs GUI, including themes, fonts and the dashboard.
|
- [[file:ha-display.org][display]] :: sets up the visual aspects of an Emacs GUI, including themes, fonts and the dashboard.
|
||||||
- [[file:ha-org.org][org]] :: configures the basics for org-mode formatted files. Specific features, however, come from their own files, however.
|
- [[file:ha-org.org][org]] :: configures the basics for org-mode formatted files. Specific features come from their own files.
|
||||||
- [[file:ha-org-word-processor.org][org-word-processor]] :: attempts to make Org files /visually/ look like a word processor, including turning off the colors for headers, and instead increasing their size.
|
- [[file:ha-org-word-processor.org][org-word-processor]] :: attempts to make Org files /visually/ look like a word processor, including turning off the colors for headers, and instead increasing their size.
|
||||||
- [[file:ha-org-clipboard.org][org-clipboard]] :: automatically converting HTML from a clipboard into Org-formatted content.
|
- [[file:ha-org-clipboard.org][org-clipboard]] :: automatically converting HTML from a clipboard into Org-formatted content.
|
||||||
- [[file:ha-org-journaling.org][org-journaling]] :: for writing journal entries and tasks.
|
- [[file:ha-org-journaling.org][org-journaling]] :: for writing journal entries and tasks.
|
||||||
|
@ -35,6 +34,5 @@ This creates [[file:~/.emacs.d/init.el][~/.emacs.d/init.el]] that starts the pro
|
||||||
- [[file:ha-programming-elisp.org][programming-elisp]] :: additions to Emacs Lisp programming.
|
- [[file:ha-programming-elisp.org][programming-elisp]] :: additions to Emacs Lisp programming.
|
||||||
- [[file:ha-programming-python.org][programming-python]] :: configuration for working with Python and LSP.
|
- [[file:ha-programming-python.org][programming-python]] :: configuration for working with Python and LSP.
|
||||||
- [[file:ha-programming-scheme.org][programming-scheme]] :: configuration for Racket.
|
- [[file:ha-programming-scheme.org][programming-scheme]] :: configuration for Racket.
|
||||||
- [[file:ha-aux-apps.org][aux-apps]] :: additional application configuration.
|
|
||||||
|
|
||||||
*Note:* Other functions and files come from essays written on [[http://www.howardism.org][my blog]]. To help with this, see [[file:support/final-initialize.el][support/final-initialize.el]] file.
|
*Note:* Other functions and files come from essays written on [[http://www.howardism.org][my blog]]. To help with this, see [[file:support/final-initialize.el][support/final-initialize.el]] file.
|
||||||
|
|
130
bootstrap.org
130
bootstrap.org
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: My Emacs Bootstrap
|
#+TITLE: My Emacs Bootstrap
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2021-10-08
|
#+DATE: 2021-10-08
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file for bootstraping my Emacs Configuration.
|
A literate programming file for bootstraping my Emacs Configuration.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; bootstrap.el --- file for bootstraping my Emacs Configuration
|
;;; bootstrap.el --- file for bootstraping my Emacs Configuration
|
||||||
;;
|
;;
|
||||||
;; © 2021-2022 Howard X. Abrams
|
;; © 2021-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,13 +22,13 @@ A literate programming file for bootstraping my Emacs Configuration.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
This file contains all the variable definitions and library loading for the other files in my project.
|
This file contains all the variable definitions and library loading for the other files in my project.
|
||||||
** Straight Package Installer
|
** Straight Package Installer
|
||||||
I'm going to be installing everything using the [[https://github.com/raxod502/straight.el#getting-started][straight.el]] for package installation and management. However, before I could tangle these org files, I needed to have =straight= grab the latest =org=, so the following initialization code is actually in [[file:initialize][initialize]], but the good stuff is:
|
I'm going to be installing everything using the [[https://github.com/raxod502/straight.el#getting-started][straight.el]] for package installation and management. Before I can /tangle/ these files, I need =straight= to grab the latest =org=, so the following initialization code is actually in [[file:initialize][initialize]], but if you are reading this online, configuring =straight= amounts to the following:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(defvar bootstrap-version)
|
(defvar bootstrap-version)
|
||||||
|
|
||||||
(let ((bootstrap-file
|
(let ((bootstrap-file
|
||||||
|
@ -43,24 +42,24 @@ I'm going to be installing everything using the [[https://github.com/raxod502/st
|
||||||
(goto-char (point-max))
|
(goto-char (point-max))
|
||||||
(eval-print-last-sexp)))
|
(eval-print-last-sexp)))
|
||||||
(load bootstrap-file nil 'nomessage))
|
(load bootstrap-file nil 'nomessage))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Let's get the Straight project working with =use-package=:
|
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
To get the Straight project working with =use-package=:
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
(straight-use-package 'use-package)
|
(straight-use-package 'use-package)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
While that enables the =:straight t= extension to =use-package=, let's just have that be the default:
|
While the above code enables the =:straight t= extension to =use-package=, let's have that as the default:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package straight
|
(use-package straight
|
||||||
:custom (straight-use-package-by-default t
|
:custom (straight-use-package-by-default t
|
||||||
straight-default-vc 'git))
|
straight-default-vc 'git))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
See the details in [[https://dev.to/jkreeftmeijer/emacs-package-management-with-straight-el-and-use-package-3oc8][this essay]].
|
See the details in [[https://dev.to/jkreeftmeijer/emacs-package-management-with-straight-el-and-use-package-3oc8][this essay]].
|
||||||
|
|
||||||
** OS Path and Native Compilation
|
** OS Path and Native Compilation
|
||||||
Helper functions to allow code for specific operating systems:
|
Helper functions to allow code for specific operating systems:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-running-on-macos? ()
|
(defun ha-running-on-macos? ()
|
||||||
"Return non-nil if running on Mac OS systems."
|
"Return non-nil if running on Mac OS systems."
|
||||||
(equal system-type 'darwin))
|
(equal system-type 'darwin))
|
||||||
|
@ -68,17 +67,16 @@ Helper functions to allow code for specific operating systems:
|
||||||
(defun ha-running-on-linux? ()
|
(defun ha-running-on-linux? ()
|
||||||
"Return non-nil if running on Linux systems."
|
"Return non-nil if running on Linux systems."
|
||||||
(equal system-type 'gnu/linux))
|
(equal system-type 'gnu/linux))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
With the way I start Emacs, I may not have the PATH I /actually/ use (from the shell) available, so we'll force it (code taken [[https://www.emacswiki.org/emacs/ExecPath][from here]]):
|
With the way I start Emacs, I may not have the =PATH= I /actually/ use (from the shell) available, so we'll force it (code taken [[https://www.emacswiki.org/emacs/ExecPath][from here]]):
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun set-exec-path-from-shell ()
|
(defun set-exec-path-from-shell ()
|
||||||
"Set up Emacs' `exec-path' and PATH environment variable to match
|
"Set up Emacs' `exec-path' and PATH environment variable to match
|
||||||
that used by the user's shell.
|
that used by the user's shell.
|
||||||
|
|
||||||
This is particularly useful under Mac OS X and macOS, where GUI
|
The MacOS, where GUI apps are not started from a shell, requires this."
|
||||||
apps are not started from a shell."
|
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((path-from-shell (shell-command-to-string "echo $PATH"))
|
(let* ((path-from-shell (shell-command-to-string "echo $PATH"))
|
||||||
(trimmed-path (replace-regexp-in-string (rx (zero-or-more space) eol)
|
(trimmed-path (replace-regexp-in-string (rx (zero-or-more space) eol)
|
||||||
|
@ -90,35 +88,35 @@ With the way I start Emacs, I may not have the PATH I /actually/ use (from the s
|
||||||
(message "PATH=%s" path-from-shell)
|
(message "PATH=%s" path-from-shell)
|
||||||
(setenv "PATH" env-path)
|
(setenv "PATH" env-path)
|
||||||
(setq exec-path (split-string trimmed-path separator))))
|
(setq exec-path (split-string trimmed-path separator))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Clear up a Mac-specific issue that sometimes arises since I'm switching to [[http://akrl.sdf.org/gccemacs.html][native compilation project]], as the =Emacs.app= that I use doesn't have its =bin= directory, e.g. =Emacs.app/Contents/MacOS/bin=:
|
Clear up a Mac-specific issue that sometimes arises since I'm switching to [[http://akrl.sdf.org/gccemacs.html][native compilation project]], as the =Emacs.app= that I use doesn't have its =bin= directory, e.g. =Emacs.app/Contents/MacOS/bin=:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (ha-running-on-macos?)
|
(when (ha-running-on-macos?)
|
||||||
(add-to-list 'exec-path "/usr/local/bin")
|
(add-to-list 'exec-path "/usr/local/bin")
|
||||||
(add-to-list 'exec-path (concat invocation-directory "bin") t))
|
(add-to-list 'exec-path (concat invocation-directory "bin") t))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Getting tired off all the packages that I load spewing a bunch of warnings that I can't do anything about:
|
Getting tired off all the packages that I load spewing a bunch of warnings that I can't do anything about:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (and (fboundp 'native-comp-available-p)
|
(when (and (fboundp 'native-comp-available-p)
|
||||||
(native-comp-available-p))
|
(native-comp-available-p))
|
||||||
(setq native-comp-async-report-warnings-errors nil
|
(setq native-comp-async-report-warnings-errors nil
|
||||||
native-comp-deferred-compilation t))
|
native-comp-deferred-compilation t))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** GNU Pretty Good Privacy
|
** GNU Pretty Good Privacy
|
||||||
On Linux, GPG is pretty straight-forward, but on the Mac, I often have troubles doing:
|
On Linux, GPG is pretty straight-forward, but on the Mac, I often have troubles doing:
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
brew install gpg
|
brew install gpg
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Next, on every reboot, start the agent:
|
Next, on every reboot, start the agent:
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
/usr/local/Cellar/gnupg/2.3.6/bin/gpg-agent --daemon
|
/usr/local/Cellar/gnupg/2.3.6/bin/gpg-agent --daemon
|
||||||
#+END_SRC
|
#+end_src
|
||||||
The only issue is that =brew link gpg= doesn’t always work, so maybe a helper function to find the executable:
|
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
Since =brew link gpg= doesn’t always work, this helper function may find the executable:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
(defun executable (path)
|
(defun executable (path)
|
||||||
"Return PATH if it is executable, see `file-executable-p'."
|
"Return PATH if it is executable, see `file-executable-p'."
|
||||||
(let ((epath (first (file-expand-wildcards path))))
|
(let ((epath (first (file-expand-wildcards path))))
|
||||||
|
@ -131,56 +129,56 @@ The only issue is that =brew link gpg= doesn’t always work, so maybe a helper
|
||||||
(executable "/usr/local/opt/gpg")
|
(executable "/usr/local/opt/gpg")
|
||||||
(executable "/usr/bin/pgp")))
|
(executable "/usr/bin/pgp")))
|
||||||
:config (epa-file-enable))
|
:config (epa-file-enable))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Basic Libraries
|
** Basic Libraries
|
||||||
The following packages come with Emacs, but seems like they still need loading:
|
The following packages come with Emacs, but seems like they still need loading:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package cl-lib
|
(use-package cl-lib
|
||||||
:straight (:type built-in)
|
:straight (:type built-in)
|
||||||
:init (defun first (elt) (car elt))
|
:init (defun first (elt) (car elt))
|
||||||
:commands (first))
|
:commands (first))
|
||||||
|
|
||||||
(require 'subr-x)
|
(require 'subr-x)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Ugh. Why am I getting a missing =first= function error? I define a simple implementation, that the CL library will overwrite ... at some point.
|
Ugh. Why am I getting a missing =first= function error? I define a simple implementation, that the CL library will overwrite ... at some point.
|
||||||
|
|
||||||
While most libraries will take care of their dependencies, I want to install /my dependent libraries/. Especially, [[https://github.com/magnars/.emacs.d/][Magnar Sveen]]'s Clojure-inspired [[https://github.com/magnars/dash.el][dash.el]] project:
|
While most libraries will take care of their dependencies, I want to install /my dependent libraries/, e.g, [[https://github.com/magnars/.emacs.d/][Magnar Sveen]]'s Clojure-inspired [[https://github.com/magnars/dash.el][dash.el]] project:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package dash)
|
(use-package dash)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Sure this package is essentially syntactic sugar, and to help /share/ my configuration, I attempt to use =thread-last= instead of =->>=, but, I still like it.
|
Sure this package is essentially syntactic sugar, and to help /share/ my configuration, I attempt to use =thread-last= instead of =->>=, but, I still like it.
|
||||||
|
|
||||||
The [[https://github.com/magnars/s.el][s.el]] project is a simpler string manipulation library that I (and other projects) use:
|
The [[https://github.com/magnars/s.el][s.el]] project is a simpler string manipulation library that I (and other projects) use:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package s)
|
(use-package s)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Manipulate file paths with the [[https://github.com/rejeep/f.el][f.el]] project:
|
Manipulate file paths with the [[https://github.com/rejeep/f.el][f.el]] project:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package f)
|
(use-package f)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** My Code Location
|
** My Code Location
|
||||||
Much of my more complicated code comes from my website essays and other projects. The destination, however, shows up here:
|
Much of my more complicated code comes from my website essays and other projects. The destination shows up here:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-to-list 'load-path (f-expand "~/.emacs.d/elisp"))
|
(add-to-list 'load-path (f-expand "~/.emacs.d/elisp"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Hopefully, this will tie me over while I transition.
|
Hopefully, this will tie me over while I transition.
|
||||||
** Emacs Server Control
|
** Emacs Server Control
|
||||||
Sure the Emacs application will almost always have the =server-start= going, however, I need to control it just a bit (because I often have two instances running on some of my machines). What /defines/ the Emacs instance for work changes ... often:
|
Sure the Emacs application will almost always have the =server-start= going, but I need to control it (because I often have two instances running on some of my machines). What /defines/ the Emacs instance for work changes ... often:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-emacs-for-work? ()
|
(defun ha-emacs-for-work? ()
|
||||||
"Return non-nil when the Emacs application's location matches as one for work.
|
"Return non-nil when the Emacs application's location matches as one for work.
|
||||||
Currently, this is the `emacs-plus@28' app that I have built with
|
This is the `emacs-plus@28' app that I have built with
|
||||||
the native-comp model, but I reserve the right to change this."
|
the native-comp model, but I reserve the right to change this."
|
||||||
(and (f-dir? "~/work")
|
(and (f-dir? "~/work")
|
||||||
;; (string-match "emacs-plus@28" exec-directory)
|
;; (string-match "emacs-plus@28" exec-directory)
|
||||||
(not (string-match "Emacs.app" exec-directory))))
|
(not (string-match "Emacs.app" exec-directory))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And now start the server with an appropriate tag name:
|
And now start the server with an appropriate tag name:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(if (not (ha-emacs-for-work?))
|
(if (not (ha-emacs-for-work?))
|
||||||
(setq server-name "personal")
|
(setq server-name "personal")
|
||||||
(setq server-name "work")
|
(setq server-name "work")
|
||||||
|
@ -188,11 +186,12 @@ And now start the server with an appropriate tag name:
|
||||||
(set-exec-path-from-shell)))
|
(set-exec-path-from-shell)))
|
||||||
|
|
||||||
(server-start)
|
(server-start)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Load the Rest
|
* Load the Rest
|
||||||
The following loads the rest of my org-mode literate files. I add them as they are /ready/, but eventually, I'll trim this up into a nicer pattern.
|
The following loads the rest of my org-mode literate files. I add new filesas they are /ready/:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defvar ha-hamacs-files (flatten-list `("ha-private.org"
|
(defvar ha-hamacs-files (flatten-list
|
||||||
|
`("ha-private.org"
|
||||||
"ha-config.org"
|
"ha-config.org"
|
||||||
,(when (display-graphic-p)
|
,(when (display-graphic-p)
|
||||||
"ha-display.org")
|
"ha-display.org")
|
||||||
|
@ -217,49 +216,48 @@ The following loads the rest of my org-mode literate files. I add them as they a
|
||||||
"ha-aux-apps.org"
|
"ha-aux-apps.org"
|
||||||
"ha-feed-reader.org"))))
|
"ha-feed-reader.org"))))
|
||||||
"List of org files that complete the hamacs project.")
|
"List of org files that complete the hamacs project.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
We can test/debug/reload any individual file, via:
|
We can test/debug/reload any individual file, via:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-hamacs-load (file)
|
(defun ha-hamacs-load (file)
|
||||||
"Load or reload an org-mode FILE containing literate Emacs configuration code."
|
"Load or reload an org-mode FILE containing literate Emacs configuration code."
|
||||||
(interactive (list (completing-read "Org file: " ha-hamacs-files)))
|
(interactive (list (completing-read "Org file: " ha-hamacs-files)))
|
||||||
(let ((full-file (f-join hamacs-source-dir file)))
|
(let ((full-file (f-join hamacs-source-dir file)))
|
||||||
(when (f-exists? full-file)
|
(when (f-exists? full-file)
|
||||||
(org-babel-load-file full-file))))
|
(org-babel-load-file full-file))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And we can now load everything:
|
And we can now load everything:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-hamacs-reload-all ()
|
(defun ha-hamacs-reload-all ()
|
||||||
"Reload our entire ecosystem of configuration files."
|
"Reload our entire ecosystem of configuration files."
|
||||||
(interactive)
|
(interactive)
|
||||||
(dolist (file ha-hamacs-files)
|
(dolist (file ha-hamacs-files)
|
||||||
(unless (equal file "bootstrap.org")
|
(unless (equal file "bootstrap.org")
|
||||||
(ha-hamacs-load file))))
|
(ha-hamacs-load file))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And do it:
|
And do it:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-hamacs-reload-all)
|
(ha-hamacs-reload-all)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Once we have loaded /my world/, let’s add every other Org file in the project to the list, so that I can easily bring more stuff.
|
Once we have loaded /my world/, let’s add every other Org file in the project to the list, so that I can load newly created files that I don’t want to commit:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq ha-hamacs-files
|
(setq ha-hamacs-files
|
||||||
(->> (rx ".org" string-end)
|
(->> (rx ".org" string-end)
|
||||||
(directory-files "~/other/hamacs" nil)
|
(directory-files "~/other/hamacs" nil)
|
||||||
(append ha-hamacs-files)
|
(append ha-hamacs-files)
|
||||||
(--filter (not (string-match (rx "README") it)))
|
(--filter (not (string-match (rx "README") it)))
|
||||||
(-uniq)))
|
(-uniq)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's provide a name so that the file can be required:
|
Let's provide a name so we can =require= this file:
|
||||||
|
#+begin_src emacs-lisp :exports none
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
|
||||||
(provide 'bootstrap)
|
(provide 'bootstrap)
|
||||||
;;; bootstrap.el ends here
|
;;; bootstrap.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Org Agenda Configuration
|
#+TITLE: Org Agenda Configuration
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-09-18
|
#+DATE: 2020-09-18
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming configuration for fancy agenda and todo lists.
|
A literate programming configuration for fancy agenda and todo lists.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-agendas --- Configuration for fancy agenda and todo lists. -*- lexical-binding: t; -*-
|
;;; ha-agendas --- Configuration for fancy agenda and todo lists. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,20 +22,20 @@ A literate programming configuration for fancy agenda and todo lists.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
All the code we describe in this file needs loading /after/ org.
|
All the code we describe in this file needs loading /after/ org.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(with-eval-after-load "org"
|
(with-eval-after-load "org"
|
||||||
(add-to-list 'org-modules 'org-protocol))
|
(add-to-list 'org-modules 'org-protocol))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Grouping
|
* Grouping
|
||||||
Typical agendas have an /order/ to them, but the [[https://github.com/alphapapa/org-super-agenda][org-super-agenda project]] allows you to get specific as well as group them under headings.
|
Typical agendas have an /order/ to them, but the [[https://github.com/alphapapa/org-super-agenda][org-super-agenda project]] allows you to get specific as well as group them under headings.
|
||||||
|
|
||||||
Unless you specify otherwise, this is the grouping we'll use:
|
Unless you specify otherwise, this is the grouping we'll use:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-super-agenda
|
(use-package org-super-agenda
|
||||||
:after org
|
:after org
|
||||||
:init
|
:init
|
||||||
|
@ -62,12 +61,12 @@ Unless you specify otherwise, this is the grouping we'll use:
|
||||||
:todo "TODO"
|
:todo "TODO"
|
||||||
:scheduled future
|
:scheduled future
|
||||||
:order 3))))
|
:order 3))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The task matches a group based on the /code order/, but the =:order= tag allows me to display them in a different order.
|
The task matches a group based on the /code order/, but the =:order= tag allows me to display them in a different order.
|
||||||
|
|
||||||
The following super agenda is just for /today/ and should be smaller:
|
The following super agenda is just for /today/ and should be smaller:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(setq ha-org-super-agenda-today
|
(setq ha-org-super-agenda-today
|
||||||
'((:name "Finished"
|
'((:name "Finished"
|
||||||
:todo ("DONE" "CANCELED")
|
:todo ("DONE" "CANCELED")
|
||||||
|
@ -80,13 +79,13 @@ The following super agenda is just for /today/ and should be smaller:
|
||||||
:scheduled past
|
:scheduled past
|
||||||
:date today
|
:date today
|
||||||
:order 0)))
|
:order 0)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Query Views
|
* Query Views
|
||||||
The [[https://github.com/alphapapa/org-ql][org-ql project]] gives us a /query language/ of sorts (based on s-expressions).
|
The [[https://github.com/alphapapa/org-ql][org-ql project]] gives us a /query language/ of sorts (based on s-expressions).
|
||||||
|
|
||||||
By putting all queries under =org-ql-views=, we can then call ~M-x query~ and select the view to display:
|
By putting all queries under =org-ql-views=, we can then call ~M-x query~ and select the view to display:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-ql
|
(use-package org-ql
|
||||||
:after org
|
:after org
|
||||||
:config
|
:config
|
||||||
|
@ -137,27 +136,27 @@ By putting all queries under =org-ql-views=, we can then call ~M-x query~ and se
|
||||||
:title "Today"
|
:title "Today"
|
||||||
:super-groups 'ha-org-super-agenda-today
|
:super-groups 'ha-org-super-agenda-today
|
||||||
:sort '(priority))))))
|
:sort '(priority))))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Agenda Interface
|
* Agenda Interface
|
||||||
We can create a function to start this:
|
We can create a function to start this:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-todays-agenda ()
|
(defun ha-todays-agenda ()
|
||||||
"Display an agenda for today, including tasks and scheduled entries."
|
"Display an agenda for today, including tasks and scheduled entries."
|
||||||
(interactive)
|
(interactive)
|
||||||
(org-ql-view "Overview: Today"))
|
(org-ql-view "Overview: Today"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And of course, a keybinding:
|
And of course, a keybinding:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "a a" '("my agenda" . ha-todays-agenda))
|
(ha-leader "a a" '("my agenda" . ha-todays-agenda))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's provide a name so that the file can be required:
|
Let's provide a name so that the file can be required:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-agendas)
|
(provide 'ha-agendas)
|
||||||
;;; ha-agendas.el ends here
|
;;; ha-agendas.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Auxillary and Optional Applications
|
#+TITLE: Auxillary and Optional Applications
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2021-11-18
|
#+DATE: 2021-11-18
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file for helper apps in Emacs.
|
A literate programming file for helper apps in Emacs.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-aux-apps --- Configuring helper apps in Emacs. -*- lexical-binding: t; -*-
|
;;; ha-aux-apps --- Configuring helper apps in Emacs. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2021-2022 Howard X. Abrams
|
;; © 2021-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,13 +22,13 @@ A literate programming file for helper apps in Emacs.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
The following applications are not really needed. I alternate between trying to /stay in Emacs/ taking advantage of the consistent interface, and simply using a stand-alone app on my Workday computer.
|
The following applications are not needed. I alternate between trying to /stay in Emacs/ taking advantage of the consistent interface, and using a stand-alone app on my Workday computer.
|
||||||
* Twitter
|
* Twitter
|
||||||
The venerable [[https://github.com/hayamiz/twittering-mode/tree/master][twittering-mode]] allows me to follow all the twits.
|
The venerable [[https://github.com/hayamiz/twittering-mode/tree/master][twittering-mode]] allows me to follow all the twits.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package twittering-mode
|
(use-package twittering-mode
|
||||||
:init
|
:init
|
||||||
(setq twittering-use-master-password t
|
(setq twittering-use-master-password t
|
||||||
|
@ -37,11 +36,11 @@ The venerable [[https://github.com/hayamiz/twittering-mode/tree/master][twitteri
|
||||||
:config
|
:config
|
||||||
(defalias 'epa--decode-coding-string 'decode-coding-string)
|
(defalias 'epa--decode-coding-string 'decode-coding-string)
|
||||||
(ha-leader "a t" '("twitter" . twit)))
|
(ha-leader "a t" '("twitter" . twit)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Telega
|
* Telega
|
||||||
I'm thinking the [[https://zevlg.github.io/telega.el/][Telega package]] would be better than Bitlbee for Telegram communication. Seems to have a bug on the Melpa version, so I'm keeping this to the =HEAD=, but only if I've cloned it.
|
I'm thinking the [[https://zevlg.github.io/telega.el/][Telega package]] would be better than Bitlbee for Telegram communication. Seems to have a bug on the Melpa version, so I'm keeping this to the =HEAD=, if I've cloned it.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (file-exists-p "~/other/telega.el")
|
(when (file-exists-p "~/other/telega.el")
|
||||||
(use-package telega
|
(use-package telega
|
||||||
:straight (:local-repo "~/other/telega.el")
|
:straight (:local-repo "~/other/telega.el")
|
||||||
|
@ -50,22 +49,22 @@ I'm thinking the [[https://zevlg.github.io/telega.el/][Telega package]] would be
|
||||||
(setq telega-use-images nil)
|
(setq telega-use-images nil)
|
||||||
:config
|
:config
|
||||||
(ha-leader "a T" 'telega)))
|
(ha-leader "a T" 'telega)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
For some reason, you need [[https://github.com/Fanael/rainbow-identifiers][rainbow-identifiers]] to work, oh, I guess the docs state this.
|
For some reason, you need [[https://github.com/Fanael/rainbow-identifiers][rainbow-identifiers]] to work, oh, I guess the docs state this.
|
||||||
* RPG DM
|
* RPG DM
|
||||||
Been working on a project for getting Emacs helping as a /Dungeon Master's Assistant/, and I must say, it is coming along nicely. In case you are reading this, let me know, and I'll start to share it.
|
Been working on a project for getting Emacs helping as a /Dungeon Master's Assistant/, and I must say, it is coming along nicely. In case you are reading this, let me know, and I'll start to share it.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (f-directory? "~/other/rpgdm")
|
(when (f-directory? "~/other/rpgdm")
|
||||||
(use-package rpgdm
|
(use-package rpgdm
|
||||||
:straight (:local-repo "~/other/rpgdm")
|
:straight (:local-repo "~/other/rpgdm")
|
||||||
:commands (rpgdm-mode rpgdm-tables-load)
|
:commands (rpgdm-mode rpgdm-tables-load)
|
||||||
:init (setq rpgdm-base (expand-file-name "~/other/rpgdm"))
|
:init (setq rpgdm-base (expand-file-name "~/other/rpgdm"))
|
||||||
:config (ha-leader "t D" '("rpg dm" . rpgdm-mode))))
|
:config (ha-leader "t D" '("rpg dm" . rpgdm-mode))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And my new Ironsworn project:
|
And my new Ironsworn project:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (f-directory? "~/other/emacs-ironsworn")
|
(when (f-directory? "~/other/emacs-ironsworn")
|
||||||
(use-package rpgdm-ironsworn
|
(use-package rpgdm-ironsworn
|
||||||
:after rpgdm
|
:after rpgdm
|
||||||
|
@ -76,14 +75,14 @@ And my new Ironsworn project:
|
||||||
org-link-elisp-skip-confirm-regexp (rx string-start (optional "(") "rpgdm-"
|
org-link-elisp-skip-confirm-regexp (rx string-start (optional "(") "rpgdm-"
|
||||||
(or "tables-" "ironsworn-")
|
(or "tables-" "ironsworn-")
|
||||||
(one-or-more any)))))
|
(one-or-more any)))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's =provide= a name so we can =require= this file:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-aux-apps)
|
(provide 'ha-aux-apps)
|
||||||
;;; ha-aux-apps.el ends here
|
;;; ha-aux-apps.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: A literate programming file for helper apps in Emacs.
|
#+DESCRIPTION: A literate programming file for helper apps in Emacs.
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Capturing Notes with Org
|
#+TITLE: Capturing Notes with Org
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-09-18
|
#+DATE: 2020-09-18
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file for configuring org for capturing notes.
|
A literate programming file for configuring org for capturing notes.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; capturing-notes --- Configuring org for capturing notes. -*- lexical-binding: t; -*-
|
;;; capturing-notes --- Configuring org for capturing notes. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,37 +22,35 @@ A literate programming file for configuring org for capturing notes.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
Capturing (or collecting) notes from files, browsers, and meetings, is a great way to get organized.
|
Capturing (or collecting) notes from files, browsers, and meetings, is a great way to get organized.
|
||||||
|
|
||||||
I even have external commands that kick-off the capturing process, and without a command this is what gets called:
|
I even have external commands that kick-off the capturing process, and without a command this is what gets called:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(setq org-capture-default-template "c")
|
(setq org-capture-default-template "c")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let's now define my templates.
|
Let's now define my templates.
|
||||||
* Templates
|
* Templates
|
||||||
Just make sure we can execute this code anytime, let's just define the variable that will hold all the templates:
|
To make sure we can execute this code anytime, let's define the variable that will hold all the templates:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defvar org-capture-templates (list))
|
(defvar org-capture-templates (list))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Some templates put the information /in front/ of other information (as opposed to the default of appending), so I define a helper function:
|
Some templates put the information /in front/ of other information (as opposed to the default of appending), so I define a helper function:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-first-header ()
|
(defun ha-first-header ()
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(search-forward-regexp "^\* ")
|
(search-forward-regexp "^\* ")
|
||||||
(beginning-of-line 1)
|
(beginning-of-line 1)
|
||||||
(point))
|
(point))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** General Notes
|
** General Notes
|
||||||
Capturing text into the =org-default-notes-file= is something I don't do much:
|
Capturing text into the =org-default-notes-file= is something I don't do much:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-to-list 'org-capture-templates
|
(add-to-list 'org-capture-templates
|
||||||
'("n" "Thought or Note" entry
|
'("n" "Thought or Note" entry
|
||||||
(file org-default-notes-file)
|
(file org-default-notes-file)
|
||||||
|
@ -63,72 +60,69 @@ Capturing text into the =org-default-notes-file= is something I don't do much:
|
||||||
(file+function "~/website/index.org" ha-first-header)
|
(file+function "~/website/index.org" ha-first-header)
|
||||||
(file "~/.spacemacs.d/templates/website-announcement.org")
|
(file "~/.spacemacs.d/templates/website-announcement.org")
|
||||||
:empty-lines 1))
|
:empty-lines 1))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Before we go too far, we should create a publishing file for the website announcement, and something for the journal.
|
Before we go too far, we should create a publishing file for the website announcement, and something for the journal.
|
||||||
** Clock in Tasks
|
** Clock in Tasks
|
||||||
Org has one task at a time that can be /clocked in/ keeping a timer. I use that as a /destination/ for collecting notes. For instance, capturing with a =c= allows me to just enter stuff in under that task without switching to it:
|
Org has one task at a time that can be /clocked in/ keeping a timer. I use that as a /destination/ for collecting notes. For instance, capturing with a =c= allows me to just enter details under that task without switching to it:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-to-list 'org-capture-templates
|
(add-to-list 'org-capture-templates
|
||||||
'("c" "Currently clocked in task"))
|
'("c" "Currently clocked in task"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let's put a bullet item under that task:
|
Let's put a bullet item under that task:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-to-list 'org-capture-templates
|
(add-to-list 'org-capture-templates
|
||||||
`("cc" "Item to Current Clocked Task" item
|
`("cc" "Item to Current Clocked Task" item
|
||||||
(clock)
|
(clock)
|
||||||
"%i%?" :empty-lines 1))
|
"%i%?" :empty-lines 1))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
We can select a /region/ and copy that using =c r=:
|
We can select a /region/ and copy that using =c r=:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-to-list 'org-capture-templates
|
(add-to-list 'org-capture-templates
|
||||||
`("cr" "Contents to Current Clocked Task" plain
|
`("cr" "Contents to Current Clocked Task" plain
|
||||||
(clock)
|
(clock)
|
||||||
"%i" :immediate-finish t :empty-lines 1))
|
"%i" :immediate-finish t :empty-lines 1))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
If we have copied anything into the clipboard, that information can be add to the current task using =c k=:
|
If we have copied anything into the clipboard, that information can be add to the current task using =c k=:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(add-to-list 'org-capture-templates
|
(add-to-list 'org-capture-templates
|
||||||
`("ck" "Kill-ring to Current Clocked Task" plain
|
`("ck" "Kill-ring to Current Clocked Task" plain
|
||||||
(clock)
|
(clock)
|
||||||
"%c" :immediate-finish t :empty-lines 1))
|
"%c" :immediate-finish t :empty-lines 1))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Instead, if I am looking at some code, I can copy some code from a region, but use a helper function to create a /link/ to the original source code using =c f=:
|
Instead, if I am looking at some code, I can copy some code from a region, but use a helper function to create a /link/ to the original source code using =c f=:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(add-to-list 'org-capture-templates
|
(add-to-list 'org-capture-templates
|
||||||
`("cf" "Code Reference with Comments to Current Task"
|
`("cf" "Code Reference with Comments to Current Task"
|
||||||
plain (clock)
|
plain (clock)
|
||||||
"%(ha-org-capture-code-snippet \"%F\")\n\n %?"
|
"%(ha-org-capture-code-snippet \"%F\")\n\n %?"
|
||||||
:empty-lines 1))
|
:empty-lines 1))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
If I want a reference to the code, without any comments, I call ~c l~:
|
If I want a reference to the code, without any comments, I call ~c l~:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-to-list 'org-capture-templates
|
(add-to-list 'org-capture-templates
|
||||||
`("cl" "Link to Code Reference to Current Task"
|
`("cl" "Link to Code Reference to Current Task"
|
||||||
plain (clock)
|
plain (clock)
|
||||||
"%(ha-org-capture-code-snippet \"%F\")"
|
"%(ha-org-capture-code-snippet \"%F\")"
|
||||||
:empty-lines 1 :immediate-finish t))
|
:empty-lines 1 :immediate-finish t))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Capture Helper Functions
|
** Capture Helper Functions
|
||||||
|
|
||||||
In order to have a capture back-ref to a function and its code, we need to use this:
|
To have a capture back-ref to a function and its code, we need to use this:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(require 'which-func)
|
(require 'which-func)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
This helper function given a code /type/ and the /function/, analyzes the current buffer in order to collects data about the source code file. It then creates a nice-looking template:
|
This helper function given a code /type/ and the /function/, analyzes the current buffer in order to collects data about the source code file. It then creates a nice-looking template:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-capture-fileref-snippet (f type headers func-name)
|
(defun ha-org-capture-fileref-snippet (f type headers func-name)
|
||||||
(let* ((code-snippet
|
(let* ((code-snippet
|
||||||
(buffer-substring-no-properties (mark) (- (point) 1)))
|
(buffer-substring-no-properties (mark) (- (point) 1)))
|
||||||
|
@ -144,14 +138,14 @@ This helper function given a code /type/ and the /function/, analyzes the curren
|
||||||
(format "
|
(format "
|
||||||
%s
|
%s
|
||||||
|
|
||||||
#+BEGIN_%s %s
|
,#+BEGIN_%s %s
|
||||||
%s
|
%s
|
||||||
#+END_%s" initial-txt type headers code-snippet type)))
|
,#+END_%s" initial-txt type headers code-snippet type)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
For typical code references, we can get the label for Org's =SRC= block by taking the =major-mode= and removing the =-mode= part. We can then call the formatter we previously defined:
|
For typical code references, we can get the label for Org's =SRC= block by taking the =major-mode= and removing the =-mode= part. We can then call the formatter previously defined:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-capture-code-snippet (f)
|
(defun ha-org-capture-code-snippet (f)
|
||||||
"Given a file, F, this captures the currently selected text
|
"Given a file, F, this captures the currently selected text
|
||||||
within an Org SRC block with a language based on the current mode
|
within an Org SRC block with a language based on the current mode
|
||||||
|
@ -160,23 +154,23 @@ and a backlink to the function and the file."
|
||||||
(let ((org-src-mode (replace-regexp-in-string "-mode" "" (format "%s" major-mode)))
|
(let ((org-src-mode (replace-regexp-in-string "-mode" "" (format "%s" major-mode)))
|
||||||
(func-name (which-function)))
|
(func-name (which-function)))
|
||||||
(ha-org-capture-fileref-snippet f "SRC" org-src-mode func-name))))
|
(ha-org-capture-fileref-snippet f "SRC" org-src-mode func-name))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let's assume that we want to copy some text from a file, but it isn't source code, then this function makes an =EXAMPLE= of it.
|
Let's assume that we want to copy some text from a file, but it isn't source code, then this function makes an =EXAMPLE= of it.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-capture-clip-snippet (f)
|
(defun ha-org-capture-clip-snippet (f)
|
||||||
"Given a file, F, this captures the currently selected text
|
"Given a file, F, this captures the currently selected text
|
||||||
within an Org EXAMPLE block and a backlink to the file."
|
within an Org EXAMPLE block and a backlink to the file."
|
||||||
(with-current-buffer (find-buffer-visiting f)
|
(with-current-buffer (find-buffer-visiting f)
|
||||||
(ha-org-capture-fileref-snippet f "EXAMPLE" "" nil)))
|
(ha-org-capture-fileref-snippet f "EXAMPLE" "" nil)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Code Capturing Functions
|
** Code Capturing Functions
|
||||||
|
|
||||||
In order to easily call a capture for code, let's make two interactive functions, one just copies the stuff, and the other pulls up a capturing window for comments:
|
To easily call a capture for code, let's make two interactive functions, one just copies the stuff, and the other pulls up a capturing window for comments:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-code-to-clock (&optional start end)
|
(defun ha-code-to-clock (&optional start end)
|
||||||
"Send the currently selected code to the currently clocked-in org-mode task."
|
"Send the currently selected code to the currently clocked-in org-mode task."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -187,24 +181,24 @@ In order to easily call a capture for code, let's make two interactive functions
|
||||||
currently clocked-in org-mode task."
|
currently clocked-in org-mode task."
|
||||||
(interactive)
|
(interactive)
|
||||||
(org-capture nil "f"))
|
(org-capture nil "f"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* External Capturing
|
* External Capturing
|
||||||
If we put something on the clipboard using =xclip= or something, and then
|
If we put something on the clipboard using =xclip= or something, and then
|
||||||
perhaps =emacsclient= could call this function to put those contents into clocked in task.
|
perhaps =emacsclient= could call this function to put those contents into clocked in task.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-external-capture-to-org ()
|
(defun ha-external-capture-to-org ()
|
||||||
"Calls `org-capture-string' on the contents of the Apple clipboard."
|
"Calls `org-capture-string' on the contents of the Apple clipboard."
|
||||||
(interactive)
|
(interactive)
|
||||||
(org-capture-string (ha-org-clipboard) "ck")
|
(org-capture-string (ha-org-clipboard) "ck")
|
||||||
(ignore-errors
|
(ignore-errors
|
||||||
(delete-frame)))
|
(delete-frame)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The =en= script is used as the last pipe entry on the command line, this displays the output, and then copies the contents into the Emacs-based engineering notebook at the currently clocked in task.
|
The =en= script is used as the last pipe entry on the command line, this displays the output, and then copies the contents into the Emacs-based engineering notebook at the currently clocked in task.
|
||||||
|
|
||||||
#+BEGIN_SRC shell :shebang "#!/bin/bash" :tangle ~/bin/en
|
#+begin_src shell :shebang "#!/bin/bash" :tangle ~/bin/en
|
||||||
# Interface to my Engineering Notebook.
|
# Interface to my Engineering Notebook.
|
||||||
#
|
#
|
||||||
# Used as the last pipe entry on the command line, this displays the output,
|
# Used as the last pipe entry on the command line, this displays the output,
|
||||||
|
@ -292,10 +286,10 @@ The =en= script is used as the last pipe entry on the command line, this display
|
||||||
emacsclient -s work -e '(org-capture-string "" "ck")'
|
emacsclient -s work -e '(org-capture-string "" "ck")'
|
||||||
|
|
||||||
rm -f $FILE
|
rm -f $FILE
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Keybindings
|
* Keybindings
|
||||||
Along with kicking off the org-capture, I want to be able to clock-in and out:
|
Along with kicking off the org-capture, I want to be able to clock-in and out:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(with-eval-after-load 'ha-org
|
(with-eval-after-load 'ha-org
|
||||||
(ha-org-leader
|
(ha-org-leader
|
||||||
"X" '("org capture" . org-capture)
|
"X" '("org capture" . org-capture)
|
||||||
|
@ -313,15 +307,15 @@ Along with kicking off the org-capture, I want to be able to clock-in and out:
|
||||||
"c t" '("eval range" . org-evaluate-time-range)
|
"c t" '("eval range" . org-evaluate-time-range)
|
||||||
"c =" '("timestamp up" . org-clock-timestamps-up)
|
"c =" '("timestamp up" . org-clock-timestamps-up)
|
||||||
"c -" '("timestamp down" . org-clock-timestamps-down)))
|
"c -" '("timestamp down" . org-clock-timestamps-down)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
|
|
||||||
Let's provide a name so we can =require= this file.
|
Let's provide a name so we can =require= this file.
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-capturing-notes)
|
(provide 'ha-capturing-notes)
|
||||||
;;; ha-capturing-notes.el ends here
|
;;; ha-capturing-notes.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
580
ha-config.org
580
ha-config.org
File diff suppressed because it is too large
Load diff
122
ha-display.org
122
ha-display.org
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Emacs Graphical Display Configuration
|
#+TITLE: Emacs Graphical Display Configuration
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-09-10
|
#+DATE: 2020-09-10
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file to configure the Emacs UI.
|
A literate programming file to configure the Emacs UI.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-display --- Emacs UI configuration. -*- lexical-binding: t; -*-
|
;;; ha-display --- Emacs UI configuration. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,20 +22,20 @@ A literate programming file to configure the Emacs UI.
|
||||||
;; Using `find-file-at-point', and tangle the file to recreate this one .
|
;; Using `find-file-at-point', and tangle the file to recreate this one .
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Dashboard
|
* Dashboard
|
||||||
The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] project makes a nicer startup screen. It requires [[https://github.com/purcell/page-break-lines][page-break-lines]] (which is a nice project):
|
The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] project makes a nicer startup screen. It requires [[https://github.com/purcell/page-break-lines][page-break-lines]] (which is a nice project):
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package page-break-lines)
|
(use-package page-break-lines)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And let’s make this Emacs look more like a fancy IDE with [[https://github.com/domtronn/all-the-icons.el][all-the-icons]]:
|
And let’s make this Emacs look more like a fancy IDE with [[https://github.com/domtronn/all-the-icons.el][all-the-icons]]:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package all-the-icons
|
(use-package all-the-icons
|
||||||
:if (display-graphic-p))
|
:if (display-graphic-p))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package dashboard
|
(use-package dashboard
|
||||||
:init
|
:init
|
||||||
(defun ha-dashboard-version ()
|
(defun ha-dashboard-version ()
|
||||||
|
@ -61,10 +60,10 @@ And let’s make this Emacs look more like a fancy IDE with [[https://github.com
|
||||||
(dashboard-setup-startup-hook)
|
(dashboard-setup-startup-hook)
|
||||||
|
|
||||||
(setq dashboard-footer-messages (list (ha--dad-joke))))
|
(setq dashboard-footer-messages (list (ha--dad-joke))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
I would appreciate seeing if my Emacs installation has the features that I expect:
|
I would appreciate seeing if my Emacs installation has the features that I expect:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-hamacs-features (&optional iconic)
|
(defun ha-hamacs-features (&optional iconic)
|
||||||
"Simple display of features I'm most keen about.
|
"Simple display of features I'm most keen about.
|
||||||
If ICONIC is non-nil, return a string of icons."
|
If ICONIC is non-nil, return a string of icons."
|
||||||
|
@ -86,10 +85,10 @@ I would appreciate seeing if my Emacs installation has the features that I expec
|
||||||
(if (called-interactively-p)
|
(if (called-interactively-p)
|
||||||
(message "Enabled features: %s" results)
|
(message "Enabled features: %s" results)
|
||||||
results)))
|
results)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Mode Line
|
* Mode Line
|
||||||
Let's install and load some of packages from the [[https://github.com/hlissner/doom-emacs][Doom Emacs]] project, like [[https://github.com/seagle0128/doom-modeline][doom-modeline]] and maybe the themes:
|
Let's install and load some of packages from the [[https://github.com/hlissner/doom-emacs][Doom Emacs]] project, like [[https://github.com/seagle0128/doom-modeline][doom-modeline]] and maybe the themes:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package doom-modeline
|
(use-package doom-modeline
|
||||||
:init
|
:init
|
||||||
(setq doom-modeline-minor-modes nil
|
(setq doom-modeline-minor-modes nil
|
||||||
|
@ -99,11 +98,11 @@ Let's install and load some of packages from the [[https://github.com/hlissner/d
|
||||||
(doom-modeline-mode +1))
|
(doom-modeline-mode +1))
|
||||||
|
|
||||||
(use-package doom-themes)
|
(use-package doom-themes)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Find the Bloody Cursor
|
* Find the Bloody Cursor
|
||||||
Large screen, lots of windows, so where is the cursor? While I used to use =hl-line+=, I found that the prolific [[https://protesilaos.com/][Protesilaos Stavrou]] [[https://protesilaos.com/codelog/2022-03-14-emacs-pulsar-demo/][introduced his Pulsar project]] is just what I need. Specifically, I might /loose the cursor/ and need to have it highlighted (using ~F6~), but also, this automatically highlights the cursor line with specific /actions/ , like changing windows.
|
Large screen, lots of windows, so where is the cursor? While I used to use =hl-line+=, I found that the prolific [[https://protesilaos.com/][Protesilaos Stavrou]] [[https://protesilaos.com/codelog/2022-03-14-emacs-pulsar-demo/][introduced his Pulsar project]] is just what I need. Specifically, I might /loose the cursor/ and need to have it highlighted (using ~F6~), but also, this automatically highlights the cursor line with specific /actions/ , like changing windows.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package pulsar
|
(use-package pulsar
|
||||||
:straight (:type git :protocol ssh :host gitlab :repo "protesilaos/pulsar")
|
:straight (:type git :protocol ssh :host gitlab :repo "protesilaos/pulsar")
|
||||||
:custom
|
:custom
|
||||||
|
@ -152,52 +151,52 @@ Large screen, lots of windows, so where is the cursor? While I used to use =hl-l
|
||||||
(pulsar-face 'pulsar-magenta)
|
(pulsar-face 'pulsar-magenta)
|
||||||
(pulsar-delay 0.055)
|
(pulsar-delay 0.055)
|
||||||
:bind ("<f6>" . pulsar-pulse-line))
|
:bind ("<f6>" . pulsar-pulse-line))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Themes
|
* Themes
|
||||||
One does get used to a particular collection of colors. Mine is Tomorrow:
|
One does get used to a particular collection of colors. Mine is Tomorrow:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package color-theme-sanityinc-tomorrow)
|
(use-package color-theme-sanityinc-tomorrow)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Most of the time, Emacs is on my desk is a darkened room, so I choose the dark theme:
|
Most of the time, Emacs is on my desk is a darkened room, so I choose the dark theme:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun laptop-inside ()
|
(defun laptop-inside ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(load-theme 'sanityinc-tomorrow-night t)
|
(load-theme 'sanityinc-tomorrow-night t)
|
||||||
(set-face-attribute 'region nil :background "#000096")
|
(set-face-attribute 'region nil :background "#000096")
|
||||||
(set-face-attribute 'mode-line nil :background "black")
|
(set-face-attribute 'mode-line nil :background "black")
|
||||||
(set-face-attribute 'mode-line-inactive nil :background "#333333"))
|
(set-face-attribute 'mode-line-inactive nil :background "#333333"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
But, when feeling adventurous, I /sometimes/ take my laptop outside:
|
But, when feeling adventurous, I /sometimes/ take my laptop outside:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun laptop-in-the-sun ()
|
(defun laptop-in-the-sun ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(load-theme 'sanityinc-tomorrow-day t)
|
(load-theme 'sanityinc-tomorrow-day t)
|
||||||
(set-face-attribute 'region nil :background "orange1")
|
(set-face-attribute 'region nil :background "orange1")
|
||||||
(set-face-attribute 'mode-line nil :background "#cccccc")
|
(set-face-attribute 'mode-line nil :background "#cccccc")
|
||||||
(set-face-attribute 'mode-line-inactive nil :background "#888888"))
|
(set-face-attribute 'mode-line-inactive nil :background "#888888"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Oh, and turn off the line highlighting:
|
Oh, and turn off the line highlighting:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(global-hl-line-mode -1)
|
(global-hl-line-mode -1)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And of course, the default is /inside/ where it is dark and safe:
|
And of course, the default is /inside/ where it is dark and safe:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(laptop-inside)
|
(laptop-inside)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Full Size Frame
|
* Full Size Frame
|
||||||
|
|
||||||
Taken from [[https://emacsredux.com/blog/2020/12/04/maximize-the-emacs-frame-on-startup/][this essay]], I figured I would start the initial frame automatically in fullscreen, but not any subsequent frames (as this could be part of the capturing system).
|
Taken from [[https://emacsredux.com/blog/2020/12/04/maximize-the-emacs-frame-on-startup/][this essay]], I figured I would start the initial frame automatically in fullscreen, but not any subsequent frames (as this could be part of the capturing system).
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(add-to-list 'initial-frame-alist '(fullscreen . maximized))
|
(add-to-list 'initial-frame-alist '(fullscreen . maximized))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Font Configuration
|
* Font Configuration
|
||||||
Am I ever really ever satisfied with any font? I regularly change my font based on the monospace du jour... [[http://blogs.adobe.com/typblography/2012/09/source-code-pro.html][Source Code Pro]] is attractive, and has been a staple on every programmers' screen. However, we all want ligatures, [[https://github.com/i-tu/Hasklig][Hasklig]] is a nice font that is thinner and easier to read than [[https://github.com/tonsky/FiraCode][Fira]], but [[https://typeof.net/Iosevka/][Iosevka]] seems to have it all. Oh, Microsoft just gave us [[https://docs.microsoft.com/en-us/windows/terminal/cascadia-code][Cascadia]] and that seems shiny. However, the [[https://github.com/ryanoasis/nerd-fonts][Nerd Font project]] adds the ligatures as well as all the other niceties to a font.
|
Am I ever really ever satisfied with any font? I regularly change my font based on the monospace du jour... [[http://blogs.adobe.com/typblography/2012/09/source-code-pro.html][Source Code Pro]] is attractive, and has been a staple on every programmers' screen. However, we all want ligatures, [[https://github.com/i-tu/Hasklig][Hasklig]] is a nice font that is thinner and easier to read than [[https://github.com/tonsky/FiraCode][Fira]], but [[https://typeof.net/Iosevka/][Iosevka]] seems to have it all. Oh, Microsoft just gave us [[https://docs.microsoft.com/en-us/windows/terminal/cascadia-code][Cascadia]] and that seems shiny. However, the [[https://github.com/ryanoasis/nerd-fonts][Nerd Font project]] adds the ligatures as well as all the other niceties to a font.
|
||||||
|
@ -226,7 +225,7 @@ I stole the following idea from [[https://protesilaos.com/dotemacs/#h:9035a1ed-e
|
||||||
|
|
||||||
|
|
||||||
The following is from [[https://source-foundry.github.io/Hack/font-specimen.html][Hack's website]]:
|
The following is from [[https://source-foundry.github.io/Hack/font-specimen.html][Hack's website]]:
|
||||||
#+BEGIN_SRC c
|
#+begin_src c
|
||||||
// The four boxing wizards jump
|
// The four boxing wizards jump
|
||||||
#include <stdio.h> // <= quickly.
|
#include <stdio.h> // <= quickly.
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
@ -236,16 +235,16 @@ int main(int argc, char **argv) {
|
||||||
printf("@$Hamburgefo%c`",'\n');
|
printf("@$Hamburgefo%c`",'\n');
|
||||||
return ~7&8^9?0:l1|!"j->k+=*w";
|
return ~7&8^9?0:l1|!"j->k+=*w";
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
To install a font, I use the following command on my Mac:
|
To install a font, I use the following command on my Mac:
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
brew tap homebrew/cask-fonts
|
brew tap homebrew/cask-fonts
|
||||||
brew install --cask font-hack-nerd-font
|
brew install --cask font-hack-nerd-font
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Specifying a Font
|
** Specifying a Font
|
||||||
My /current/ favorite font is actually the top list of fonts that may be installed on my system (they usually are):
|
My /current/ favorite font is actually the top list of fonts that may be installed on my system (they usually are):
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defvar ha-fixed-font
|
(defvar ha-fixed-font
|
||||||
(when window-system
|
(when window-system
|
||||||
(cond
|
(cond
|
||||||
|
@ -261,15 +260,15 @@ My /current/ favorite font is actually the top list of fonts that may be install
|
||||||
((x-list-fonts "Anonymous Pro") "Anonymous Pro")
|
((x-list-fonts "Anonymous Pro") "Anonymous Pro")
|
||||||
(t "monospaced")))
|
(t "monospaced")))
|
||||||
"My fixed width font based on what is installed, `nil' if not defined.")
|
"My fixed width font based on what is installed, `nil' if not defined.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Force something as well:
|
Force something as well:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(setq ha-fixed-font "Hack Nerd Font")
|
(setq ha-fixed-font "Hack Nerd Font")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
I probably don't need to have such a ranking system, as chances are really good that I'll have all of them installed. Still.
|
I probably don't need to have such a ranking system, as chances are really good that I'll have all of them installed. Still.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defvar ha-variable-font
|
(defvar ha-variable-font
|
||||||
(when window-system
|
(when window-system
|
||||||
(cond ((x-list-fonts "Overpass") "Overpass")
|
(cond ((x-list-fonts "Overpass") "Overpass")
|
||||||
|
@ -279,22 +278,22 @@ I probably don't need to have such a ranking system, as chances are really good
|
||||||
((x-family-fonts "Sans Serif") "Sans Serif")
|
((x-family-fonts "Sans Serif") "Sans Serif")
|
||||||
(nil (warn "Cannot find a Sans Serif Font. Install Source Sans Pro."))))
|
(nil (warn "Cannot find a Sans Serif Font. Install Source Sans Pro."))))
|
||||||
"My variable width font available to org-mode files and whatnot.")
|
"My variable width font available to org-mode files and whatnot.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Simple function that gives me the font information based on the size I need. Recently updated after reading [[https://protesilaos.com/codelog/2020-09-05-emacs-note-mixed-font-heights/][this essay]], as I wanted my =fixed-pitch= to scale along with my =variable-pitch= font.
|
Simple function that gives me the font information based on the size I need. Recently updated after reading [[https://protesilaos.com/codelog/2020-09-05-emacs-note-mixed-font-heights/][this essay]], as I wanted my =fixed-pitch= to scale along with my =variable-pitch= font.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-set-favorite-font-size (size)
|
(defun ha-set-favorite-font-size (size)
|
||||||
"Set the default font size as well as equalize the fixed and variable fonts."
|
"Set the default font size as well as equalize the fixed and variable fonts."
|
||||||
(let ((fav-font (format "%s-%d" ha-fixed-font size)))
|
(let ((fav-font (format "%s-%d" ha-fixed-font size)))
|
||||||
(set-face-attribute 'default nil :font fav-font)
|
(set-face-attribute 'default nil :font fav-font)
|
||||||
(set-face-attribute 'fixed-pitch nil :family ha-fixed-font :inherit 'default :height 1.0)
|
(set-face-attribute 'fixed-pitch nil :family ha-fixed-font :inherit 'default :height 1.0)
|
||||||
(set-face-attribute 'variable-pitch nil :family ha-variable-font :inherit 'default :height 1.2)))
|
(set-face-attribute 'variable-pitch nil :family ha-variable-font :inherit 'default :height 1.2)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Define /interactive/ functions to quickly adjusting the font size based on my computing scenario:
|
Define /interactive/ functions to quickly adjusting the font size based on my computing scenario:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-mac-monitor-fontsize ()
|
(defun ha-mac-monitor-fontsize ()
|
||||||
"Quickly set reset my font size when I connect my laptop to a monitor on a Mac."
|
"Quickly set reset my font size when I connect my laptop to a monitor on a Mac."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -319,11 +318,11 @@ Define /interactive/ functions to quickly adjusting the font size based on my co
|
||||||
"Quickly set reset my font size when I am on my iMac."
|
"Quickly set reset my font size when I am on my iMac."
|
||||||
(interactive)
|
(interactive)
|
||||||
(ha-set-favorite-font-size 16))
|
(ha-set-favorite-font-size 16))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Which font to choose?
|
Which font to choose?
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun font-monitor-size-default ()
|
(defun font-monitor-size-default ()
|
||||||
"Set the default size according to my preference."
|
"Set the default size according to my preference."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -340,12 +339,12 @@ Which font to choose?
|
||||||
(ha-mac-laptop-fontsize)))
|
(ha-mac-laptop-fontsize)))
|
||||||
|
|
||||||
(font-monitor-size-default)
|
(font-monitor-size-default)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Zooming or Increasing Font Size
|
** Zooming or Increasing Font Size
|
||||||
Do we want to increase the size of font in a single window (using =text-scale-increase=), or globally (using my new =font-size-increase=)?
|
Do we want to increase the size of font in a single window (using =text-scale-increase=), or globally (using my new =font-size-increase=)?
|
||||||
|
|
||||||
Increase or decrease the set size of the face:
|
Increase or decrease the set size of the face:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun font-size-adjust (delta)
|
(defun font-size-adjust (delta)
|
||||||
"Adjust the current frame's font size.
|
"Adjust the current frame's font size.
|
||||||
DELTA would be something like 1 or -1."
|
DELTA would be something like 1 or -1."
|
||||||
|
@ -366,25 +365,25 @@ Increase or decrease the set size of the face:
|
||||||
"Decrease the `default' font size of all frames."
|
"Decrease the `default' font size of all frames."
|
||||||
(interactive)
|
(interactive)
|
||||||
(font-size-adjust -1))
|
(font-size-adjust -1))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And some keybindings to call them:
|
And some keybindings to call them:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(global-set-key (kbd "s-+") 'font-size-increase)
|
(global-set-key (kbd "s-+") 'font-size-increase)
|
||||||
(global-set-key (kbd "s-=") 'font-size-increase)
|
(global-set-key (kbd "s-=") 'font-size-increase)
|
||||||
(global-set-key (kbd "s--") 'font-size-decrease)
|
(global-set-key (kbd "s--") 'font-size-decrease)
|
||||||
(global-set-key (kbd "s-0") 'font-size-monitor-default)
|
(global-set-key (kbd "s-0") 'font-size-monitor-default)
|
||||||
(global-set-key (kbd "s-9") 'font-size-laptop-default)
|
(global-set-key (kbd "s-9") 'font-size-laptop-default)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Emojis, Icons and Whatnot
|
* Emojis, Icons and Whatnot
|
||||||
Sometimes two symbols should really be one, for instance:
|
Display these two symbols as one:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-hook 'text-mode-hook (lambda ()
|
(add-hook 'text-mode-hook (lambda ()
|
||||||
(push '("!?" . "‽") prettify-symbols-alist)))
|
(push '("!?" . "‽") prettify-symbols-alist)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
In Emacs 28.1, we have better Unicode 14 support. Which means, we need to install [[https://github.com/googlefonts/noto-emoji][Noto Color Emoji]]. Currently, my systems, seems to work just fine, but I’m leaving this code here in case I have issues, as I might use what Apple supplies when on a Mac (thanks [[http://xahlee.info/emacs/emacs/emacs_list_and_set_font.html][Xah Lee]]):
|
In Emacs 28.1, we have better Unicode 14 support. Which means, we need to install [[https://github.com/googlefonts/noto-emoji][Noto Color Emoji]]. My systems, seems to work fine, but I’m leaving this code here in case I have issues, as I might use what Apple supplies when on a Mac (thanks [[http://xahlee.info/emacs/emacs/emacs_list_and_set_font.html][Xah Lee]]):
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
;; set font for symbols
|
;; set font for symbols
|
||||||
(set-fontset-font t 'symbol
|
(set-fontset-font t 'symbol
|
||||||
(cond
|
(cond
|
||||||
|
@ -401,36 +400,35 @@ In Emacs 28.1, we have better Unicode 14 support. Which means, we need to instal
|
||||||
((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji")
|
((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji")
|
||||||
((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji")
|
((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji")
|
||||||
((member "Symbola" (font-family-list)) "Symbola")))
|
((member "Symbola" (font-family-list)) "Symbola")))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Test this out: 😄 😱 😸 👸 👽 🙋
|
Test this out: 😄 😱 😸 👸 👽 🙋
|
||||||
|
|
||||||
Not use what I'm doing with the [[https://github.com/domtronn/all-the-icons.el][all-the-icons]] package, but the Doom Modeline uses much of this.
|
Not use what I'm doing with the [[https://github.com/domtronn/all-the-icons.el][all-the-icons]] package, but the Doom Modeline uses much of this.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package all-the-icons)
|
(use-package all-the-icons)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*Note:* Install everything with the function, =all-the-icons-install-fonts=.
|
*Note:* Install everything with the function, =all-the-icons-install-fonts=.
|
||||||
* Ligatures
|
* Ligatures
|
||||||
|
|
||||||
Seems like getting ligatures to work in Emacs has been a Holy Grail. On Mac, I've used special builds that have hacks, but now with Emacs 27 and Harfbuzz, I should be able to get --> to look like it should.
|
Seems like getting ligatures to work in Emacs has been a Holy Grail. On Mac, I've used special builds that have hacks, but now with Emacs 27 and Harfbuzz, I should be able to get --> to look like it should.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(setq prettify-symbols-unprettify-at-point 'right-edge)
|
(setq prettify-symbols-unprettify-at-point 'right-edge)
|
||||||
|
|
||||||
(global-prettify-symbols-mode +1)
|
(global-prettify-symbols-mode +1)
|
||||||
(prettify-symbols-mode +1)
|
(prettify-symbols-mode +1)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Note, in Doom, is appears we have a =ligatures= module.
|
Note, in Doom, is appears we have a =ligatures= module.
|
||||||
We'll start using that instead, but changing it in [[file:general-programming.org][general-programming]] file.
|
We'll start using that instead, but changing it in [[file:general-programming.org][general-programming]] file.
|
||||||
|
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
|
|
||||||
Let's provide a name so that the file can be required:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
#+begin_src emacs-lisp :exports none
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
|
||||||
(provide 'ha-display)
|
(provide 'ha-display)
|
||||||
;;; ha-display.el ends here
|
;;; ha-display.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
175
ha-email.org
175
ha-email.org
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Configuring Emacs for Email with Notmuch
|
#+TITLE: Configuring Emacs for Email with Notmuch
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-09-16
|
#+DATE: 2020-09-16
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate configuration file for email using Notmuch.
|
A literate configuration file for email using Notmuch.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-email --- Email configuration using Notmuch. -*- lexical-binding: t; -*-
|
;;; ha-email --- Email configuration using Notmuch. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,36 +22,36 @@ A literate configuration file for email using Notmuch.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
To use this system, begin with ~SPC a m~ (after a ~SPC a n~ to asychronously download new mail ... which probably should be running regularly).
|
To use this system, begin with ~SPC a m~ (after a ~SPC a n~ to asychronously download new mail … which probably should be running beforehand).
|
||||||
|
|
||||||
When the Notmuch interface up, hit ~J~ to jump to one of the Search boxes (described below). Typically, this is ~i~ for the Imbox, check out the focused message from people I care). Hit ~q~ to return.
|
When the Notmuch interface up, hit ~J~ to jump to one of the Search boxes (described below). Typically, this is ~i~ for the Imbox, check out the focused message from people I care). Hit ~q~ to return.
|
||||||
|
|
||||||
Next type ~s~ to view and organize mail I've never seen before. We need to keep things focused, so regularly /making auto filtering rules/ is important. Move the point to the message and hit one of the following to automatically move the sender to a pre-defined box:
|
Next type ~s~ to view and organize mail I've never seen before. We need to focus the display, so /creating auto filtering rules/ is important. Move the point to the message and hit one of the following to automatically move the sender to a pre-defined box:
|
||||||
|
|
||||||
- ~I~ :: screened stuff that important enough to go to my Imbox
|
- ~I~ :: screened email important enough to go to my Imbox
|
||||||
- ~S~ :: spam ... so much goes here
|
- ~S~ :: spam … so much goes here
|
||||||
- ~P~ :: receipts go to this *Paper Trail*, which takes a *tag* as the name of the store
|
- ~P~ :: receipts go to this *Paper Trail*, which takes a *tag* as the name of the store
|
||||||
- ~f~ :: mailing lists and other things that might be nice to read go to *The Feed*
|
- ~f~ :: mailing lists and other email that might be nice to read go to *The Feed*
|
||||||
|
|
||||||
** Email Addresses
|
** Email Addresses
|
||||||
The configuration files below expect email addresses (I store passwords and other encrypted information elsewhere). These email addresses are /hardly/ private, but I figured I would annoy any screenscraping spam-inducing crawlers out there, while still allowing others to follow my lead on configuring Emacs and Email.
|
The configuration files below expect email addresses (I store passwords and other encrypted information elsewhere). These email addresses are /not/ private, but I figured I would annoy any screenscraping spam-inducing crawlers out there, while still allowing others to follow my lead on configuring Emacs and Email.
|
||||||
|
|
||||||
#+NAME: email-address-1
|
#+NAME: email-address-1
|
||||||
#+BEGIN_SRC emacs-lisp :exports none :tangle no :results silent
|
#+begin_src emacs-lisp :exports none :tangle no :results silent
|
||||||
(rot13-string "ubjneq.noenzf@tznvy.pbz")
|
(rot13-string "ubjneq.noenzf@tznvy.pbz")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+NAME: email-address-2
|
#+NAME: email-address-2
|
||||||
#+BEGIN_SRC emacs-lisp :exports none :tangle no :results silent
|
#+begin_src emacs-lisp :exports none :tangle no :results silent
|
||||||
(rot13-string "ubjneq@ubjneqnoenzf.pbz")
|
(rot13-string "ubjneq@ubjneqnoenzf.pbz")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+NAME: email-address-3
|
#+NAME: email-address-3
|
||||||
#+BEGIN_SRC emacs-lisp :exports none :tangle no :results silent
|
#+begin_src emacs-lisp :exports none :tangle no :results silent
|
||||||
(rot13-string "ubjneq@shmmlgbnfg.pbz")
|
(rot13-string "ubjneq@shmmlgbnfg.pbz")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
To use these, we set the =:noweb yes= (to pull in the /name/ of the code block) but put a pair of parens after the name to have it evaluated. For instance:
|
To use these, we set the =:noweb yes= (to pull in the /name/ of the code block) but put a pair of parens after the name to have it evaluated. For instance:
|
||||||
#+begin_example
|
#+begin_example
|
||||||
|
@ -65,19 +64,19 @@ some-address: <<email-address-2()>>
|
||||||
|
|
||||||
To begin, we need the code. On Ubuntu, this is:
|
To begin, we need the code. On Ubuntu, this is:
|
||||||
|
|
||||||
#+BEGIN_SRC shell :tangle no
|
#+begin_src shell :tangle no
|
||||||
sudo apt install -y notmuch
|
sudo apt install -y notmuch
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And on MacOS, we use =brew=:
|
And on MacOS, we use =brew=:
|
||||||
|
|
||||||
#+BEGIN_SRC shell :tangle no
|
#+begin_src shell :tangle no
|
||||||
brew install notmuch
|
brew install notmuch
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Next, we need some basic configuration settings and some global keybindings:
|
Next, we need some basic configuration settings and some global keybindings:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :noweb yes
|
#+begin_src emacs-lisp :noweb yes
|
||||||
(use-package notmuch
|
(use-package notmuch
|
||||||
:init
|
:init
|
||||||
(setq mail-user-agent 'notmuch-user-agent
|
(setq mail-user-agent 'notmuch-user-agent
|
||||||
|
@ -109,26 +108,26 @@ Next, we need some basic configuration settings and some global keybindings:
|
||||||
"C" '("reply-later" . hey-notmuch-reply-later))
|
"C" '("reply-later" . hey-notmuch-reply-later))
|
||||||
<<hey-show-keybindings>>
|
<<hey-show-keybindings>>
|
||||||
<<hey-search-keybindings>>)
|
<<hey-search-keybindings>>)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Also, let's do some basic configuration of Emacs' mail system:
|
Also, let's do some basic configuration of Emacs' mail system:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq mm-text-html-renderer 'shr
|
(setq mm-text-html-renderer 'shr
|
||||||
mail-specify-envelope-from t
|
mail-specify-envelope-from t
|
||||||
message-kill-buffer-on-exit t
|
message-kill-buffer-on-exit t
|
||||||
message-send-mail-function 'message-send-mail-with-sendmail
|
message-send-mail-function 'message-send-mail-with-sendmail
|
||||||
message-sendmail-envelope-from 'header)
|
message-sendmail-envelope-from 'header)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Configuration
|
* Configuration
|
||||||
Do I want to sign messages by default? Nope.
|
Do I want to sign messages by default? Nope.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(add-hook 'message-setup-hook 'mml-secure-sign-pgpmime)
|
(add-hook 'message-setup-hook 'mml-secure-sign-pgpmime)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Addresses
|
** Addresses
|
||||||
|
|
||||||
I need to incorporate an address book again, but in the meantime, searching through a history of past email works well enough.
|
I need to incorporate an address book again, but in the meantime, searching through a history of past email works well enough.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq notmuch-address-selection-function
|
(setq notmuch-address-selection-function
|
||||||
(lambda (prompt collection initial-input)
|
(lambda (prompt collection initial-input)
|
||||||
(completing-read prompt
|
(completing-read prompt
|
||||||
|
@ -137,7 +136,7 @@ I need to incorporate an address book again, but in the meantime, searching thro
|
||||||
t
|
t
|
||||||
nil
|
nil
|
||||||
'notmuch-address-history)))
|
'notmuch-address-history)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Sending Messages
|
** Sending Messages
|
||||||
|
|
||||||
Do I need to set up [[https://marlam.de/msmtp/][MSMTP]]? No, as Notmuch will do that work.
|
Do I need to set up [[https://marlam.de/msmtp/][MSMTP]]? No, as Notmuch will do that work.
|
||||||
|
@ -147,19 +146,18 @@ To do this, type ~c~ and select an option (including ~r~ to reply).
|
||||||
|
|
||||||
When we start notmuch, we need to retrieve the email and then process it. Most of this is actually contained in the Notmuch configuration.
|
When we start notmuch, we need to retrieve the email and then process it. Most of this is actually contained in the Notmuch configuration.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun notmuch-retrieve-messages ()
|
(defun notmuch-retrieve-messages ()
|
||||||
"Retrieve and process my mail messages."
|
"Retrieve and process my mail messages."
|
||||||
(interactive)
|
(interactive)
|
||||||
(async-shell-command "notmuch new"))
|
(async-shell-command "notmuch new"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* iSync Configuration
|
* iSync Configuration
|
||||||
Using [[https://isync.sourceforge.io/][isync]] (or is it =mbsync=) for mail retrieval.
|
Using [[https://isync.sourceforge.io/][isync]] (or is it =mbsync=) for mail retrieval. I have a couple of Google Mail accounts that I want connected.
|
||||||
Currently, I have a couple of Google Mail accounts that I want connected.
|
|
||||||
|
|
||||||
The file generally can have a =Pass= entry for the encrypted passcode, but in order to demonstrate how to connect to multiple accounts, I'm using a GPG daemon:
|
The file generally can have a =Pass= entry for the encrypted passcode, but to show how to connect to more than one accounts, I'm using a GPG daemon:
|
||||||
|
|
||||||
#+BEGIN_SRC conf :tangle ~/.mbsyncrc :noweb yes
|
#+begin_src conf :tangle ~/.mbsyncrc :noweb yes
|
||||||
# Note: We now tangle this file from ~/other/hamacs/ha-email.org
|
# Note: We now tangle this file from ~/other/hamacs/ha-email.org
|
||||||
Create Both
|
Create Both
|
||||||
SyncState *
|
SyncState *
|
||||||
|
@ -169,7 +167,7 @@ The file generally can have a =Pass= entry for the encrypted passcode, but in or
|
||||||
# PERSONAL ACCOUNT
|
# PERSONAL ACCOUNT
|
||||||
IMAPAccount personal
|
IMAPAccount personal
|
||||||
Host imap.gmail.com
|
Host imap.gmail.com
|
||||||
User <<email-address-2()>> # Obviously, you'd substitute your own email address here
|
User <<email-address-2()>> # Substitute your own email address here
|
||||||
PassCmd "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.mailpass-personal.gpg"
|
PassCmd "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.mailpass-personal.gpg"
|
||||||
SSLType IMAPS
|
SSLType IMAPS
|
||||||
AuthMechs LOGIN
|
AuthMechs LOGIN
|
||||||
|
@ -232,67 +230,63 @@ The file generally can have a =Pass= entry for the encrypted passcode, but in or
|
||||||
Master :gmail-remote:"[Gmail]/Trash"
|
Master :gmail-remote:"[Gmail]/Trash"
|
||||||
Slave :gmail-local:trash
|
Slave :gmail-local:trash
|
||||||
ExpireUnread yes
|
ExpireUnread yes
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Notmuch Configuration
|
* Notmuch Configuration
|
||||||
Notmuch requires a few configuration files.
|
Notmuch requires these configuration files.
|
||||||
** =notmuch-config=
|
** =notmuch-config=
|
||||||
The general settings file that goes into =~/.notmuch-config=:
|
The general settings file that goes into =~/.notmuch-config=:
|
||||||
|
|
||||||
#+BEGIN_SRC conf-unix :tangle ~/.notmuch-config
|
#+begin_src conf-unix :tangle ~/.notmuch-config
|
||||||
# .notmuch-config - Configuration file for the notmuch mail system
|
# .notmuch-config - Configuration file for the notmuch mail system
|
||||||
# Note: We now tangle this file from ~/other/hamacs/ha-email.org
|
# Note: We now tangle this file from ~/other/hamacs/ha-email.org
|
||||||
#
|
#
|
||||||
# For more information about notmuch, see https://notmuchmail.org
|
# For more information about notmuch, see https://notmuchmail.org
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The commentary for each of the subsections came from their man page.
|
The commentary for each of the subsections came from their man page.
|
||||||
*** Database configuration
|
*** Database configuration
|
||||||
The only value supported here is 'path' which should be the top-level directory where your mail currently exists and to where mail will be delivered in the future. Files should be individual email messages. Notmuch will store its database within a sub-directory of the path configured here named ".notmuch".
|
The value supported here is =path= which should be the top-level directory where your mail exists and to where =mbsync= will new mail. Files should be individual email messages. Notmuch will store its database within a sub-directory of the path configured here named ".notmuch".
|
||||||
|
|
||||||
#+BEGIN_SRC conf-unix :tangle ~/.notmuch-config
|
#+begin_src conf-unix :tangle ~/.notmuch-config
|
||||||
[database]
|
[database]
|
||||||
path=.mail
|
path=.mail
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** User configuration
|
*** User configuration
|
||||||
Here is where you can let notmuch know how you would like to be addressed. Valid settings are
|
Here is where you can let notmuch know how you address emails. Valid settings are
|
||||||
|
|
||||||
- =name= :: Your full name.
|
- =name= :: Your full name.
|
||||||
- =primary_email= :: Your primary email address.
|
- =primary_email= :: Your primary email address.
|
||||||
- =other_email= :: A list (separated by =;=) of other email addresses at which you receive email.
|
- =other_email= :: A list (separated by =;=) of other email addresses at which you receive email.
|
||||||
|
|
||||||
Notmuch will use the various email addresses configured here when formatting replies. It will avoid including your own addresses in the recipient list of replies, and will set the From address based on the address to which the original email was addressed.
|
Notmuch use the email addresses configured here when formatting replies. It will avoid including your own addresses in the recipient list of replies, and will set the From address based on the address in the original email.
|
||||||
|
|
||||||
#+BEGIN_SRC conf-unix :tangle ~/.notmuch-config :noweb yes
|
#+begin_src conf-unix :tangle ~/.notmuch-config :noweb yes
|
||||||
[user]
|
[user]
|
||||||
name=Howard Abrams
|
name=Howard Abrams
|
||||||
primary_email=<<email-address-1()>>
|
primary_email=<<email-address-1()>>
|
||||||
other_email=<<email-address-2()>>;<<email-address-3()>>
|
other_email=<<email-address-2()>>;<<email-address-3()>>
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*NB:* In the configuration above, you may see the addresses are all set to =nil=. If you are copying this from a rendered web page, just note that you need to substitute that with your own email address.
|
*NB:* In the configuration above, you may see the addresses are all set to =nil=. If you are copying this from a rendered web page, note that you need to substitute that with your own email address.
|
||||||
*** Configuration for "notmuch new"
|
*** Configuration for "notmuch new"
|
||||||
The following options are supported here:
|
Note the following supported options:
|
||||||
|
- =tags= :: A list (separated by =;=) of the tags that added to all messages incorporated by "notmuch new".
|
||||||
- =tags= :: A list (separated by =;=) of the tags that will be added to all messages incorporated by "notmuch new".
|
|
||||||
|
|
||||||
- =ignore= :: A list (separated by =;=) of file and directory names that will not be searched for messages by "notmuch new".
|
- =ignore= :: A list (separated by =;=) of file and directory names that will not be searched for messages by "notmuch new".
|
||||||
|
|
||||||
NOTE: *Every* file/directory that goes by one of those names will be ignored, independent of its depth/location in the mail store.
|
NOTE: *Every* file/directory that goes by one of those names will be ignored, independent of its depth/location in the mail store.
|
||||||
|
#+begin_src conf-unix :tangle ~/.notmuch-config
|
||||||
#+BEGIN_SRC conf-unix :tangle ~/.notmuch-config
|
|
||||||
[new]
|
[new]
|
||||||
tags=unread;inbox;
|
tags=unread;inbox;
|
||||||
ignore=
|
ignore=
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Search configuration
|
*** Search configuration
|
||||||
The following option is supported here:
|
The following option is supported here:
|
||||||
|
|
||||||
- =exclude_tags= :: A ;-separated list of tags that will be excluded from search results by default. Using an excluded tag in a query will override that exclusion.
|
- =exclude_tags= :: A ;-separated list of tags that will be excluded from search results by default. Using an excluded tag in a query will override that exclusion.
|
||||||
|
|
||||||
#+BEGIN_SRC conf-unix :tangle ~/.notmuch-config
|
#+begin_src conf-unix :tangle ~/.notmuch-config
|
||||||
[search]
|
[search]
|
||||||
exclude_tags=deleted;spam;
|
exclude_tags=deleted;spam;
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Maildir compatibility configuration
|
*** Maildir compatibility configuration
|
||||||
The following option is supported here:
|
The following option is supported here:
|
||||||
|
|
||||||
|
@ -308,16 +302,16 @@ The following option is supported here:
|
||||||
|
|
||||||
The =notmuch new= command will notice flag changes in filenames and update tags, while the =notmuch tag= and =notmuch restore= commands will notice tag changes and update flags in filenames.
|
The =notmuch new= command will notice flag changes in filenames and update tags, while the =notmuch tag= and =notmuch restore= commands will notice tag changes and update flags in filenames.
|
||||||
|
|
||||||
#+BEGIN_SRC conf-unix :tangle ~/.notmuch-config
|
#+begin_src conf-unix :tangle ~/.notmuch-config
|
||||||
[maildir]
|
[maildir]
|
||||||
synchronize_flags=true
|
synchronize_flags=true
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
That should complete the Notmuch configuration.
|
That should complete the Notmuch configuration.
|
||||||
** =pre-new=
|
** =pre-new=
|
||||||
Then we need a shell script called when beginning a retrieval, =pre-new= that simply calls =mbsync= to download all the messages:
|
Then we need a shell script called when beginning a retrieval, =pre-new= that simply calls =mbsync= to download all the messages:
|
||||||
|
|
||||||
#+BEGIN_SRC shell :tangle ~/.mail/.notmuch/hooks/pre-new :shebang "#!/bin/bash"
|
#+begin_src shell :tangle ~/.mail/.notmuch/hooks/pre-new :shebang "#!/bin/bash"
|
||||||
# More info about hooks: https://notmuchmail.org/manpages/notmuch-hooks-5/
|
# More info about hooks: https://notmuchmail.org/manpages/notmuch-hooks-5/
|
||||||
# Note: We now tangle this file from ~/other/hamacs/ha-email.org
|
# Note: We now tangle this file from ~/other/hamacs/ha-email.org
|
||||||
|
|
||||||
|
@ -326,11 +320,11 @@ echo "Starting not-much 'pre-new' script"
|
||||||
mbsync -a
|
mbsync -a
|
||||||
|
|
||||||
echo "Completing not-much 'pre-new' script"
|
echo "Completing not-much 'pre-new' script"
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** =post-new=
|
** =post-new=
|
||||||
And a =post-new= hook based on a filtering scheme that mimics the Hey.com workflow taken from [[https://gist.githubusercontent.com/frozencemetery/5042526/raw/57195ba748e336de80c27519fe66e428e5003ab8/post-new][this gist]] (note we have more to say on that later on) to filter and tag all messages after they have arrived:
|
And a =post-new= hook based on a filtering scheme that mimics the Hey.com workflow taken from [[https://gist.githubusercontent.com/frozencemetery/5042526/raw/57195ba748e336de80c27519fe66e428e5003ab8/post-new][this gist]] (note we have more to say on that later on) to filter and tag all messages after they have arrived:
|
||||||
|
|
||||||
#+BEGIN_SRC shell :tangle ~/.mail/.notmuch/hooks/post-new :shebang "#!/bin/bash"
|
#+begin_src shell :tangle ~/.mail/.notmuch/hooks/post-new :shebang "#!/bin/bash"
|
||||||
# Based On: https://gist.githubusercontent.com/frozencemetery/5042526/raw/57195ba748e336de80c27519fe66e428e5003ab8/post-new
|
# Based On: https://gist.githubusercontent.com/frozencemetery/5042526/raw/57195ba748e336de80c27519fe66e428e5003ab8/post-new
|
||||||
# Note: We now tangle this file from ~/other/hamacs/ha-email.org
|
# Note: We now tangle this file from ~/other/hamacs/ha-email.org
|
||||||
#
|
#
|
||||||
|
@ -422,7 +416,7 @@ timer_end "Old-Projects"
|
||||||
notmuch tag +screened 'subject:[Web]'
|
notmuch tag +screened 'subject:[Web]'
|
||||||
|
|
||||||
echo "Completing not-much 'post-new' script"
|
echo "Completing not-much 'post-new' script"
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Hey
|
* Hey
|
||||||
I originally took the following configuration from [[https://youtu.be/wuSPssykPtE][Vedang Manerikar's video]], along with [[https://gist.github.com/vedang/26a94c459c46e45bc3a9ec935457c80f][the code]]. The ideas brought out were to mimic the hey.com email workflow, and while not bad, I thought that maybe I could improve upon it slowly over time.
|
I originally took the following configuration from [[https://youtu.be/wuSPssykPtE][Vedang Manerikar's video]], along with [[https://gist.github.com/vedang/26a94c459c46e45bc3a9ec935457c80f][the code]]. The ideas brought out were to mimic the hey.com email workflow, and while not bad, I thought that maybe I could improve upon it slowly over time.
|
||||||
|
|
||||||
|
@ -431,7 +425,7 @@ To allow me to keep Vedang's and my code side-by-side in the same Emacs variable
|
||||||
|
|
||||||
A list of pre-defined searches act like "Folder buttons" at the top to quickly see files that match those /buckets/:
|
A list of pre-defined searches act like "Folder buttons" at the top to quickly see files that match those /buckets/:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq notmuch-saved-searches '((:name "Imbox"
|
(setq notmuch-saved-searches '((:name "Imbox"
|
||||||
:query "tag:inbox AND tag:screened AND tag:unread"
|
:query "tag:inbox AND tag:screened AND tag:unread"
|
||||||
:key "i"
|
:key "i"
|
||||||
|
@ -464,12 +458,12 @@ A list of pre-defined searches act like "Folder buttons" at the top to quickly s
|
||||||
(:name "Old Projects"
|
(:name "Old Projects"
|
||||||
:query "tag:old-project AND NOT tag:unread"
|
:query "tag:old-project AND NOT tag:unread"
|
||||||
:key "X")))
|
:key "X")))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Helper Functions
|
** Helper Functions
|
||||||
|
|
||||||
With good bucket definitions, we should be able to scan the mail quickly and deal with the entire lot of them:
|
With good bucket definitions, we should be able to scan the mail quickly and deal with the entire lot of them:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun hey-notmuch-archive-all ()
|
(defun hey-notmuch-archive-all ()
|
||||||
"Archive all the emails in the current view."
|
"Archive all the emails in the current view."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -495,11 +489,11 @@ When called directly, BEG and END provide the region."
|
||||||
(interactive (notmuch-search-interactive-tag-changes))
|
(interactive (notmuch-search-interactive-tag-changes))
|
||||||
(notmuch-search-tag tag-changes beg end)
|
(notmuch-search-tag tag-changes beg end)
|
||||||
(notmuch-search-archive-thread nil beg end))
|
(notmuch-search-archive-thread nil beg end))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
A key point in organizing emails with the Hey model, is looking at the "from" address:
|
A key point in organizing emails with the Hey model, is looking at the "from" address:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun hey-notmuch-search-find-from ()
|
(defun hey-notmuch-search-find-from ()
|
||||||
"A helper function to find the email address for the given email."
|
"A helper function to find the email address for the given email."
|
||||||
(let ((notmuch-addr-sexp (first
|
(let ((notmuch-addr-sexp (first
|
||||||
|
@ -509,11 +503,11 @@ A key point in organizing emails with the Hey model, is looking at the "from" ad
|
||||||
"--output=sender"
|
"--output=sender"
|
||||||
(notmuch-search-find-thread-id)))))
|
(notmuch-search-find-thread-id)))))
|
||||||
(plist-get notmuch-addr-sexp :address)))
|
(plist-get notmuch-addr-sexp :address)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And we can create a filter, /search/ and tagging based on this "from" function:
|
And we can create a filter, /search/ and tagging based on this "from" function:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun hey-notmuch-filter-by-from ()
|
(defun hey-notmuch-filter-by-from ()
|
||||||
"Filter the current search view to show all emails sent from the sender of the current thread."
|
"Filter the current search view to show all emails sent from the sender of the current thread."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -546,13 +540,13 @@ search."
|
||||||
(when refresh
|
(when refresh
|
||||||
(set-buffer this-buf)
|
(set-buffer this-buf)
|
||||||
(notmuch-refresh-this-buffer))))
|
(notmuch-refresh-this-buffer))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Moving Mail to Buckets
|
** Moving Mail to Buckets
|
||||||
|
|
||||||
We based the Hey buckets on notmuch databases, we combine the =hey-notmuch-add-addr-to-db= with the =hey-notmuch-tag-by-from= functions to move messages.
|
We based the Hey buckets on notmuch databases, we combine the =hey-notmuch-add-addr-to-db= with the =hey-notmuch-tag-by-from= functions to move messages.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun hey-notmuch-add-addr-to-db (nmaddr nmdbfile)
|
(defun hey-notmuch-add-addr-to-db (nmaddr nmdbfile)
|
||||||
"Add the email address NMADDR to the db-file NMDBFILE."
|
"Add the email address NMADDR to the db-file NMDBFILE."
|
||||||
(append-to-file (format "%s\n" nmaddr) nil nmdbfile))
|
(append-to-file (format "%s\n" nmaddr) nil nmdbfile))
|
||||||
|
@ -626,12 +620,12 @@ This means:
|
||||||
(substring (notmuch-show-get-from) 0 15)))
|
(substring (notmuch-show-get-from) 0 15)))
|
||||||
(email-string (format "%s (From: %s)" email-subject email-from)))
|
(email-string (format "%s (From: %s)" email-subject email-from)))
|
||||||
(message "Noted! Reply Later: %s" email-string)))
|
(message "Noted! Reply Later: %s" email-string)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Bucket Keybindings
|
** Bucket Keybindings
|
||||||
In /Emacs/ mode, we can just call =define-key=, but since it starts in Evil state (and we may want to use Evil keybindings, let's create some local leaders:
|
In /Emacs/ mode, we can just call =define-key=, but since it starts in Evil state (and we may want to use Evil keybindings, let's create some local leaders:
|
||||||
|
|
||||||
#+NAME: local-leader-keybindings
|
#+NAME: local-leader-keybindings
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(general-create-definer ha-mail-hello-leader
|
(general-create-definer ha-mail-hello-leader
|
||||||
:states '(normal visual motion)
|
:states '(normal visual motion)
|
||||||
:keymaps 'notmuch-hello-mode-map
|
:keymaps 'notmuch-hello-mode-map
|
||||||
|
@ -652,23 +646,23 @@ In /Emacs/ mode, we can just call =define-key=, but since it starts in Evil stat
|
||||||
:prefix "SPC m"
|
:prefix "SPC m"
|
||||||
:global-prefix "<f17>"
|
:global-prefix "<f17>"
|
||||||
:non-normal-prefix "S-SPC")
|
:non-normal-prefix "S-SPC")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
A series of keybindings to quickly send messages to one of the pre-defined buckets.
|
A series of keybindings to quickly send messages to one of the pre-defined buckets.
|
||||||
|
|
||||||
#+NAME: hey-show-keybindings
|
#+NAME: hey-show-keybindings
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(ha-mail-show-leader
|
(ha-mail-show-leader
|
||||||
"c" '("compose" . notmuch-mua-new-mail)
|
"c" '("compose" . notmuch-mua-new-mail)
|
||||||
"C" '("reply-later" . hey-notmuch-reply-later))
|
"C" '("reply-later" . hey-notmuch-reply-later))
|
||||||
|
|
||||||
(define-key notmuch-show-mode-map (kbd "C") 'hey-notmuch-reply-later)
|
(define-key notmuch-show-mode-map (kbd "C") 'hey-notmuch-reply-later)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The bindings in =notmuch-search-mode= are available when looking at a list of messages:
|
The bindings in =notmuch-search-mode= are available when looking at a list of messages:
|
||||||
|
|
||||||
#+NAME: hey-search-keybindings
|
#+NAME: hey-search-keybindings
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(ha-mail-search-leader
|
(ha-mail-search-leader
|
||||||
"r" '("reply" . notmuch-search-reply-to-thread)
|
"r" '("reply" . notmuch-search-reply-to-thread)
|
||||||
"R" '("reply-all" . notmuch-search-reply-to-thread-sender)
|
"R" '("reply-all" . notmuch-search-reply-to-thread-sender)
|
||||||
|
@ -700,19 +694,19 @@ The bindings in =notmuch-search-mode= are available when looking at a list of me
|
||||||
(define-key notmuch-search-mode-map (kbd "P") 'hey-notmuch-move-sender-to-papertrail)
|
(define-key notmuch-search-mode-map (kbd "P") 'hey-notmuch-move-sender-to-papertrail)
|
||||||
(define-key notmuch-search-mode-map (kbd "f") 'hey-notmuch-move-sender-to-thefeed)
|
(define-key notmuch-search-mode-map (kbd "f") 'hey-notmuch-move-sender-to-thefeed)
|
||||||
(define-key notmuch-search-mode-map (kbd "C") 'hey-notmuch-reply-later)
|
(define-key notmuch-search-mode-map (kbd "C") 'hey-notmuch-reply-later)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Org Integration
|
** Org Integration
|
||||||
The gods ordained that Mail and Org should dance together, so step one is composing mail with org:
|
The gods ordained that Mail and Org should dance together, so step one is composing mail with org:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-mime
|
(use-package org-mime
|
||||||
:config
|
:config
|
||||||
(ha-local-leader
|
(ha-local-leader
|
||||||
:keymaps 'notmuch-message-mode-map
|
:keymaps 'notmuch-message-mode-map
|
||||||
"s" '("send" . notmuch-mua-send-and-exit)
|
"s" '("send" . notmuch-mua-send-and-exit)
|
||||||
"m" '("mime it" . org-mime-htmlize)))
|
"m" '("mime it" . org-mime-htmlize)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
A new option is to use [[https://github.com/jeremy-compostella/org-msg][org-msg]], so let's try it:
|
A new option is to use [[https://github.com/jeremy-compostella/org-msg][org-msg]], so let's try it:
|
||||||
#+BEGIN_SRC emacs-lisp :noweb yes
|
#+begin_src emacs-lisp :noweb yes
|
||||||
(use-package org-msg
|
(use-package org-msg
|
||||||
:init
|
:init
|
||||||
(setq org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil \\n:t"
|
(setq org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil \\n:t"
|
||||||
|
@ -733,30 +727,29 @@ A new option is to use [[https://github.com/jeremy-compostella/org-msg][org-msg]
|
||||||
,*Howard*
|
,*Howard*
|
||||||
/One Emacs to rule them all/
|
/One Emacs to rule them all/
|
||||||
,#+end_signature"))
|
,#+end_signature"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The idea of linking org documents to email could be nice, however, the =ol-notmuch= package in the [[https://elpa.nongnu.org/nongnu/org-contrib.html][org-contrib]] package needs a maintainer.
|
The idea of linking org documents to email could be nice, however, the =ol-notmuch= package in the [[https://elpa.nongnu.org/nongnu/org-contrib.html][org-contrib]] package needs a maintainer.
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package ol-notmuch
|
(use-package ol-notmuch
|
||||||
:after org
|
:after org
|
||||||
:straight (:type built-in)
|
:straight (:type built-in)
|
||||||
:config (add-to-list 'org-modules 'ol-notmuch))
|
:config (add-to-list 'org-modules 'ol-notmuch))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
To use, read a message and save a link to it with ~SPC o l~. Next, in an org document, create a link with ~SPC m l~. Now, you can return to the message from that document with ~SPC m o~. Regardless, I may need to store a local copy when I upgrade Org.
|
To use, read a message and save a link to it with ~SPC o l~. Next, in an org document, create a link with ~SPC m l~. Now, you can return to the message from that document with ~SPC m o~. Regardless, I may need to store a local copy when I upgrade Org.
|
||||||
* Display Configuration
|
* Display Configuration
|
||||||
Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications:
|
Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package doom-modeline
|
(use-package doom-modeline
|
||||||
:config
|
:config
|
||||||
(setq doom-modeline-mu4e t))
|
(setq doom-modeline-mu4e t))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's provide a name so that the file can be required:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
#+begin_src emacs-lisp :exports none
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
|
||||||
(provide 'ha-email)
|
(provide 'ha-email)
|
||||||
;;; ha-email.el ends here
|
;;; ha-email.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: A literate configuration file for email using Notmuch.
|
#+DESCRIPTION: A literate configuration file for email using Notmuch.
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: My RSS Feeds
|
#+TITLE: My RSS Feeds
|
||||||
#+AUTHOR: Howard Abrams
|
#+AUTHOR: Howard Abrams
|
||||||
#+DATE: 2018-08-08 August
|
#+DATE: 2018-08-08 August
|
||||||
#+FILETAGS: :elfeed:
|
|
||||||
|
|
||||||
A literate programming file for configuring =elfeed= in Emacs.
|
A literate programming file for configuring =elfeed= in Emacs.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-config --- ElFeed configuration. -*- lexical-binding: t; -*-
|
;;; ha-config --- ElFeed configuration. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,19 +22,19 @@ A literate programming file for configuring =elfeed= in Emacs.
|
||||||
;; Using `find-file-at-point', and tangle the file to recreate this one .
|
;; Using `find-file-at-point', and tangle the file to recreate this one .
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Configuring Elfeed
|
* Configuring Elfeed
|
||||||
Let's get our feeds from a collection of org mode files. By default, Doom configures =rmh-elfeed-org-files= to [[file:~/Dropbox/org/elfeed.org][elfeed.org]] in =org-directory=, so that will be fine.
|
Let's get our feeds from a collection of org mode files. By default, Doom configures =rmh-elfeed-org-files= to [[file:~/Dropbox/org/elfeed.org][elfeed.org]] in =org-directory=, so that will be fine.
|
||||||
|
|
||||||
By setting this variable, we configure elfeed to use elfeed:
|
By setting this variable, we configure elfeed to use elfeed:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq rmh-elfeed-org-files (list (f-join hamacs-source-dir "ha-feed-reader.org")))
|
(setq rmh-elfeed-org-files (list (f-join hamacs-source-dir "ha-feed-reader.org")))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
While I would like to share the /status/ of my reads, so ...
|
While I would like to share the /status/ of my reads, so ...
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package elfeed
|
(use-package elfeed
|
||||||
:init
|
:init
|
||||||
(setq elfeed-db-directory "~/dropbox/.elfeed/")
|
(setq elfeed-db-directory "~/dropbox/.elfeed/")
|
||||||
|
@ -63,11 +62,11 @@ While I would like to share the /status/ of my reads, so ...
|
||||||
(interactive)
|
(interactive)
|
||||||
(elfeed-search-untag-all 'unread)
|
(elfeed-search-untag-all 'unread)
|
||||||
(elfeed-search-update))
|
(elfeed-search-update))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
According to Ben Maughan and [[http://pragmaticemacs.com/emacs/to-eww-or-not-to-eww/][this Pragmatic Emacs essay]], we could easily browse an article in the GUI browser instead of EWW with capital B:
|
According to Ben Maughan and [[http://pragmaticemacs.com/emacs/to-eww-or-not-to-eww/][this Pragmatic Emacs essay]], we could easily browse an article in the GUI browser instead of EWW with capital B:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package elfeed
|
(use-package elfeed
|
||||||
:config
|
:config
|
||||||
(defun elfeed-show-visit-gui ()
|
(defun elfeed-show-visit-gui ()
|
||||||
|
@ -78,10 +77,10 @@ According to Ben Maughan and [[http://pragmaticemacs.com/emacs/to-eww-or-not-to-
|
||||||
|
|
||||||
:bind (:map elfeed-show-mode-map
|
:bind (:map elfeed-show-mode-map
|
||||||
("B" . elfeed-show-visit-gui)))
|
("B" . elfeed-show-visit-gui)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Quick way to start and jump to my world of feeds.
|
Quick way to start and jump to my world of feeds.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-elfeed-persp-start ()
|
(defun ha-elfeed-persp-start ()
|
||||||
"Create an ELFEED workspace and start my ELFEED client."
|
"Create an ELFEED workspace and start my ELFEED client."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -92,15 +91,15 @@ Quick way to start and jump to my world of feeds.
|
||||||
"Switch to the ELFEED workspace and load the next buffer."
|
"Switch to the ELFEED workspace and load the next buffer."
|
||||||
(interactive)
|
(interactive)
|
||||||
(persp-switch "feeds"))
|
(persp-switch "feeds"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And some global keys to display them in the =apps= menu:
|
And some global keys to display them in the =apps= menu:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader
|
(ha-leader
|
||||||
"a f" '("elfeed switch" . ha-elfeed-persp-switch)
|
"a f" '("elfeed switch" . ha-elfeed-persp-switch)
|
||||||
"a F" '("elfeed start" . ha-elfeed-persp-start))
|
"a F" '("elfeed start" . ha-elfeed-persp-start))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* The Feeds :elfeed:
|
* The Feeds :elfeed:
|
||||||
** Personal :personal:
|
** Personal :personal:
|
||||||
*** [[http://www.howardism.org/index.xml][Howardisms]] :mustread:
|
*** [[http://www.howardism.org/index.xml][Howardisms]] :mustread:
|
||||||
|
@ -250,10 +249,10 @@ Has some good, thought-provoking essays.
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's /provide/ a name so we can =require= the file:
|
Let's /provide/ a name so we can =require= the file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-feed-reader)
|
(provide 'ha-feed-reader)
|
||||||
;;; ha-feed-reader.el ends here
|
;;; ha-feed-reader.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: A literate programming file for configuring elfeed.
|
#+DESCRIPTION: A literate programming file for configuring elfeed.
|
||||||
|
|
||||||
|
|
43
ha-irc.org
43
ha-irc.org
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: IRC and Bitlbee Interface
|
#+TITLE: IRC and Bitlbee Interface
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-12-10
|
#+DATE: 2020-12-10
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming configuration file for IRC communiction.
|
A literate programming configuration file for IRC communiction.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-irc.el --- configuration for IRC communication. -*- lexical-binding: t; -*-
|
;;; ha-irc.el --- configuration for IRC communication. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,11 +22,11 @@ A literate programming configuration file for IRC communiction.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
My IRC /needs/ are basic, but I'm not sure which I want to use.
|
My IRC /needs/ are basic, but I'm not sure which I want to use.
|
||||||
** ERC
|
** ERC
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package erc-hl-nicks
|
(use-package erc-hl-nicks
|
||||||
:after erc)
|
:after erc)
|
||||||
|
|
||||||
|
@ -71,20 +70,20 @@ My IRC /needs/ are basic, but I'm not sure which I want to use.
|
||||||
(erc :server "howardabrams.com" :port 7777)
|
(erc :server "howardabrams.com" :port 7777)
|
||||||
(sit-for 2)
|
(sit-for 2)
|
||||||
(erc-cmd-QUOTE (format "PASS %s:%s" username password))))
|
(erc-cmd-QUOTE (format "PASS %s:%s" username password))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
I like to make sure the text formats to the size of the window:
|
I like to make sure the text formats to the size of the window:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-erc-resize-text ()
|
(defun ha-erc-resize-text ()
|
||||||
"Resize the ERC text to fill the current window."
|
"Resize the ERC text to fill the current window."
|
||||||
(interactive)
|
(interactive)
|
||||||
(setq erc-fill-column (1- (window-width))))
|
(setq erc-fill-column (1- (window-width))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* ZNC Server
|
* ZNC Server
|
||||||
I'm using my own ZNC server, and I need to log in with a password stored in my GPG auth storage:
|
I'm using my own ZNC server, and I need to log in with a password stored in my GPG auth storage:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-erc-reconnect-password ()
|
(defun ha-erc-reconnect-password ()
|
||||||
"Send the reconnection password string."
|
"Send the reconnection password string."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -94,11 +93,11 @@ I'm using my own ZNC server, and I need to log in with a password stored in my G
|
||||||
(username (plist-get auth-first :user))
|
(username (plist-get auth-first :user))
|
||||||
(password (funcall (plist-get auth-first :secret))))
|
(password (funcall (plist-get auth-first :secret))))
|
||||||
(erc-cmd-QUOTE (format "PASS %s:%s" username password))))
|
(erc-cmd-QUOTE (format "PASS %s:%s" username password))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Key Bindings
|
* Key Bindings
|
||||||
Quick way to start and jump to my IRC world.
|
Quick way to start and jump to my IRC world.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-irc-persp-start ()
|
(defun ha-irc-persp-start ()
|
||||||
"Create an IRC workspace and start my IRC client."
|
"Create an IRC workspace and start my IRC client."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -110,46 +109,46 @@ Quick way to start and jump to my IRC world.
|
||||||
(interactive)
|
(interactive)
|
||||||
(persp-switch "irc")
|
(persp-switch "irc")
|
||||||
(call-interactively 'erc-track-switch-buffer))
|
(call-interactively 'erc-track-switch-buffer))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And some global keys to display them:
|
And some global keys to display them:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader
|
(ha-leader
|
||||||
"a i" '("irc switch" . ha-irc-persp-switch)
|
"a i" '("irc switch" . ha-irc-persp-switch)
|
||||||
"a I" '("irc start" . ha-irc-persp-start))
|
"a I" '("irc start" . ha-irc-persp-start))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let's create a leader for this mode:
|
Let's create a leader for this mode:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(general-create-definer ha-irc-leader
|
(general-create-definer ha-irc-leader
|
||||||
:states '(normal visual motion)
|
:states '(normal visual motion)
|
||||||
:keymaps '(erc-mode-map)
|
:keymaps '(erc-mode-map)
|
||||||
:prefix "SPC m"
|
:prefix "SPC m"
|
||||||
:global-prefix "<f17>"
|
:global-prefix "<f17>"
|
||||||
:non-normal-prefix "S-SPC")
|
:non-normal-prefix "S-SPC")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And a quick shortcut to call it:
|
And a quick shortcut to call it:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-irc-leader
|
(ha-irc-leader
|
||||||
"o" '("next channel" . erc-track-switch-buffer)
|
"o" '("next channel" . erc-track-switch-buffer)
|
||||||
"w" '("resize text" . ha-erc-resize-text)
|
"w" '("resize text" . ha-erc-resize-text)
|
||||||
"r" '("reconnect" . ha-erc-connect-irc)
|
"r" '("reconnect" . ha-erc-connect-irc)
|
||||||
"p" '("send password" . ha-erc-reconnect-password))
|
"p" '("send password" . ha-erc-reconnect-password))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Display Configuration
|
* Display Configuration
|
||||||
Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications:
|
Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq doom-modeline-irc t
|
(setq doom-modeline-irc t
|
||||||
doom-modeline-irc-stylize 'identity)
|
doom-modeline-irc-stylize 'identity)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
This will =provide= a code name, so that we can =require= this.
|
This will =provide= a code name, so that we can =require= this.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-irc)
|
(provide 'ha-irc)
|
||||||
;;; ha-irc.el ends here
|
;;; ha-irc.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: A literate programming configuration file for IRC.
|
#+DESCRIPTION: A literate programming configuration file for IRC.
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Pasting the Org Clipboard
|
#+TITLE: Pasting the Org Clipboard
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-09-15
|
#+DATE: 2020-09-15
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file of functions for formatting the clipboard.
|
A literate programming file of functions for formatting the clipboard.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; org-clipboard --- Functions for formatting the clipboard. -*- lexical-binding: t; -*-
|
;;; org-clipboard --- Functions for formatting the clipboard. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,7 +22,7 @@ A literate programming file of functions for formatting the clipboard.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
I would like to paste the formatted contents of the clipboard into an Org file /as org-formatted text/.
|
I would like to paste the formatted contents of the clipboard into an Org file /as org-formatted text/.
|
||||||
* The Clipboard
|
* The Clipboard
|
||||||
|
@ -32,18 +31,18 @@ Functions to help convert content from the operating system's clipboard into org
|
||||||
|
|
||||||
Each operating system as a different way of working with the clipboard, so let's create an operating-system abstraction:
|
Each operating system as a different way of working with the clipboard, so let's create an operating-system abstraction:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-get-clipboard ()
|
(defun ha-get-clipboard ()
|
||||||
"Returns a list where the first entry is the content type,
|
"Returns a list where the first entry is the content type,
|
||||||
either :html or :text, and the second is the clipboard contents."
|
either :html or :text, and the second is the clipboard contents."
|
||||||
(if (ha-running-on-macos?)
|
(if (ha-running-on-macos?)
|
||||||
(ha-get-mac-clipboard)
|
(ha-get-mac-clipboard)
|
||||||
(ha-get-linux-clipboard)))
|
(ha-get-linux-clipboard)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let's define the clipboard for a Mac. The challenge here is that we need to binary unpack the data from a call to Applescript.
|
Let's define the clipboard for a Mac. The challenge here is that we need to binary unpack the data from a call to Applescript.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-get-mac-clipboard ()
|
(defun ha-get-mac-clipboard ()
|
||||||
"Returns a list where the first entry is the content type,
|
"Returns a list where the first entry is the content type,
|
||||||
either :html or :text, and the second is the clipboard contents."
|
either :html or :text, and the second is the clipboard contents."
|
||||||
|
@ -65,11 +64,11 @@ Let's define the clipboard for a Mac. The challenge here is that we need to bina
|
||||||
(mapcar #'hex-pack-bytes))))
|
(mapcar #'hex-pack-bytes))))
|
||||||
(decode-coding-string
|
(decode-coding-string
|
||||||
(mapconcat #'byte-to-string byte-seq "") 'utf-8))))
|
(mapconcat #'byte-to-string byte-seq "") 'utf-8))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And define the same interface for Linux. Keep in mind, we need the exit code from calling a process, so I am going to define/use a helper function (that really should go into the piper project).
|
And define the same interface for Linux. Keep in mind, we need the exit code from calling a process, so I am going to define/use a helper function (that really should go into the piper project).
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-get-linux-clipboard ()
|
(defun ha-get-linux-clipboard ()
|
||||||
"Return the clipbaard for a Unix-based system. See `ha-get-clipboard'."
|
"Return the clipbaard for a Unix-based system. See `ha-get-clipboard'."
|
||||||
(cl-destructuring-bind (exit-code contents)
|
(cl-destructuring-bind (exit-code contents)
|
||||||
|
@ -83,13 +82,13 @@ And define the same interface for Linux. Keep in mind, we need the exit code fro
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(list (apply 'call-process program nil (current-buffer) nil args)
|
(list (apply 'call-process program nil (current-buffer) nil args)
|
||||||
(buffer-string))))
|
(buffer-string))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Converting from Slack
|
* Converting from Slack
|
||||||
|
|
||||||
We can assume that most non-HTML text could be Slack-like:
|
We can assume that most non-HTML text could be Slack-like:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-slack-to-markdown-buffer ()
|
(defun ha-slack-to-markdown-buffer ()
|
||||||
"Odd function that converts Slack’s version of Markdown (where
|
"Odd function that converts Slack’s version of Markdown (where
|
||||||
code is delimited with triple backticks) into a more formal
|
code is delimited with triple backticks) into a more formal
|
||||||
|
@ -116,23 +115,23 @@ four-space indent markdown style."
|
||||||
(next-line)
|
(next-line)
|
||||||
(beginning-of-line)
|
(beginning-of-line)
|
||||||
(insert " ")))))))
|
(insert " ")))))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Converting to Org
|
* Converting to Org
|
||||||
|
|
||||||
Let's work top-down at this point with the interactive function that inserts the clipboard into the current buffer:
|
Let's work top-down at this point with the interactive function that inserts the clipboard into the current buffer:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-yank-clipboard ()
|
(defun ha-org-yank-clipboard ()
|
||||||
"Yanks (pastes) the contents of the Apple Mac clipboard in an
|
"Yanks (pastes) the contents of the Apple Mac clipboard in an
|
||||||
org-mode-compatible format."
|
org-mode-compatible format."
|
||||||
(interactive)
|
(interactive)
|
||||||
(insert (ha-org-clipboard)))
|
(insert (ha-org-clipboard)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The heavy lifting, however is done by this function. Note that I will need another function to tidy up the output from =pandoc= that will be more to my liking.
|
The heavy lifting, however is done by this function. Note that I will need another function to tidy up the output from =pandoc= that will be more to my liking.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-clipboard ()
|
(defun ha-org-clipboard ()
|
||||||
"Return the contents of the clipboard in org-mode format."
|
"Return the contents of the clipboard in org-mode format."
|
||||||
(seq-let (type contents) (ha-get-clipboard)
|
(seq-let (type contents) (ha-get-clipboard)
|
||||||
|
@ -161,22 +160,22 @@ The heavy lifting, however is done by this function. Note that I will need anoth
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(while (re-search-forward search nil t)
|
(while (re-search-forward search nil t)
|
||||||
(replace-match replace)))))
|
(replace-match replace)))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Keybinding to Paste into Org Files
|
* Keybinding to Paste into Org Files
|
||||||
We just need to bind it to the /local/ mode key sequence:
|
We just need to bind it to the /local/ mode key sequence:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(with-eval-after-load 'ha-org
|
(with-eval-after-load 'ha-org
|
||||||
(ha-org-leader "y" 'ha-org-yank-clipboard))
|
(ha-org-leader "y" 'ha-org-yank-clipboard))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's provide a name so we can =require= this file:
|
Let's provide a name so we can =require= this file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(provide 'ha-org-clipboard)
|
(provide 'ha-org-clipboard)
|
||||||
;;; ha-org-clipboard.el ends here
|
;;; ha-org-clipboard.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: A literate programming version of functions for formatting the clipboard.
|
#+DESCRIPTION: A literate programming version of functions for formatting the clipboard.
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
A literate programming configuration file for extending the Journaling capabilities.
|
A literate programming configuration file for extending the Journaling capabilities.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; org-journaling --- Configuring journals in org. -*- lexical-binding: t; -*-
|
;;; org-journaling --- Configuring journals in org. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
|
@ -23,11 +23,11 @@ A literate programming configuration file for extending the Journaling capabilit
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
Using the [[https://github.com/bastibe/org-journal][org-journal]] project to easily create /daily/ journal entries:
|
Using the [[https://github.com/bastibe/org-journal][org-journal]] project to easily create /daily/ journal entries:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-journal
|
(use-package org-journal
|
||||||
:init
|
:init
|
||||||
(setq org-journal-dir "~/journal"
|
(setq org-journal-dir "~/journal"
|
||||||
|
@ -36,45 +36,45 @@ Using the [[https://github.com/bastibe/org-journal][org-journal]] project to eas
|
||||||
org-journal-file-type 'daily
|
org-journal-file-type 'daily
|
||||||
org-journal-file-format "%Y%m%d")
|
org-journal-file-format "%Y%m%d")
|
||||||
:config
|
:config
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Notice that the rest of this file's contents is /contained/ in this =config= section!
|
Notice that the rest of this file's contents is /contained/ in this =config= section!
|
||||||
|
|
||||||
And let's put a /leader key/ sequence for it (Doom-specific):
|
And let's put a /leader key/ sequence for it (Doom-specific):
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "f j" '("journal" . org-journal-new-entry))
|
(ha-leader "f j" '("journal" . org-journal-new-entry))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
In normal Org file, I like large headers, but in my Journal, where each task is a header, I want them smaller:
|
In normal Org file, I like large headers, but in my Journal, where each task is a header, I want them smaller:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-hook 'org-journal-mode-hook
|
(add-hook 'org-journal-mode-hook
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(set-face-attribute 'org-level-1 nil :height 1.2)
|
(set-face-attribute 'org-level-1 nil :height 1.2)
|
||||||
(set-face-attribute 'org-level-2 nil :height 1.1)
|
(set-face-attribute 'org-level-2 nil :height 1.1)
|
||||||
(set-face-attribute 'org-level-3 nil :height 1.0)))
|
(set-face-attribute 'org-level-3 nil :height 1.0)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
But new files could use /my formatting/ (which is different than the options available in the project):
|
But new files could use /my formatting/ (which is different than the options available in the project):
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-auto-insert-file (rx "journal/" (zero-or-more any) (= 8 digit)) "journal")
|
(ha-auto-insert-file (rx "journal/" (zero-or-more any) (= 8 digit)) "journal")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
This depends on the following [[file:~/.doom.d/snippets/org-journal-mode/__journal][snippet/template file]]:
|
This depends on the following [[file:~/.doom.d/snippets/org-journal-mode/__journal][snippet/template file]]:
|
||||||
|
|
||||||
#+BEGIN_SRC snippet :tangle ~/other/hamacs/templates/journal
|
#+begin_src snippet :tangle ~/other/hamacs/templates/journal
|
||||||
#+TITLE: Journal Entry- `(ha-journal-file-datestamp)`
|
#+TITLE: Journal Entry- `(ha-journal-file-datestamp)`
|
||||||
|
|
||||||
$0
|
$0
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Note that when I create a new journal entry, I want a title that should insert a date to match the file's name, not necessarily the current date (see below).
|
Note that when I create a new journal entry, I want a title that should insert a date to match the file's name, not necessarily the current date (see below).
|
||||||
* Journal Filename to Date
|
* Journal Filename to Date
|
||||||
Since the Journal's filename represents a date, I should be able to get the "date" associated with a file.
|
Since the Journal's filename represents a date, I should be able to get the "date" associated with a file.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-journal-file-date (&optional datename)
|
(defun ha-journal-file-date (&optional datename)
|
||||||
"Returns a Lisp date-timestamp based on the format of the current filename,
|
"Returns a Lisp date-timestamp based on the format of the current filename,
|
||||||
or DATENAME if given."
|
or DATENAME if given."
|
||||||
|
@ -89,24 +89,24 @@ or DATENAME if given."
|
||||||
(month (string-to-number (match-string 2 datename)))
|
(month (string-to-number (match-string 2 datename)))
|
||||||
(year(string-to-number (match-string 1 datename))))
|
(year(string-to-number (match-string 1 datename))))
|
||||||
(encode-time 0 0 0 day month year)))
|
(encode-time 0 0 0 day month year)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Using the "date" associated with a file, we can create our standard timestamp:
|
Using the "date" associated with a file, we can create our standard timestamp:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-journal-file-datestamp (&optional datename)
|
(defun ha-journal-file-datestamp (&optional datename)
|
||||||
"Return a string of the buffer's date (based on the file's name)."
|
"Return a string of the buffer's date (based on the file's name)."
|
||||||
(format-time-string "%e %b %Y (%A)" (ha-journal-file-date datename)))
|
(format-time-string "%e %b %Y (%A)" (ha-journal-file-date datename)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Close the =use-package= call:
|
Close the =use-package= call:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
)
|
)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Journal Capture
|
* Journal Capture
|
||||||
Capturing a task (that when uncompleted, would then spillover to following days) could go to the daily journal entry. This requires a special function that opens today's journal, but specifies a non-nil prefix argument in order to inhibit inserting the heading, as =org-capture= will insert the heading.
|
Capturing a task (that when uncompleted, would then spillover to following days) could go to the daily journal entry. This requires a special function that opens today's journal, but specifies a non-nil prefix argument in order to inhibit inserting the heading, as =org-capture= will insert the heading.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun org-journal-find-location ()
|
(defun org-journal-find-location ()
|
||||||
(org-journal-new-entry t)
|
(org-journal-new-entry t)
|
||||||
(org-narrow-to-subtree)
|
(org-narrow-to-subtree)
|
||||||
|
@ -118,11 +118,11 @@ Capturing a task (that when uncompleted, would then spillover to following days)
|
||||||
(function org-journal-find-location)
|
(function org-journal-find-location)
|
||||||
"* %?\n\n %i\n\n From: %a"
|
"* %?\n\n %i\n\n From: %a"
|
||||||
:empty-lines 1 :jump-to-captured t :immediate-finish t))
|
:empty-lines 1 :jump-to-captured t :immediate-finish t))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Next and Previous File
|
* Next and Previous File
|
||||||
Sometimes it is obvious what is the /next file/ based on the one I'm currently reading. For instance, in my journal entries, the filename is a number that can be incremented. Same with presentation files...
|
Sometimes it is obvious what is the /next file/ based on the one I'm currently reading. For instance, in my journal entries, the filename is a number that can be incremented. Same with presentation files...
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun split-string-with-number (string)
|
(defun split-string-with-number (string)
|
||||||
"Returns a list of three components of the string, the first is
|
"Returns a list of three components of the string, the first is
|
||||||
the text prior to any numbers, the second is the embedded number,
|
the text prior to any numbers, the second is the embedded number,
|
||||||
|
@ -133,22 +133,22 @@ Sometimes it is obvious what is the /next file/ based on the one I'm currently r
|
||||||
(list (substring string 0 start)
|
(list (substring string 0 start)
|
||||||
(substring string start end)
|
(substring string start end)
|
||||||
(if end (substring string end) "")))))
|
(if end (substring string end) "")))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Which means that the following defines this function:
|
Which means that the following defines this function:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(ert-deftest split-string-with-number-test ()
|
(ert-deftest split-string-with-number-test ()
|
||||||
(should (equal (split-string-with-number "abc42xyz") '("abc" "42" "xyz")))
|
(should (equal (split-string-with-number "abc42xyz") '("abc" "42" "xyz")))
|
||||||
(should (equal (split-string-with-number "42xyz") '("" "42" "xyz")))
|
(should (equal (split-string-with-number "42xyz") '("" "42" "xyz")))
|
||||||
(should (equal (split-string-with-number "abc42") '("abc" "42" "")))
|
(should (equal (split-string-with-number "abc42") '("abc" "42" "")))
|
||||||
(should (equal (split-string-with-number "20140424") '("" "20140424" "")))
|
(should (equal (split-string-with-number "20140424") '("" "20140424" "")))
|
||||||
(should (null (split-string-with-number "abcxyz"))))
|
(should (null (split-string-with-number "abcxyz"))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Given this splitter function, we create a function that takes some sort of operator and return a new filename based on the conversion that happens:
|
Given this splitter function, we create a function that takes some sort of operator and return a new filename based on the conversion that happens:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun find-file-number-change (f)
|
(defun find-file-number-change (f)
|
||||||
(let* ((filename (buffer-file-name))
|
(let* ((filename (buffer-file-name))
|
||||||
(parts (split-string-with-number
|
(parts (split-string-with-number
|
||||||
|
@ -159,11 +159,11 @@ Given this splitter function, we create a function that takes some sort of opera
|
||||||
(nth 0 parts)
|
(nth 0 parts)
|
||||||
new-name
|
new-name
|
||||||
(nth 2 parts))))
|
(nth 2 parts))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And this allows us to create two simple functions that can load the "next" and "previous" files:
|
And this allows us to create two simple functions that can load the "next" and "previous" files:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun find-file-increment ()
|
(defun find-file-increment ()
|
||||||
"Takes the current buffer, and loads the file that is 'one
|
"Takes the current buffer, and loads the file that is 'one
|
||||||
more' than the file contained in the current buffer. This
|
more' than the file contained in the current buffer. This
|
||||||
|
@ -171,9 +171,9 @@ And this allows us to create two simple functions that can load the "next" and "
|
||||||
incremented."
|
incremented."
|
||||||
(interactive)
|
(interactive)
|
||||||
(find-file (find-file-number-change '1+)))
|
(find-file (find-file-number-change '1+)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun find-file-decrement ()
|
(defun find-file-decrement ()
|
||||||
"Takes the current buffer, and loads the file that is 'one
|
"Takes the current buffer, and loads the file that is 'one
|
||||||
less' than the file contained in the current buffer. This
|
less' than the file contained in the current buffer. This
|
||||||
|
@ -181,14 +181,14 @@ And this allows us to create two simple functions that can load the "next" and "
|
||||||
decremented."
|
decremented."
|
||||||
(interactive)
|
(interactive)
|
||||||
(find-file (find-file-number-change '1-)))
|
(find-file (find-file-number-change '1-)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's =provide= a name so we can =require= this file.
|
Let's =provide= a name so we can =require= this file.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-org-journaling)
|
(provide 'ha-org-journaling)
|
||||||
;;; ha-org-journaling.el ends here
|
;;; ha-org-journaling.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Publishing my Website with Org
|
#+TITLE: Publishing my Website with Org
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-12-22
|
#+DATE: 2020-12-22
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file for publishing my website using org.
|
A literate programming file for publishing my website using org.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; org-publishing --- Publishing my website using org. -*- lexical-binding: t; -*-
|
;;; org-publishing --- Publishing my website using org. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,24 +22,24 @@ A literate programming file for publishing my website using org.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
While the Emacs community have a plethora of options for generating a static website from org-formatted files, I keep my pretty simple, and just use the standard =org-publish= feature.
|
While the Emacs community have a plethora of options for generating a static website from org-formatted files, I keep my pretty simple, and use the standard =org-publish= feature.
|
||||||
|
|
||||||
While the following packages come with Emacs, they aren't necessarily loaded:
|
While the following packages come with Emacs, they aren't necessarily loaded:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :results silent
|
#+begin_src emacs-lisp :results silent
|
||||||
(require 'ox-rss)
|
(require 'ox-rss)
|
||||||
(require 'ox-publish)
|
(require 'ox-publish)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Variable settings:
|
Variable settings:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq org-export-with-broken-links t
|
(setq org-export-with-broken-links t
|
||||||
org-mode-websrc-directory "/Volumes/Personal/dropbox/website"
|
org-mode-websrc-directory "/Volumes/Personal/dropbox/website"
|
||||||
org-mode-publishing-directory (concat (getenv "HOME") "/website-public/"))
|
org-mode-publishing-directory (concat (getenv "HOME") "/website-public/"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* The Projects
|
* The Projects
|
||||||
I separate my /website/ into distinct projects separately built:
|
I separate my /website/ into distinct projects separately built:
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@ I separate my /website/ into distinct projects separately built:
|
||||||
- =blog-rss= :: Regenerate the feeder files
|
- =blog-rss= :: Regenerate the feeder files
|
||||||
- =org-notes= :: Optionally render a non-web site collection of notes.
|
- =org-notes= :: Optionally render a non-web site collection of notes.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq org-publish-project-alist
|
(setq org-publish-project-alist
|
||||||
`(("all"
|
`(("all"
|
||||||
:components ("blog-content" "blog-static" "org-notes" "blog-rss"))
|
:components ("blog-content" "blog-static" "org-notes" "blog-rss"))
|
||||||
|
@ -134,11 +133,11 @@ I separate my /website/ into distinct projects separately built:
|
||||||
:publishing-directory ,(concat org-mode-publishing-directory "/other/")
|
:publishing-directory ,(concat org-mode-publishing-directory "/other/")
|
||||||
:recursive t
|
:recursive t
|
||||||
:publishing-function org-publish-attachment)))
|
:publishing-function org-publish-attachment)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Including Sections
|
* Including Sections
|
||||||
In the project definitions, I reference a =pre-= and =postamble= that allow me to inject some standard HTML file headers and footers:
|
In the project definitions, I reference a =pre-= and =postamble= that allow me to inject some standard HTML file headers and footers:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun org-mode-blog-preamble (options)
|
(defun org-mode-blog-preamble (options)
|
||||||
"The function that creates the preamble top section for the blog.
|
"The function that creates the preamble top section for the blog.
|
||||||
OPTIONS contains the property list from the org-mode export."
|
OPTIONS contains the property list from the org-mode export."
|
||||||
|
@ -151,10 +150,10 @@ In the project definitions, I reference a =pre-= and =postamble= that allow me t
|
||||||
OPTIONS contains the property list from the org-mode export."
|
OPTIONS contains the property list from the org-mode export."
|
||||||
(let ((base-directory (plist-get options :base-directory)))
|
(let ((base-directory (plist-get options :base-directory)))
|
||||||
(org-babel-with-temp-filebuffer (expand-file-name "bottom.html" base-directory) (buffer-string))))
|
(org-babel-with-temp-filebuffer (expand-file-name "bottom.html" base-directory) (buffer-string))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Another helper function for the content of website is to make sure to update =index.org=, so that the RSS gets generated.
|
Another helper function for the content of website is to make sure to update =index.org=, so that the RSS gets generated.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun org-mode-blog-prepare (&optional options)
|
(defun org-mode-blog-prepare (&optional options)
|
||||||
"`index.org' should always be exported so touch the file before publishing."
|
"`index.org' should always be exported so touch the file before publishing."
|
||||||
(let* ((base-directory (plist-get options :base-directory))
|
(let* ((base-directory (plist-get options :base-directory))
|
||||||
|
@ -163,31 +162,31 @@ Another helper function for the content of website is to make sure to update =in
|
||||||
(set-buffer-modified-p t)
|
(set-buffer-modified-p t)
|
||||||
(save-buffer 0))
|
(save-buffer 0))
|
||||||
(kill-buffer buffer)))
|
(kill-buffer buffer)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Keybindings
|
* Keybindings
|
||||||
Make it easy to publish all or just some of my website:
|
Make it easy to publish all or just some of my website:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(with-eval-after-load 'ha-org
|
(with-eval-after-load 'ha-org
|
||||||
(ha-org-leader
|
(ha-org-leader
|
||||||
"p" '(:ignore t :which-key "publishing")
|
"p" '(:ignore t :which-key "publishing")
|
||||||
"p a" '("all" . org-publish-all)
|
"p a" '("all" . org-publish-all)
|
||||||
"p p" '("project" . org-publish-project)))
|
"p p" '("project" . org-publish-project)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And let's put a /leader key/ sequence for my favorite file on my website:
|
And let's put a /leader key/ sequence for my favorite file on my website:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader
|
(ha-leader
|
||||||
"f h" '(:ignore t :which-key "howards")
|
"f h" '(:ignore t :which-key "howards")
|
||||||
"f h i" '("website index" . (lambda ()
|
"f h i" '("website index" . (lambda ()
|
||||||
(find-file (expand-file-name "index.org" "~/website")))))
|
(find-file (expand-file-name "index.org" "~/website")))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's =provide= a name so we can =require= it:
|
Let's =provide= a name so we can =require= it:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-org-publishing)
|
(provide 'ha-org-publishing)
|
||||||
;;; ha-org-publishing.el ends here
|
;;; ha-org-publishing.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: My Sprint Calculations and Support
|
#+TITLE: My Sprint Calculations and Support
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-09-25
|
#+DATE: 2020-09-25
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate program for configuring org files for work-related notes.
|
A literate program for configuring org files for work-related notes.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; org-sprint --- Configuring org files for work-related notes. -*- lexical-binding: t; -*-
|
;;; org-sprint --- Configuring org files for work-related notes. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,34 +22,32 @@ A literate program for configuring org files for work-related notes.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Introduction
|
* Introduction
|
||||||
|
|
||||||
At the beginning of each Sprint, I create a new org file dedicated to it. This workflow/technique strikes a balance between a single ever-growing file, and a thousand tiny ones. This also gives me a sense of continuity, as the filename of each sprint is date-based.
|
At the beginning of each Sprint, I create a new org file dedicated to it. This workflow/technique strikes a balance between a single ever-growing file, and a thousand little ones. This also gives me a sense of continuity, as the filename of each sprint is date-based.
|
||||||
|
|
||||||
I want a single keybinding that always displays the current Sprint note file, regardless of what Sprint it is. This means, I need to have functions that can calculate what this is.
|
I want a single keybinding that always displays the current Sprint note file, regardless of the Sprint. This means, I need to have functions that can calculate what this is.
|
||||||
|
|
||||||
In order to have the Org Capture features to be able to write to correct locations in the current file, I need each file to follow a particular format. I create a [[file:snippets/org-mode/__sprint.org][sprint note template]] that will be automatically expanded with a new sprint.
|
To have the Org Capture features to be able to write to correct locations in the current file, I need each file to follow a particular format. I create a [[file:snippets/org-mode/__sprint.org][sprint note template]] that will be automatically expanded with a new sprint.
|
||||||
|
|
||||||
This template needs the following functions:
|
This template needs the following functions:
|
||||||
|
|
||||||
- =sprint-current-name= to be both the numeric label as well as the nickname
|
- =sprint-current-name= to be both the numeric label as well as the nickname
|
||||||
- =sprint-date-range= to include a org-formatted date range beginning and ending the sprint
|
- =sprint-date-range= to include a org-formatted date range beginning and ending the sprint
|
||||||
- =sprint-date-from-start= return a date for pre-scheduled and recurring meetings
|
- =sprint-date-from-start= return a date for pre-scheduled and recurring meetings
|
||||||
|
|
||||||
* Naming Sprints
|
* Naming Sprints
|
||||||
|
|
||||||
I give each sprint a nickname, based on a /theme/ of some sorts, alphabetized. Since our sprints are every two weeks, this allows me to go through the alphabet once. Yeah, my group likes to boringly /number/ the sprints, so I do both...mostly for myself.
|
I give each sprint a nickname, based on a /theme/ of some sorts, alphabetized. Since our sprints are every two weeks, this allows me to go through the alphabet once. Yeah, my group likes to boringly /number/ the sprints, so I do both… for myself.
|
||||||
|
|
||||||
At the beginning of the year, I choose a theme, and make a list for the upcoming sprints. In the org file, this is just a list, that gets /tangled/ into an actual Emacs LIsp list. This is pretty cool.
|
At the beginning of the year, I choose a theme, and make a list for the upcoming sprints. In the org file, this is a list, that gets /tangled/ into an actual Emacs LIsp list. This is pretty cool.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :noweb yes
|
#+begin_src emacs-lisp :noweb yes
|
||||||
(defvar sprint-nicknames
|
(defvar sprint-nicknames
|
||||||
(--map (replace-regexp-in-string " *[:#].*" "" (first it))
|
(--map (replace-regexp-in-string " *[:#].*" "" (first it))
|
||||||
'<<sprint-names-2022()>>)
|
'<<sprint-names-2022()>>)
|
||||||
"List of 26 Sprint Nicknames from A to Z.")
|
"List of 26 Sprint Nicknames from A to Z.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** 2022
|
** 2022
|
||||||
|
|
||||||
Fun sprint names for 2022 lists my favorite D&D monsters, also see [[https://list.fandom.com/wiki/List_of_monsters][this list of monsters]] from mythology and other sources:
|
Fun sprint names for 2022 lists my favorite D&D monsters, also see [[https://list.fandom.com/wiki/List_of_monsters][this list of monsters]] from mythology and other sources:
|
||||||
|
@ -177,14 +174,13 @@ Came up with a list of somewhat well-known cities throughout the world (at least
|
||||||
- zippy-zinder
|
- zippy-zinder
|
||||||
|
|
||||||
* Sprint Boundaries
|
* Sprint Boundaries
|
||||||
Function to help in calculating dates and other features of a two-week sprint that starts on Thursday and ends on a Wednesday...hey, that is just how we do things at my job.
|
Function to help in calculating dates and other features of a two-week sprint that starts on Thursday and ends on a Wednesday… how we work at my job.
|
||||||
|
|
||||||
Emacs have an internal rep of a time.
|
Emacs have an internal rep of a time.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defun get-date-time (date)
|
(defun get-date-time (date)
|
||||||
"Many functions can't deal with dates as string, so this will
|
"My functions can't deal with dates as string, so this will
|
||||||
parse DATE if it is a string, or return the value given otherwise."
|
parse DATE as a string, or return the value given otherwise."
|
||||||
(if (and date (stringp date))
|
(if (and date (stringp date))
|
||||||
(->> date ; Shame that encode-time
|
(->> date ; Shame that encode-time
|
||||||
parse-time-string ; can't take a string, as
|
parse-time-string ; can't take a string, as
|
||||||
|
@ -192,19 +188,17 @@ parse DATE if it is a string, or return the value given otherwise."
|
||||||
(--map (if (null it) 0 it))
|
(--map (if (null it) 0 it))
|
||||||
(apply 'encode-time))
|
(apply 'encode-time))
|
||||||
date))
|
date))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Sprint Numbering
|
** Sprint Numbering
|
||||||
|
|
||||||
My Sprint starts on Thursday, but this sometimes changed, so let's make this a variable:
|
My Sprint starts on Thursday, but this sometimes changed, so let's make this a variable:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defvar sprint-starting-day 2 "The day of the week the sprint begins, where 0 is Sunday.")
|
(defvar sprint-starting-day 2 "The day of the week the sprint begins, where 0 is Sunday.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
We label our sprint based on the week number that it starts. However, on a Monday, I want to consider that we are still numbering from last week.
|
We label our sprint based on the week number that it starts. Note that on a Monday, I want to consider that we are still numbering from last week.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defun sprint-week-num (&optional date)
|
(defun sprint-week-num (&optional date)
|
||||||
"Return the week of the current year (or DATE), but starting
|
"Return the week of the current year (or DATE), but starting
|
||||||
the week at Thursday to Wednesday."
|
the week at Thursday to Wednesday."
|
||||||
|
@ -216,22 +210,20 @@ the week at Thursday to Wednesday."
|
||||||
(if (>= dow sprint-starting-day)
|
(if (>= dow sprint-starting-day)
|
||||||
(1+ week)
|
(1+ week)
|
||||||
week)))
|
week)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let's have a few tests to make sure, and yeah, perhaps we update this at the beginning of each year.
|
Let's have these tests to make sure, and yeah, perhaps we update this at the beginning of each year.
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
|
||||||
(ert-deftest sprint-week-num-test ()
|
(ert-deftest sprint-week-num-test ()
|
||||||
(should (= (sprint-week-num "2021-03-15") 11)) ;; Monday previous week
|
(should (= (sprint-week-num "2021-03-15") 11)) ;; Monday previous week
|
||||||
(should (= (sprint-week-num "2021-03-16") 12)) ;; Tuesday current week
|
(should (= (sprint-week-num "2021-03-16") 12)) ;; Tuesday current week
|
||||||
(should (= (sprint-week-num "2021-03-19") 12)))
|
(should (= (sprint-week-num "2021-03-19") 12)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Since my sprints are currently two weeks long, we could be see that on even week numbers, the /sprint/ is actually the previous week's number.
|
My company has sprints two weeks long, we could be see that on even week numbers, the /sprint/ is actually the previous week's number.
|
||||||
|
|
||||||
And it appears that my PM for this year, is a week number behind.
|
And it appears that my PM for this year, is a week number behind.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defun sprint-number (&optional date)
|
(defun sprint-number (&optional date)
|
||||||
"Return the current sprint number, with some assumptions that
|
"Return the current sprint number, with some assumptions that
|
||||||
each sprint is two weeks long, starting on Thursday."
|
each sprint is two weeks long, starting on Thursday."
|
||||||
|
@ -240,11 +232,11 @@ each sprint is two weeks long, starting on Thursday."
|
||||||
(if (cl-oddp num)
|
(if (cl-oddp num)
|
||||||
(- num 2)
|
(- num 2)
|
||||||
(- num 1))))
|
(- num 1))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And some tests to verify that:
|
And some tests to verify that:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(ert-deftest sprint-number-test ()
|
(ert-deftest sprint-number-test ()
|
||||||
(should (= (sprint-number "2021-03-15") 9))
|
(should (= (sprint-number "2021-03-15") 9))
|
||||||
(should (= (sprint-number "2021-03-16") 11))
|
(should (= (sprint-number "2021-03-16") 11))
|
||||||
|
@ -252,12 +244,10 @@ And some tests to verify that:
|
||||||
(should (= (sprint-number "2021-03-23") 11))
|
(should (= (sprint-number "2021-03-23") 11))
|
||||||
(should (= (sprint-number "2021-03-29") 11))
|
(should (= (sprint-number "2021-03-29") 11))
|
||||||
(should (= (sprint-number "2021-03-30") 13)))
|
(should (= (sprint-number "2021-03-30") 13)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Sprint File Name
|
** Sprint File Name
|
||||||
|
|
||||||
I create my org-file notes based on the Sprint number.
|
I create my org-file notes based on the Sprint number.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defun sprint-current-file (&optional date)
|
(defun sprint-current-file (&optional date)
|
||||||
"Return the absolute pathname to the current sprint file."
|
"Return the absolute pathname to the current sprint file."
|
||||||
(let ((d (get-date-time date)))
|
(let ((d (get-date-time date)))
|
||||||
|
@ -265,11 +255,10 @@ I create my org-file notes based on the Sprint number.
|
||||||
(format "~/Notes/Sprint-%s-%02d.org"
|
(format "~/Notes/Sprint-%s-%02d.org"
|
||||||
(format-time-string "%Y" d)
|
(format-time-string "%Y" d)
|
||||||
(sprint-number d)))))
|
(sprint-number d)))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
So what that means, is given a particular date, I should expect to be able to find the correct Sprint file name:
|
So given a particular date, I should expect to be able to find the correct Sprint file name:
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
|
||||||
(ert-deftest sprint-current-file-test ()
|
(ert-deftest sprint-current-file-test ()
|
||||||
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-07")))
|
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-07")))
|
||||||
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-09")))
|
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-09")))
|
||||||
|
@ -277,11 +266,11 @@ So what that means, is given a particular date, I should expect to be able to fi
|
||||||
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-13")))
|
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-13")))
|
||||||
(should (s-ends-with? "Sprint-2019-07.org" (sprint-current-file "2019-02-14")))
|
(should (s-ends-with? "Sprint-2019-07.org" (sprint-current-file "2019-02-14")))
|
||||||
(should (s-ends-with? "Sprint-2019-07.org" (sprint-current-file "2019-02-17"))))
|
(should (s-ends-with? "Sprint-2019-07.org" (sprint-current-file "2019-02-17"))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Daily note-taking goes into my sprint file notes, so this interactive function makes an easy global short-cut key.
|
Daily note-taking goes into my sprint file notes, so this interactive function makes an easy global short-cut key.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun sprint-current-find-file (&optional date)
|
(defun sprint-current-find-file (&optional date)
|
||||||
"Load the `org-mode' note associated with my current sprint."
|
"Load the `org-mode' note associated with my current sprint."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -290,11 +279,11 @@ Daily note-taking goes into my sprint file notes, so this interactive function m
|
||||||
org-annotate-file-storage-file filename)
|
org-annotate-file-storage-file filename)
|
||||||
(add-to-list 'org-agenda-files filename)
|
(add-to-list 'org-agenda-files filename)
|
||||||
(find-file filename)))
|
(find-file filename)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The /name/ and /nickname/ of the sprint will be used in the =#+TITLE= section, and it looks something like: =Sprint 2019-07 (darling-dadu)=
|
The /name/ and /nickname/ of the sprint will be used in the =#+TITLE= section, and it looks something like: =Sprint 2019-07 (darling-dadu)=
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun sprint-current-name (&optional date)
|
(defun sprint-current-name (&optional date)
|
||||||
"Return the default name of the current sprint (based on DATE)."
|
"Return the default name of the current sprint (based on DATE)."
|
||||||
(let* ((d (get-date-time date))
|
(let* ((d (get-date-time date))
|
||||||
|
@ -304,21 +293,21 @@ The /name/ and /nickname/ of the sprint will be used in the =#+TITLE= section, a
|
||||||
(format-time-string "%Y" d)
|
(format-time-string "%Y" d)
|
||||||
(sprint-number d)
|
(sprint-number d)
|
||||||
nickname)))
|
nickname)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
These test won't pass any more, as the nickname of the sprint changes from year to year.
|
These test won't pass any more, as the nickname of the sprint changes from year to year.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(ert-deftest sprint-current-name-test ()
|
(ert-deftest sprint-current-name-test ()
|
||||||
(should (equal "Sprint 2019-05 (candid-cannes)" (sprint-current-name "2019-02-13")))
|
(should (equal "Sprint 2019-05 (candid-cannes)" (sprint-current-name "2019-02-13")))
|
||||||
(should (equal "Sprint 2019-07 (darling-dadu)" (sprint-current-name "2019-02-14"))))
|
(should (equal "Sprint 2019-07 (darling-dadu)" (sprint-current-name "2019-02-14"))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Sprint Start and End
|
** Sprint Start and End
|
||||||
|
|
||||||
I want to print the beginning and ending of the sprint, where we have a sprint number or a data, and we can give the dates that bound the sprint. This odd function calculates this based on knowing the date of the /first thursday/ of the year, so I need to begin the year changing this value. I should fix this.
|
I want to print the beginning and ending of the sprint, where we have a sprint number or a data, and we can give the dates that bound the sprint. This odd function calculates this based on knowing the date of the /first thursday/ of the year, so I need to begin the year changing this value. I should fix this.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun sprint-range (&optional number-or-date)
|
(defun sprint-range (&optional number-or-date)
|
||||||
"Return a list of three entries, start of the current sprint,
|
"Return a list of three entries, start of the current sprint,
|
||||||
end of the current sprint, and the start of the next sprint.
|
end of the current sprint, and the start of the next sprint.
|
||||||
|
@ -336,11 +325,11 @@ Each date value should be formatted with `format-time-string'."
|
||||||
(sprint-next (time-add time-start (* week-length (1+ num))))
|
(sprint-next (time-add time-start (* week-length (1+ num))))
|
||||||
(sprint-end (time-add sprint-next (- day-length))))
|
(sprint-end (time-add sprint-next (- day-length))))
|
||||||
(list sprint-start sprint-end sprint-next)))
|
(list sprint-start sprint-end sprint-next)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Format the start and end so that we can insert this directly in the org file:
|
Format the start and end so that we can insert this directly in the org file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun sprint-date-range (&optional number-or-date)
|
(defun sprint-date-range (&optional number-or-date)
|
||||||
"Return an `org-mode' formatted date range for a given sprint
|
"Return an `org-mode' formatted date range for a given sprint
|
||||||
number or date, `NUMBER-OR-DATE' or if `nil', the date range of
|
number or date, `NUMBER-OR-DATE' or if `nil', the date range of
|
||||||
|
@ -350,21 +339,20 @@ the current sprint."
|
||||||
(start (format-time-string formatter sprint-start))
|
(start (format-time-string formatter sprint-start))
|
||||||
(end (format-time-string formatter sprint-end)))
|
(end (format-time-string formatter sprint-end)))
|
||||||
(format "[%s]--[%s]" start end))))
|
(format "[%s]--[%s]" start end))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And let's have a test to validate this:
|
And validate with a test:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(ert-deftest sprint-date-range ()
|
(ert-deftest sprint-date-range ()
|
||||||
(should (equal (sprint-date-range 7)
|
(should (equal (sprint-date-range 7)
|
||||||
(sprint-date-range "2020-02-17"))))
|
(sprint-date-range "2020-02-17"))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Pre-scheduled Dates
|
** Pre-scheduled Dates
|
||||||
|
|
||||||
Due to the regularity of the sprint cadence, I can pre-schedule meetings and other deadlines by /counting/ the number of days from the start of the sprint:
|
Due to the regularity of the sprint cadence, I can pre-schedule meetings and other deadlines by /counting/ the number of days from the start of the sprint:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun sprint-date-from-start (days &optional formatter)
|
(defun sprint-date-from-start (days &optional formatter)
|
||||||
"Given a number of DAYS from the start of the sprint, return a formatted date string."
|
"Given a number of DAYS from the start of the sprint, return a formatted date string."
|
||||||
(let* ((day-length (* 3600 24))
|
(let* ((day-length (* 3600 24))
|
||||||
|
@ -373,20 +361,20 @@ Due to the regularity of the sprint cadence, I can pre-schedule meetings and oth
|
||||||
(if formatter
|
(if formatter
|
||||||
(format-time-string formatter adate)
|
(format-time-string formatter adate)
|
||||||
(format-time-string "%Y-%m-%d %a" adate))))
|
(format-time-string "%Y-%m-%d %a" adate))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Other Date Functions
|
* Other Date Functions
|
||||||
|
|
||||||
The following functions /were/ helpful at times. But I'm not sure I will use them.
|
The following functions /were/ helpful at times. But I'm not sure I will use them.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(defun sprint-num-days (time-interval)
|
(defun sprint-num-days (time-interval)
|
||||||
"Converts a TIME-INTERVAL to a number of days."
|
"Converts a TIME-INTERVAL to a number of days."
|
||||||
(let ((day-length (* 3600 24)))
|
(let ((day-length (* 3600 24)))
|
||||||
(round (/ (float-time time-interval) day-length))))
|
(round (/ (float-time time-interval) day-length))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(defun sprint-day-range (&optional date)
|
(defun sprint-day-range (&optional date)
|
||||||
"Returns a list of two values, the number of days from the
|
"Returns a list of two values, the number of days from the
|
||||||
start of the sprint, and the number of days to the end of the
|
start of the sprint, and the number of days to the end of the
|
||||||
|
@ -396,17 +384,17 @@ sprint based on DATE if given, or from today if DATE is `nil'."
|
||||||
(starting (time-subtract sprint-start now))
|
(starting (time-subtract sprint-start now))
|
||||||
(ending (time-subtract sprint-end now)))
|
(ending (time-subtract sprint-end now)))
|
||||||
(list (sprint-num-days starting) (sprint-num-days ending)))))
|
(list (sprint-num-days starting) (sprint-num-days ending)))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(ert-deftest sprint-day-range ()
|
(ert-deftest sprint-day-range ()
|
||||||
;; This sprint starts on 2/13 and ends on 2/26
|
;; This sprint starts on 2/13 and ends on 2/26
|
||||||
(should (equal '(0 13) (sprint-day-range "2020-02-13")))
|
(should (equal '(0 13) (sprint-day-range "2020-02-13")))
|
||||||
(should (equal '(-1 12) (sprint-day-range "2020-02-14")))
|
(should (equal '(-1 12) (sprint-day-range "2020-02-14")))
|
||||||
(should (equal '(-13 0) (sprint-day-range "2020-02-26"))))
|
(should (equal '(-13 0) (sprint-day-range "2020-02-26"))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(defun sprint-day-start (&optional date)
|
(defun sprint-day-start (&optional date)
|
||||||
"Return a relative number of days to the start of the current sprint. For instance, if today was Friday, and the sprint started on Thursday, this would return -1."
|
"Return a relative number of days to the start of the current sprint. For instance, if today was Friday, and the sprint started on Thursday, this would return -1."
|
||||||
(first (sprint-day-range date)))
|
(first (sprint-day-range date)))
|
||||||
|
@ -414,16 +402,15 @@ sprint based on DATE if given, or from today if DATE is `nil'."
|
||||||
(defun sprint-day-end (&optional date)
|
(defun sprint-day-end (&optional date)
|
||||||
"Return a relative number of days to the end of the current sprint. For instance, if today was Monday, and the sprint will end on Wednesday, this would return 3."
|
"Return a relative number of days to the end of the current sprint. For instance, if today was Monday, and the sprint will end on Wednesday, this would return 3."
|
||||||
(second (sprint-day-range date)))
|
(second (sprint-day-range date)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
|
|
||||||
Let's provide a name so that the file can be required:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
#+begin_src emacs-lisp :exports none
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
|
||||||
(provide 'ha-org-sprint)
|
(provide 'ha-org-sprint)
|
||||||
;;; ha-org-sprint.el ends here
|
;;; ha-org-sprint.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
|
|
||||||
A literate programming file for making Org file more readable.
|
A literate programming file for making Org file more readable.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-org-word-processor --- Making Org file more readable. -*- lexical-binding: t; -*-
|
;;; ha-org-word-processor --- Making Org file more readable. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,13 +23,13 @@ A literate programming file for making Org file more readable.
|
||||||
;; Using `find-file-at-point', and tangle the file to recreate this one .
|
;; Using `find-file-at-point', and tangle the file to recreate this one .
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
I like having org-mode files look more like a word processor than having it look like programming code. But that is just me.
|
I like having org-mode files look more like a word processor than having it look like programming code. But that is me.
|
||||||
* General Org Settings
|
* General Org Settings
|
||||||
Since I use ellipsis in my writing… to /change/ how org renders a collapsed heading.
|
Since I use ellipsis in my writing… to /change/ how org renders a collapsed heading.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq org-pretty-entities t
|
(setq org-pretty-entities t
|
||||||
org-ellipsis "⤵" ; …, ➡, ⚡, ▼, ↴, , ∞, ⬎, ⤷, ⤵
|
org-ellipsis "⤵" ; …, ➡, ⚡, ▼, ↴, , ∞, ⬎, ⤷, ⤵
|
||||||
org-agenda-breadcrumbs-separator " ❱ "
|
org-agenda-breadcrumbs-separator " ❱ "
|
||||||
|
@ -37,24 +37,24 @@ Since I use ellipsis in my writing… to /change/ how org renders a collapsed he
|
||||||
org-special-ctrl-a/e t ; Note: Need to get this working with Evil!
|
org-special-ctrl-a/e t ; Note: Need to get this working with Evil!
|
||||||
org-src-fontify-natively t ; Pretty code blocks
|
org-src-fontify-natively t ; Pretty code blocks
|
||||||
org-hide-emphasis-markers t)
|
org-hide-emphasis-markers t)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Oh, and as I indent lists, they should change the /bulleting/ in a particular sequence. If I begin with an =*= asterisk, I walk down the chain, but with the dashed bullets (my default choice), I just stay with dashed bullets. Numeric bullets should cycle:
|
Oh, and as I indent lists, they should change the /bulleting/ in a particular sequence. If I begin with an =*= asterisk, I walk down the chain, but with the dashed bullets (my default choice), I stay with dashed bullets. Numeric bullets should cycle:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq org-list-demote-modify-bullet '(("*" . "+") ("+" . "-") ("-" . "-")
|
(setq org-list-demote-modify-bullet '(("*" . "+") ("+" . "-") ("-" . "-")
|
||||||
("1." . "a.") ("a." . "1.")))
|
("1." . "a.") ("a." . "1.")))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The =org-indent-indentation-per-level=, which defaults to =2= doesn’t really work well with variable-width fonts, so let’s make the spaces at the beginning of the line fixed:
|
The =org-indent-indentation-per-level=, which defaults to =2= doesn’t really work well with variable-width fonts, so let’s make the spaces at the beginning of the line fixed:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org
|
(use-package org
|
||||||
:custom-face (org-indent ((t (:inherit fixed-pitch)))))
|
:custom-face (org-indent ((t (:inherit fixed-pitch)))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Typographic Quotes
|
** Typographic Quotes
|
||||||
According to [[http://endlessparentheses.com/prettify-your-quotation-marks.html][Artur Malabarba]] of [[http://endlessparentheses.com/prettify-you-apostrophes.html][Endless Parenthesis]] blog, I type either a /straight single or double quote/, ", Emacs actually inserts Unicode rounded quotes, like “this”. This idea isn’t how a file is /displayed/, but actually how the file is /made/. Time will tell if this idea works with my auxiliary functions on my phone, like [[https://play.google.com/store/apps/details?id=com.orgzly&hl=en_US&gl=US][Orgzly]] and [[https://github.com/amake/orgro][Orgro]].
|
According to [[http://endlessparentheses.com/prettify-your-quotation-marks.html][Artur Malabarba]] of [[http://endlessparentheses.com/prettify-you-apostrophes.html][Endless Parenthesis]] blog, I type either a /straight single or double quote/, ", Emacs actually inserts Unicode rounded quotes, like “this”. This idea isn’t how a file is /displayed/, but actually how the file is /made/. Time will tell if this idea works with my auxiliary functions on my phone, like [[https://play.google.com/store/apps/details?id=com.orgzly&hl=en_US&gl=US][Orgzly]] and [[https://github.com/amake/orgro][Orgro]].
|
||||||
|
|
||||||
Stealing his function, and updating it a bit, so that “quotes” just work to insert /rounded/ quotation marks:
|
Stealing his function, and updating it a bit, so that “quotes” work to insert /rounded/ quotation marks:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha--insert-round-quotes (opening closing)
|
(defun ha--insert-round-quotes (opening closing)
|
||||||
"Insert rounded quotes in prose but not inside code.
|
"Insert rounded quotes in prose but not inside code.
|
||||||
The OPENING and CLOSING variables are either or .
|
The OPENING and CLOSING variables are either or .
|
||||||
|
@ -93,11 +93,11 @@ Stealing his function, and updating it a bit, so that “quotes” just work to
|
||||||
((looking-back starting-anew) (insert-pair))
|
((looking-back starting-anew) (insert-pair))
|
||||||
((looking-at existing-endq) (goto-char (match-end 0)))
|
((looking-at existing-endq) (goto-char (match-end 0)))
|
||||||
(t (insert closing)))))))
|
(t (insert closing)))))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Now we can take advantage of the abstraction for “double quotes”:
|
Now we can take advantage of the abstraction for “double quotes”:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-round-quotes ()
|
(defun ha-round-quotes ()
|
||||||
"Insert “” and leave point in the middle.
|
"Insert “” and leave point in the middle.
|
||||||
Inside a code-block, just call `self-insert-command'.
|
Inside a code-block, just call `self-insert-command'.
|
||||||
|
@ -106,11 +106,11 @@ Now we can take advantage of the abstraction for “double quotes”:
|
||||||
(ha--insert-round-quotes "“" "”"))
|
(ha--insert-round-quotes "“" "”"))
|
||||||
|
|
||||||
(define-key org-mode-map "\"" #'ha-round-quotes)
|
(define-key org-mode-map "\"" #'ha-round-quotes)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And something similar for single quotes:
|
And something similar for single quotes:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-apostrophe ()
|
(defun ha-apostrophe ()
|
||||||
"Insert ‘’ and leave point in the middle.
|
"Insert ‘’ and leave point in the middle.
|
||||||
Inside a code-block, just call `self-insert-command'.
|
Inside a code-block, just call `self-insert-command'.
|
||||||
|
@ -119,13 +119,13 @@ And something similar for single quotes:
|
||||||
(ha--insert-round-quotes "‘" "’"))
|
(ha--insert-round-quotes "‘" "’"))
|
||||||
|
|
||||||
(define-key org-mode-map "'" #'ha-apostrophe)
|
(define-key org-mode-map "'" #'ha-apostrophe)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
*Note:* I still need to worry about how quotes affect [[file:ha-org.org::*Spell Checking][spell checking]].
|
*Note:* I still need to worry about how quotes affect [[file:ha-org.org::*Spell Checking][spell checking]].
|
||||||
|
|
||||||
What would be nice, is that if I end quotes using the functions above, that if I immediately delete, I delete both pairs.
|
What would be nice, is that if I end quotes using the functions above, that if I immediately delete, I delete both pairs.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-delete-quote-pairs (&optional N)
|
(defun ha-delete-quote-pairs (&optional N)
|
||||||
"If positioned between two quote symbols, delete the last.
|
"If positioned between two quote symbols, delete the last.
|
||||||
Used as advice to `org-delete-backward-char' function."
|
Used as advice to `org-delete-backward-char' function."
|
||||||
|
@ -135,10 +135,10 @@ What would be nice, is that if I end quotes using the functions above, that if I
|
||||||
|
|
||||||
(advice-add #'org-delete-backward-char :before #'ha-delete-quote-pairs)
|
(advice-add #'org-delete-backward-char :before #'ha-delete-quote-pairs)
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Can we do the same with ellipses?
|
Can we do the same with ellipses?
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-insert-dot-or-ellipsis ()
|
(defun ha-insert-dot-or-ellipsis ()
|
||||||
"Insert a `.' unless two have already be inserted.
|
"Insert a `.' unless two have already be inserted.
|
||||||
In this case, insert an ellipsis instead."
|
In this case, insert an ellipsis instead."
|
||||||
|
@ -156,10 +156,10 @@ Can we do the same with ellipses?
|
||||||
(define-key org-mode-map "." #'ha-insert-dot-or-ellipsis)
|
(define-key org-mode-map "." #'ha-insert-dot-or-ellipsis)
|
||||||
|
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Now I’m getting obsessive with elongating dashes:
|
Now I’m getting obsessive with elongating dashes:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-insert-long-dash ()
|
(defun ha-insert-long-dash ()
|
||||||
"Insert a `.' unless two have already be inserted.
|
"Insert a `.' unless two have already be inserted.
|
||||||
In this case, insert an ellipsis instead."
|
In this case, insert an ellipsis instead."
|
||||||
|
@ -179,32 +179,32 @@ Now I’m getting obsessive with elongating dashes:
|
||||||
(t (insert "-")))))
|
(t (insert "-")))))
|
||||||
|
|
||||||
(define-key org-mode-map "-" #'ha-insert-long-dash)
|
(define-key org-mode-map "-" #'ha-insert-long-dash)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Org Beautify
|
* Org Beautify
|
||||||
I really want to use the Org Beautify package, but it overrides my darker themes (and all I really want is headlines to behave).
|
I really want to use the Org Beautify package, but it overrides my darker themes (and all I really want is headlines to behave).
|
||||||
|
|
||||||
First step is to make all Org header levels to use the variable font, and be the same color as the default text:
|
First step is to make all Org header levels to use the variable font, and be the same color as the default text:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when window-system
|
(when window-system
|
||||||
(let ((default-color (face-attribute 'default :foreground)))
|
(let ((default-color (face-attribute 'default :foreground)))
|
||||||
(dolist (face '(org-level-1 org-level-2 org-level-3 org-level-4 org-level-5 org-level-6 org-level-7 org-level-8))
|
(dolist (face '(org-level-1 org-level-2 org-level-3 org-level-4 org-level-5 org-level-6 org-level-7 org-level-8))
|
||||||
(set-face-attribute face nil :height 1.1
|
(set-face-attribute face nil :height 1.1
|
||||||
:foreground default-color :weight 'bold :font ha-variable-font))))
|
:foreground default-color :weight 'bold :font ha-variable-font))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Next, we just need to change the header sizes:
|
Next, we just need to change the header sizes:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when window-system
|
(when window-system
|
||||||
(set-face-attribute 'org-level-1 nil :height 2.2)
|
(set-face-attribute 'org-level-1 nil :height 2.2)
|
||||||
(set-face-attribute 'org-level-2 nil :height 1.8)
|
(set-face-attribute 'org-level-2 nil :height 1.8)
|
||||||
(set-face-attribute 'org-level-3 nil :height 1.4)
|
(set-face-attribute 'org-level-3 nil :height 1.4)
|
||||||
(set-face-attribute 'org-level-4 nil :height 1.2))
|
(set-face-attribute 'org-level-4 nil :height 1.2))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
While we are at it, let’s make sure the code blocks are using my fixed with font:
|
While we are at it, let’s make sure the code blocks are using my fixed with font:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when window-system
|
(when window-system
|
||||||
(dolist (face '(org-block org-code org-verbatim org-table org-drawer
|
(dolist (face '(org-block org-code org-verbatim org-table org-drawer
|
||||||
org-table org-formula org-special-keyword org-block
|
org-table org-formula org-special-keyword org-block
|
||||||
|
@ -214,28 +214,28 @@ While we are at it, let’s make sure the code blocks are using my fixed with fo
|
||||||
(set-face-attribute 'org-table nil :height 1.0)
|
(set-face-attribute 'org-table nil :height 1.0)
|
||||||
(set-face-attribute 'org-formula nil :height 1.0)
|
(set-face-attribute 'org-formula nil :height 1.0)
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Not sure why the above code removes the color of =org-verbatim=, so let’s make it stand out slightly:
|
Not sure why the above code removes the color of =org-verbatim=, so let’s make it stand out slightly:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(set-face-attribute 'org-verbatim nil :foreground "#aaaacc")
|
(set-face-attribute 'org-verbatim nil :foreground "#aaaacc")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And some slight adjustments to the way blocks are displayed:
|
And some slight adjustments to the way blocks are displayed:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(set-face-attribute 'org-block-begin-line nil :background "#282828")
|
(set-face-attribute 'org-block-begin-line nil :background "#282828")
|
||||||
(set-face-attribute 'org-block nil :height 0.95)
|
(set-face-attribute 'org-block nil :height 0.95)
|
||||||
(set-face-attribute 'org-block-end-line nil :background "#262626")
|
(set-face-attribute 'org-block-end-line nil :background "#262626")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And decrease the prominence of the property drawers:
|
And decrease the prominence of the property drawers:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(set-face-attribute 'org-drawer nil :height 0.8)
|
(set-face-attribute 'org-drawer nil :height 0.8)
|
||||||
(set-face-attribute 'org-property-value nil :height 0.85)
|
(set-face-attribute 'org-property-value nil :height 0.85)
|
||||||
(set-face-attribute 'org-special-keyword nil :height 0.85)
|
(set-face-attribute 'org-special-keyword nil :height 0.85)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
This process allows us to use =variable-pitch= mode for all org documents.
|
This process allows us to use =variable-pitch= mode for all org documents.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org
|
(use-package org
|
||||||
:hook (org-mode . variable-pitch-mode))
|
:hook (org-mode . variable-pitch-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Org Modern
|
* Org Modern
|
||||||
The [[https://github.com/minad/org-modern][org-modern]] project attempts to do a lot of what I was doing in this file.
|
The [[https://github.com/minad/org-modern][org-modern]] project attempts to do a lot of what I was doing in this file.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
|
@ -247,8 +247,8 @@ The [[https://github.com/minad/org-modern][org-modern]] project attempts to do a
|
||||||
#+end_src
|
#+end_src
|
||||||
I like the smaller code blocks as well as the <2022-06-16 Thu> timestamps.
|
I like the smaller code blocks as well as the <2022-06-16 Thu> timestamps.
|
||||||
* Checkboxes
|
* Checkboxes
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
According to an idea by [[https://jft.home.blog/2019/07/17/use-unicode-symbol-to-display-org-mode-checkboxes/][Huy Trần]], (and expanded by the [[https://github.com/minad/org-modern][org-modern]] project), we can prettify the list checkboxes. To make completed tasks more distinguishable, he changed the colors:
|
According to an idea by [[https://jft.home.blog/2019/07/17/use-unicode-symbol-to-display-org-mode-checkboxes/][Huy Trần]], (and expanded by the [[https://github.com/minad/org-modern][org-modern]] project), we can prettify the list checkboxes. To make completed tasks more distinguishable, he changed the colors:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
(defface org-checkbox-done-text
|
(defface org-checkbox-done-text
|
||||||
'((t (:foreground "#71696A" :strike-through t)))
|
'((t (:foreground "#71696A" :strike-through t)))
|
||||||
"Face for the text part of a checked org-mode checkbox.")
|
"Face for the text part of a checked org-mode checkbox.")
|
||||||
|
@ -297,20 +297,12 @@ However, I'm just going to have to write a function to clean this.
|
||||||
bol (zero-or-more space) "#+END" (zero-or-more any) eol "\n")
|
bol (zero-or-more space) "#+END" (zero-or-more any) eol "\n")
|
||||||
(optional bol (zero-or-more space) eol "\n")) nil t)
|
(optional bol (zero-or-more space) eol "\n")) nil t)
|
||||||
(replace-match (match-string 1) nil :no-error)))
|
(replace-match (match-string 1) nil :no-error)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Now that is some complicated regular expressions.
|
Now that is some complicated regular expressions.
|
||||||
* Pasting
|
|
||||||
I like the idea that I will paste HTML text from the clipboard and have it converted to org-formatted text:
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defun ha-org-paste ()
|
|
||||||
(interactive)
|
|
||||||
(if (eq system-type 'gnu/linux)
|
|
||||||
(shell-command "xclip -t text/html -o | pandoc -r html -w org" t)))
|
|
||||||
#+END_SRC
|
|
||||||
* Presentations
|
* Presentations
|
||||||
Used to use [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for showing org files as presentations. Converted to use [[https://github.com/rlister/org-present][org-present]]. I love the /hooks/ as that makes it easier to pull out much of my =demo-it= configuration. My concern with =org-present= is that it only jumps from one top-level to another top-level header.
|
Used to use [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for showing org files as presentations. Converted to use [[https://github.com/rlister/org-present][org-present]]. I love the /hooks/ as that makes it easier to pull out much of my =demo-it= configuration. My concern with =org-present= is that it only jumps from one top-level to another top-level header.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-present
|
(use-package org-present
|
||||||
:init
|
:init
|
||||||
(defvar ha-org-present-mode-line mode-line-format "Cache previous mode-line format state")
|
(defvar ha-org-present-mode-line mode-line-format "Cache previous mode-line format state")
|
||||||
|
@ -368,13 +360,42 @@ Used to use [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for sho
|
||||||
:hook
|
:hook
|
||||||
(org-present-mode . org-present-start)
|
(org-present-mode . org-present-start)
|
||||||
(org-present-mode-quit . org-present-end))
|
(org-present-mode-quit . org-present-end))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's provide a name so that the file can be required:
|
Note, according to [[https://www.reddit.com/r/emacs/comments/vahsao/orgmode_use_capitalized_property_keywords_or/][this discussion]] (and especially [[https://scripter.co/org-keywords-lower-case/][this essay]]), I’m switching over to lower-case version of org properties. Using this helper function:
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp
|
||||||
#+END_SRC
|
(defun modi/lower-case-org-keywords ()
|
||||||
|
"Lower case Org keywords and block identifiers.
|
||||||
|
|
||||||
|
Example: \"#+TITLE\" -> \"#+title\"
|
||||||
|
\"#+BEGIN_EXAMPLE\" -> \"#+begin_example\"
|
||||||
|
|
||||||
|
Inspiration:
|
||||||
|
https://code.orgmode.org/bzg/org-mode/commit/13424336a6f30c50952d291e7a82906c1210daf0."
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(let ((case-fold-search nil)
|
||||||
|
(count 0)
|
||||||
|
;; All keywords can be found with this expression:
|
||||||
|
;; (org-keyword-re "\\(?1:#\\+[A-Z_]+\\(?:_[[:alpha:]]+\\)*\\)\\(?:[ :=~’”]\\|$\\)")
|
||||||
|
;; Match examples: "#+foo bar", "#+foo:", "=#+foo=", "~#+foo~",
|
||||||
|
;; "‘#+foo’", "“#+foo”", ",#+foo bar",
|
||||||
|
;; "#+FOO_bar<eol>", "#+FOO<eol>".
|
||||||
|
;;
|
||||||
|
;; Perhap I want the #+begin_src and whatnot:
|
||||||
|
(org-keyword-re (rx line-start (optional (zero-or-more space))
|
||||||
|
"#+" (group (or "BEGIN" "END") "_" (one-or-more alpha)))))
|
||||||
|
(while (re-search-forward org-keyword-re nil :noerror)
|
||||||
|
(setq count (1+ count))
|
||||||
|
(replace-match (downcase (match-string-no-properties 1)) :fixedcase nil nil 1))
|
||||||
|
(message "Lower-cased %d matches" count))))
|
||||||
|
#+end_src
|
||||||
|
Let's provide a name so we can =require= this file:
|
||||||
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-org-word-processor)
|
(provide 'ha-org-word-processor)
|
||||||
;;; ha-org-word-processor.el ends here
|
;;; ha-org-word-processor.el ends here
|
||||||
|
#+end_src
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
#+DESCRIPTION: A literate programming file for making Org file more readable.
|
#+DESCRIPTION: A literate programming file for making Org file more readable.
|
||||||
|
|
253
ha-org.org
253
ha-org.org
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: General Org-Mode Configuration
|
#+TITLE: General Org-Mode Configuration
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-09-18
|
#+DATE: 2020-09-18
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file for configuring org-mode and those files.
|
A literate programming file for configuring org-mode and those files.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha --- Org configuration. -*- lexical-binding: t; -*-
|
;;; ha --- Org configuration. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -24,10 +23,10 @@ A literate programming file for configuring org-mode and those files.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Use Package
|
* Use Package
|
||||||
Org is a /large/ complex beast with a gazillion settings, so I discuss these later in this document.
|
Org is a /large/ complex beast with a gazillion settings, so I discuss these later in this document.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org
|
(use-package org
|
||||||
:mode ("\\.org" . org-mode) ; Addresses an odd warning
|
:mode ("\\.org" . org-mode) ; Addresses an odd warning
|
||||||
:init
|
:init
|
||||||
|
@ -47,22 +46,22 @@ Org is a /large/ complex beast with a gazillion settings, so I discuss these lat
|
||||||
<<org-return-key>>
|
<<org-return-key>>
|
||||||
<<global-keybindings>>
|
<<global-keybindings>>
|
||||||
<<org-keybindings>>)
|
<<org-keybindings>>)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
One other helper routine is a =general= macro for org-mode files:
|
One other helper routine is a =general= macro for org-mode files:
|
||||||
#+NAME: ha-org-leader
|
#+name: ha-org-leader
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(general-create-definer ha-org-leader
|
(general-create-definer ha-org-leader
|
||||||
:states '(normal visual motion)
|
:states '(normal visual motion)
|
||||||
:keymaps 'org-mode-map
|
:keymaps 'org-mode-map
|
||||||
:prefix "SPC m"
|
:prefix "SPC m"
|
||||||
:global-prefix "<f17>"
|
:global-prefix "<f17>"
|
||||||
:non-normal-prefix "S-SPC")
|
:non-normal-prefix "S-SPC")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Initialization Section
|
* Initialization Section
|
||||||
Begin by initializing these org variables:
|
Begin by initializing these org variables:
|
||||||
#+NAME: variables
|
#+name: variables
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(setq org-return-follows-link t
|
(setq org-return-follows-link t
|
||||||
org-adapt-indentation nil ; Don't physically change files
|
org-adapt-indentation nil ; Don't physically change files
|
||||||
org-startup-indented t ; Visually show paragraphs indented
|
org-startup-indented t ; Visually show paragraphs indented
|
||||||
|
@ -90,28 +89,28 @@ Begin by initializing these org variables:
|
||||||
org-confirm-babel-evaluate nil
|
org-confirm-babel-evaluate nil
|
||||||
org-src-fontify-natively t
|
org-src-fontify-natively t
|
||||||
org-src-tab-acts-natively t)
|
org-src-tab-acts-natively t)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Configuration Section
|
* Configuration Section
|
||||||
I pretend that my org files are word processing files that wrap automatically:
|
I pretend that my org files are word processing files that wrap automatically:
|
||||||
#+NAME: visual-hook
|
#+name: visual-hook
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(add-hook 'org-mode-hook #'visual-line-mode)
|
(add-hook 'org-mode-hook #'visual-line-mode)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Files that end in =.txt= are still org files to me:
|
Files that end in =.txt= are still org files to me:
|
||||||
#+NAME: text-files
|
#+name: text-files
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(add-to-list 'auto-mode-alist '("\\.txt\\'" . org-mode))
|
(add-to-list 'auto-mode-alist '("\\.txt\\'" . org-mode))
|
||||||
|
|
||||||
(add-to-list 'safe-local-variable-values '(org-content . 2))
|
(add-to-list 'safe-local-variable-values '(org-content . 2))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*Note:* Org mode files with the =org-content= variable setting will collapse two levels headers. Let's allow that without the need to approve that.
|
*Note:* Org mode files with the =org-content= variable setting will collapse two levels headers. Let's allow that without the need to approve that.
|
||||||
** Better Return
|
** Better Return
|
||||||
Hitting the ~Return~ key in an org file should format the following line based on context. For instance, at the end of a list, insert a new item.
|
Hitting the ~Return~ key in an org file should format the following line based on context. For instance, at the end of a list, insert a new item.
|
||||||
We begin with the interactive function that calls our code if we are at the end of the line.
|
We begin with the interactive function that calls our code if we are at the end of the line.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-return ()
|
(defun ha-org-return ()
|
||||||
"If at the end of a line, do something special based on the
|
"If at the end of a line, do something special based on the
|
||||||
information about the line by calling `ha-org-special-return',
|
information about the line by calling `ha-org-special-return',
|
||||||
|
@ -120,13 +119,13 @@ We begin with the interactive function that calls our code if we are at the end
|
||||||
(if (eolp)
|
(if (eolp)
|
||||||
(ha-org-special-return)
|
(ha-org-special-return)
|
||||||
(org-return)))
|
(org-return)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And bind it to the Return key:
|
And bind it to the Return key:
|
||||||
#+NAME: org-return-key
|
#+name: org-return-key
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(define-key org-mode-map (kbd "RET") #'ha-org-return)
|
(define-key org-mode-map (kbd "RET") #'ha-org-return)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
What should we do if we are at the end of a line?
|
What should we do if we are at the end of a line?
|
||||||
- Given a prefix, call =org-return= as usual in an org file.
|
- Given a prefix, call =org-return= as usual in an org file.
|
||||||
|
@ -137,7 +136,7 @@ What should we do if we are at the end of a line?
|
||||||
|
|
||||||
I should break this function into smaller bits ...
|
I should break this function into smaller bits ...
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-special-return (&optional ignore)
|
(defun ha-org-special-return (&optional ignore)
|
||||||
"Add new list item, heading or table row with RET.
|
"Add new list item, heading or table row with RET.
|
||||||
A double return on an empty element deletes it.
|
A double return on an empty element deletes it.
|
||||||
|
@ -177,11 +176,11 @@ I should break this function into smaller bits ...
|
||||||
|
|
||||||
(t
|
(t
|
||||||
(org-return)))))
|
(org-return)))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
How do we know if we are in a list item? 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 one blank line.
|
How do we know if we are in a list item? 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 one blank line.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun org-really-in-item-p ()
|
(defun org-really-in-item-p ()
|
||||||
"Return item beginning position when in a plain list, nil otherwise.
|
"Return item beginning position when in a plain list, nil otherwise.
|
||||||
Unlike `org-in-item-p', this works around an issue where the
|
Unlike `org-in-item-p', this works around an issue where the
|
||||||
|
@ -192,30 +191,30 @@ How do we know if we are in a list item? Lists end with two blank lines, so we n
|
||||||
(when location
|
(when location
|
||||||
(goto-char location))
|
(goto-char location))
|
||||||
(org-in-item-p))))
|
(org-in-item-p))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The org API allows getting the context associated with the /current element/. This could be a line-level symbol, like paragraph or =list-item=, but always when the point isn't /inside/ a bold or italics item. You know how HTML distinguishes between /block/ and /inline/ elements, org doesn't. So, let's make a function that makes that distinction:
|
The org API allows getting the context associated with the /current element/. This could be a line-level symbol, like paragraph or =list-item=, but always when the point isn't /inside/ a bold or italics item. You know how HTML distinguishes between /block/ and /inline/ elements, org doesn't. So, let's make a function that makes that distinction:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun org-line-element-context ()
|
(defun org-line-element-context ()
|
||||||
"Return the symbol of the current block element, e.g. paragraph or list-item."
|
"Return the symbol of the current block element, e.g. paragraph or list-item."
|
||||||
(let ((context (org-element-context)))
|
(let ((context (org-element-context)))
|
||||||
(while (member (car context) '(verbatim code bold italic underline))
|
(while (member (car context) '(verbatim code bold italic underline))
|
||||||
(setq context (org-element-property :parent context)))
|
(setq context (org-element-property :parent context)))
|
||||||
context))
|
context))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Tasks
|
** Tasks
|
||||||
I need to add a /blocked/ state:
|
I need to add a /blocked/ state:
|
||||||
|
|
||||||
#+NAME: org-todo
|
#+name: org-todo
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(setq org-todo-keywords '((sequence "TODO(t)" "DOING(g)" "|" "DONE(d)")
|
(setq org-todo-keywords '((sequence "TODO(t)" "DOING(g)" "|" "DONE(d)")
|
||||||
(sequence "BLOCKED(b)" "|" "CANCELLED(c)")))
|
(sequence "BLOCKED(b)" "|" "CANCELLED(c)")))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And I would like to have cute little icons for those states:
|
And I would like to have cute little icons for those states:
|
||||||
|
|
||||||
#+NAME: org-font-lock
|
#+name: org-font-lock
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(dolist (m '(org-mode org-journal-mode))
|
(dolist (m '(org-mode org-journal-mode))
|
||||||
(font-lock-add-keywords m ; A bit silly but my headers are now
|
(font-lock-add-keywords m ; A bit silly but my headers are now
|
||||||
`(("^\\*+ \\(TODO\\) " ; shorter, and that is nice canceled
|
`(("^\\*+ \\(TODO\\) " ; shorter, and that is nice canceled
|
||||||
|
@ -233,11 +232,11 @@ And I would like to have cute little icons for those states:
|
||||||
;; file or the behavior).
|
;; file or the behavior).
|
||||||
("^ +\\([-*]\\) "
|
("^ +\\([-*]\\) "
|
||||||
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))))))
|
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Meetings
|
** Meetings
|
||||||
I've notice that while showing a screen while taking meeting notes, I don't always like showing other windows, so I created this function to remove distractions during a meeting.
|
I've notice that while showing a screen while taking meeting notes, I don't always like showing other windows, so I created this function to remove distractions during a meeting.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun meeting-notes ()
|
(defun meeting-notes ()
|
||||||
"Call this after creating an org-mode heading for where the notes for the meeting
|
"Call this after creating an org-mode heading for where the notes for the meeting
|
||||||
should be. After calling this function, call 'meeting-done' to reset the environment."
|
should be. After calling this function, call 'meeting-done' to reset the environment."
|
||||||
|
@ -249,11 +248,11 @@ I've notice that while showing a screen while taking meeting notes, I don't alwa
|
||||||
(text-scale-set 2) ; readable by others
|
(text-scale-set 2) ; readable by others
|
||||||
(fringe-mode 0)
|
(fringe-mode 0)
|
||||||
(message "When finished taking your notes, run meeting-done."))
|
(message "When finished taking your notes, run meeting-done."))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Of course, I need an 'undo' feature when the meeting is over…
|
Of course, I need an 'undo' feature when the meeting is over…
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun meeting-done ()
|
(defun meeting-done ()
|
||||||
"Attempt to 'undo' the effects of taking meeting notes."
|
"Attempt to 'undo' the effects of taking meeting notes."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -261,10 +260,10 @@ Of course, I need an 'undo' feature when the meeting is over…
|
||||||
(text-scale-set 0) ; Reset the font size increase
|
(text-scale-set 0) ; Reset the font size increase
|
||||||
(fringe-mode 1)
|
(fringe-mode 1)
|
||||||
(winner-undo)) ; Put the windows back in place
|
(winner-undo)) ; Put the windows back in place
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Searching
|
** Searching
|
||||||
Now that my paragraphs in an org file are on a single line, I need this less, but being able to use an /indexed search system/, like [[https://ss64.com/osx/mdfind.html][mdfind]] on Macos, or [[https://www.lesbonscomptes.com/recoll/][recoll]] on Linux, gives better results that line-oriented search systems, like =grep=. Let’s create operating-system functions the command line for searching:
|
Now that my paragraphs in an org file are on a single line, I need this less, but being able to use an /indexed search system/, like [[https://ss64.com/osx/mdfind.html][mdfind]] on Macos, or [[https://www.lesbonscomptes.com/recoll/][recoll]] on Linux, gives better results that line-oriented search systems, like =grep=. Let’s create operating-system functions the command line for searching:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-search-notes--macos (phrase path)
|
(defun ha-search-notes--macos (phrase path)
|
||||||
"Return the indexed search system command on MACOS, mdfind.
|
"Return the indexed search system command on MACOS, mdfind.
|
||||||
Including the parameters using the PHRASE on the PATH(s)."
|
Including the parameters using the PHRASE on the PATH(s)."
|
||||||
|
@ -279,10 +278,10 @@ Now that my paragraphs in an org file are on a single line, I need this less, bu
|
||||||
(format "recoll -t -a -b %s" phrase))
|
(format "recoll -t -a -b %s" phrase))
|
||||||
|
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
This function calls these operating-system functions, but returns the matching files as a /single string/ (where each file is wrapped in single quotes, and all joined together, separated by spaces. This function also allows me to /not-match/ backup files and whatnot.
|
This function calls these operating-system functions, but returns the matching files as a /single string/ (where each file is wrapped in single quotes, and all joined together, separated by spaces. This function also allows me to /not-match/ backup files and whatnot.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-search-notes--files (phrase path)
|
(defun ha-search-notes--files (phrase path)
|
||||||
"Return an escaped string of all files matching PHRASE.
|
"Return an escaped string of all files matching PHRASE.
|
||||||
On a Mac, this search is limited by PATH"
|
On a Mac, this search is limited by PATH"
|
||||||
|
@ -296,11 +295,11 @@ This function calls these operating-system functions, but returns the matching f
|
||||||
(--map (format "'%s'" it))
|
(--map (format "'%s'" it))
|
||||||
(s-join " "))))
|
(s-join " "))))
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The =ha-search-notes= function prompts for the phrase to search, and then searches through the =org-directory= path to acquire the matching files. It then feeds that list to =grep= (and the [[help:grep][grep function]] in order to display a list of matches that I can jump to.
|
The =ha-search-notes= function prompts for the phrase to search, and then searches through the =org-directory= path to acquire the matching files. It then feeds that list to =grep= (and the [[help:grep][grep function]] in order to display a list of matches that I can jump to.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-search-notes (phrase &optional path)
|
(defun ha-search-notes (phrase &optional path)
|
||||||
"Search files in PATH for PHRASE and display in a grep mode buffer."
|
"Search files in PATH for PHRASE and display in a grep mode buffer."
|
||||||
(interactive "sSearch notes for: ")
|
(interactive "sSearch notes for: ")
|
||||||
|
@ -311,33 +310,33 @@ The =ha-search-notes= function prompts for the phrase to search, and then search
|
||||||
(grep (format "%s -ni -m 1 '%s' %s" command regexp files))))
|
(grep (format "%s -ni -m 1 '%s' %s" command regexp files))))
|
||||||
|
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Eventually, I would like to change the output so that the title of the Org mode is displayed instead of the first match, but that is good enough.
|
Eventually, I would like to change the output so that the title of the Org mode is displayed instead of the first match, but that is good enough.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "f n" '("find notes" . ha-search-notes))
|
(ha-leader "f n" '("find notes" . ha-search-notes))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Misc
|
** Misc
|
||||||
*** Babel Blocks
|
*** Babel Blocks
|
||||||
I use [[https://orgmode.org/worg/org-contrib/babel/intro.html][org-babel]] (obviously) and don’t need confirmation before evaluating a block:
|
I use [[https://orgmode.org/worg/org-contrib/babel/intro.html][org-babel]] (obviously) and don’t need confirmation before evaluating a block:
|
||||||
#+NAME: ob-configuration
|
#+name: ob-configuration
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(setq org-confirm-babel-evaluate nil
|
(setq org-confirm-babel-evaluate nil
|
||||||
org-src-fontify-natively t
|
org-src-fontify-natively t
|
||||||
org-src-tab-acts-natively t)
|
org-src-tab-acts-natively t)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Whenever I edit Emacs Lisp blocks from my tangle-able configuration files, I get a lot of superfluous warnings. Let's turn them off.
|
Whenever I edit Emacs Lisp blocks from my tangle-able configuration files, I get a lot of superfluous warnings. Let's turn them off.
|
||||||
#+NAME: no-flycheck-in-org
|
#+name: no-flycheck-in-org
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(defun disable-flycheck-in-org-src-block ()
|
(defun disable-flycheck-in-org-src-block ()
|
||||||
(setq-local flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
|
(setq-local flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
|
||||||
|
|
||||||
(add-hook 'org-src-mode-hook 'disable-flycheck-in-org-src-block)
|
(add-hook 'org-src-mode-hook 'disable-flycheck-in-org-src-block)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And turn on ALL the languages:
|
And turn on ALL the languages:
|
||||||
#+NAME: ob-languages
|
#+name: ob-languages
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(org-babel-do-load-languages 'org-babel-load-languages
|
(org-babel-do-load-languages 'org-babel-load-languages
|
||||||
'((shell . t)
|
'((shell . t)
|
||||||
(js . t)
|
(js . t)
|
||||||
|
@ -348,7 +347,7 @@ And turn on ALL the languages:
|
||||||
(dot . t)
|
(dot . t)
|
||||||
(css . t)
|
(css . t)
|
||||||
(plantuml . t)))
|
(plantuml . t)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** REST Web Services
|
*** REST Web Services
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:header-args: :var user-agent="my-super-agent"
|
:header-args: :var user-agent="my-super-agent"
|
||||||
|
@ -398,13 +397,13 @@ And let’s try this:
|
||||||
|
|
||||||
*** Graphviz
|
*** Graphviz
|
||||||
The [[https://graphviz.org/][graphviz project]] can be written in org blocks, and then rendered as an image:
|
The [[https://graphviz.org/][graphviz project]] can be written in org blocks, and then rendered as an image:
|
||||||
#+NAME: ob-graphviz
|
#+name: ob-graphviz
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(add-to-list 'org-src-lang-modes '("dot" . "graphviz-dot"))
|
(add-to-list 'org-src-lang-modes '("dot" . "graphviz-dot"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
#+BEGIN_SRC dot :file support/ha-org-graphviz-example.png :exports file :results replace file
|
#+begin_src dot :file support/ha-org-graphviz-example.png :exports file :results replace file
|
||||||
digraph G {
|
digraph G {
|
||||||
graph [bgcolor=transparent];
|
graph [bgcolor=transparent];
|
||||||
edge [color=white];
|
edge [color=white];
|
||||||
|
@ -419,25 +418,25 @@ For example:
|
||||||
A -> H;
|
A -> H;
|
||||||
E -> G;
|
E -> G;
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+ATTR_ORG: :width 400px
|
#+attr_org: :width 400px
|
||||||
#+RESULTS:
|
#+results:
|
||||||
[[file:support/ha-org-graphviz-example.png]]
|
[[file:support/ha-org-graphviz-example.png]]
|
||||||
*** PlantUML
|
*** PlantUML
|
||||||
Need to install and configure Emacs to work with [[https://plantuml.com/][PlantUML]]. Granted, this is easier now that [[http://orgmode.org/worg/org-contrib/babel][Org-Babel]] natively supports [[http://eschulte.github.io/babel-dev/DONE-integrate-plantuml-support.html][blocks of plantuml code]]. First, [[https://plantuml.com/download][download the Jar]].
|
Need to install and configure Emacs to work with [[https://plantuml.com/][PlantUML]]. Granted, this is easier now that [[http://orgmode.org/worg/org-contrib/babel][Org-Babel]] natively supports [[http://eschulte.github.io/babel-dev/DONE-integrate-plantuml-support.html][blocks of plantuml code]]. First, [[https://plantuml.com/download][download the Jar]].
|
||||||
|
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
curl -o ~/bin/plantuml.jar https://github.com/plantuml/plantuml/releases/download/v1.2022.4/plantuml-1.2022.4.jar
|
curl -o ~/bin/plantuml.jar https://github.com/plantuml/plantuml/releases/download/v1.2022.4/plantuml-1.2022.4.jar
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
After installing the [[https://github.com/skuro/plantuml-mode][plantuml-mode]], we need to reference the location:
|
After installing the [[https://github.com/skuro/plantuml-mode][plantuml-mode]], we need to reference the location:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package plantuml-mode
|
(use-package plantuml-mode
|
||||||
:straight (:host github :repo "skuro/plantuml-mode")
|
:straight (:host github :repo "skuro/plantuml-mode")
|
||||||
:init
|
:init
|
||||||
(setq org-plantuml-jar-path (expand-file-name "~/bin/plantuml.jar")))
|
(setq org-plantuml-jar-path (expand-file-name "~/bin/plantuml.jar")))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
With some [[file:snippets/org-mode/plantuml][YASnippets]], I have =<p= to start a general diagram, and afterwards (while still in the org-mode file), type one of the following to expand as an example:
|
With some [[file:snippets/org-mode/plantuml][YASnippets]], I have =<p= to start a general diagram, and afterwards (while still in the org-mode file), type one of the following to expand as an example:
|
||||||
- =activity= :: https://plantuml.com/activity-diagram-betastart
|
- =activity= :: https://plantuml.com/activity-diagram-betastart
|
||||||
|
@ -451,12 +450,12 @@ With some [[file:snippets/org-mode/plantuml][YASnippets]], I have =<p= to start
|
||||||
|
|
||||||
You may be wondering how such trivial terms can be used as expansions in an org file. Well, the trick is that each snippets has a =condition= that calls the following predicate function, that make the snippets context aware:
|
You may be wondering how such trivial terms can be used as expansions in an org file. Well, the trick is that each snippets has a =condition= that calls the following predicate function, that make the snippets context aware:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-nested-in-plantuml-block ()
|
(defun ha-org-nested-in-plantuml-block ()
|
||||||
"Predicate is true if point is inside a Plantuml Source code block in org-mode."
|
"Predicate is true if point is inside a Plantuml Source code block in org-mode."
|
||||||
(equal "plantuml"
|
(equal "plantuml"
|
||||||
(plist-get (cadr (org-element-at-point)) :language)))
|
(plist-get (cadr (org-element-at-point)) :language)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Here is a sequence diagram example to show how is looks/works:
|
Here is a sequence diagram example to show how is looks/works:
|
||||||
#+begin_src plantuml :file ha-org-plantuml-example.png :exports file :results file
|
#+begin_src plantuml :file ha-org-plantuml-example.png :exports file :results file
|
||||||
|
@ -471,12 +470,12 @@ Here is a sequence diagram example to show how is looks/works:
|
||||||
@enduml
|
@enduml
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
#+ATTR_ORG: :width 800px
|
#+attr_org: :width 800px
|
||||||
[[file:ha-org-plantuml-example.png]]
|
[[file:ha-org-plantuml-example.png]]
|
||||||
*** Next Image
|
*** Next Image
|
||||||
When I create images or other artifacts that I consider /part/ of the org document, I want to have them based on the org file, but with a prepended number. Keeping track of what numbers are now free is difficult, so for a /default/ let's figure it out:
|
When I create images or other artifacts that I consider /part/ of the org document, I want to have them based on the org file, but with a prepended number. Keeping track of what numbers are now free is difficult, so for a /default/ let's figure it out:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-next-image-number (&optional prefix)
|
(defun ha-org-next-image-number (&optional prefix)
|
||||||
(when (null prefix)
|
(when (null prefix)
|
||||||
(if (null (buffer-file-name))
|
(if (null (buffer-file-name))
|
||||||
|
@ -490,20 +489,20 @@ When I create images or other artifacts that I consider /part/ of the org docume
|
||||||
(while (re-search-forward png-reg nil t)
|
(while (re-search-forward png-reg nil t)
|
||||||
(setq largest (max largest (string-to-number (match-string-no-properties 1)))))
|
(setq largest (max largest (string-to-number (match-string-no-properties 1)))))
|
||||||
(format "%s-%02d" prefix (1+ largest)))))
|
(format "%s-%02d" prefix (1+ largest)))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Keybindings
|
** Keybindings
|
||||||
Global keybindings available to all file buffers:
|
Global keybindings available to all file buffers:
|
||||||
#+NAME: global-keybindings
|
#+name: global-keybindings
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(ha-leader
|
(ha-leader
|
||||||
"o l" '("store link" . org-store-link)
|
"o l" '("store link" . org-store-link)
|
||||||
"o x" '("org capture" . org-capture)
|
"o x" '("org capture" . org-capture)
|
||||||
"o c" '("clock out" . org-clock-out))
|
"o c" '("clock out" . org-clock-out))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Bindings specific to org files:
|
Bindings specific to org files:
|
||||||
#+NAME: org-keybindings
|
#+name: org-keybindings
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(evil-define-key '(normal motion operator visual) org-mode-map "gu" #'org-up-element)
|
(evil-define-key '(normal motion operator visual) org-mode-map "gu" #'org-up-element)
|
||||||
|
|
||||||
(ha-org-leader
|
(ha-org-leader
|
||||||
|
@ -557,27 +556,27 @@ Bindings specific to org files:
|
||||||
"n b" '("block" . org-narrow-to-block)
|
"n b" '("block" . org-narrow-to-block)
|
||||||
"n e" '("element" . org-narrow-to-element)
|
"n e" '("element" . org-narrow-to-element)
|
||||||
"n w" '("widen" . widen))
|
"n w" '("widen" . widen))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Supporting Packages
|
* Supporting Packages
|
||||||
** Exporters
|
** Exporters
|
||||||
Limit the number of exporters to the ones that I would use:
|
Limit the number of exporters to the ones that I would use:
|
||||||
#+NAME: ox-exporters
|
#+name: ox-exporters
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq org-export-backends '(ascii html icalendar md odt))
|
(setq org-export-backends '(ascii html icalendar md odt))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
I have a special version of tweaked [[file:elisp/ox-confluence.el][Confluence exporter]] for my org files:
|
I have a special version of tweaked [[file:elisp/ox-confluence.el][Confluence exporter]] for my org files:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ox-confluence
|
(use-package ox-confluence
|
||||||
:after org
|
:after org
|
||||||
:straight nil ; Located in my "elisp" directory
|
:straight nil ; Located in my "elisp" directory
|
||||||
:config
|
:config
|
||||||
(ha-org-leader
|
(ha-org-leader
|
||||||
"E" '("to confluence" . ox-export-to-confluence)))
|
"E" '("to confluence" . ox-export-to-confluence)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And Graphviz configuration using [[https://github.com/ppareit/graphviz-dot-mode][graphviz-dot-mode]]:
|
And Graphviz configuration using [[https://github.com/ppareit/graphviz-dot-mode][graphviz-dot-mode]]:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package graphviz-dot-mode
|
(use-package graphviz-dot-mode
|
||||||
:mode "\\.dot\\'"
|
:mode "\\.dot\\'"
|
||||||
:init
|
:init
|
||||||
|
@ -586,18 +585,18 @@ And Graphviz configuration using [[https://github.com/ppareit/graphviz-dot-mode]
|
||||||
graphviz-dot-auto-indent-on-newline t
|
graphviz-dot-auto-indent-on-newline t
|
||||||
graphviz-dot-auto-indent-on-braces t
|
graphviz-dot-auto-indent-on-braces t
|
||||||
graphviz-dot-auto-indent-on-semi t))
|
graphviz-dot-auto-indent-on-semi t))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And we can install company support:
|
And we can install company support:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package company-graphviz-dot)
|
(use-package company-graphviz-dot)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Focused Work
|
** Focused Work
|
||||||
:LOGBOOK:
|
:LOGBOOK:
|
||||||
CLOCK: [2022-02-11 Fri 11:05]--[2022-02-11 Fri 11:21] => 0:16
|
CLOCK: [2022-02-11 Fri 11:05]--[2022-02-11 Fri 11:21] => 0:16
|
||||||
:END:
|
:END:
|
||||||
I've been working on my own [[http://www.howardism.org/Technical/Emacs/focused-work.html][approach to focused work]],
|
I've been working on my own [[http://www.howardism.org/Technical/Emacs/focused-work.html][approach to focused work]],
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package async)
|
(use-package async)
|
||||||
|
|
||||||
(use-package ha-focus
|
(use-package ha-focus
|
||||||
|
@ -606,23 +605,23 @@ I've been working on my own [[http://www.howardism.org/Technical/Emacs/focused-w
|
||||||
(ha-leader
|
(ha-leader
|
||||||
"o f" '("begin focus" . ha-focus-begin)
|
"o f" '("begin focus" . ha-focus-begin)
|
||||||
"o F" '("break focus" . ha-focus-break)))
|
"o F" '("break focus" . ha-focus-break)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Spell Checking
|
** Spell Checking
|
||||||
Let's hook some spell-checking into org files, and actually all text files. I’m making this particularly delicious.
|
Let's hook some spell-checking into org files, and actually all text files. I’m making this particularly delicious.
|
||||||
|
|
||||||
First, we turn on =abbrev-mode=. While this package comes with Emacs, check out [[https://masteringemacs.org/article/correcting-typos-misspellings-abbrev][Mickey Petersen's overview]] of using this package for auto-correcting typos.
|
First, we turn on =abbrev-mode=. While this package comes with Emacs, check out [[https://masteringemacs.org/article/correcting-typos-misspellings-abbrev][Mickey Petersen's overview]] of using this package for auto-correcting typos.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq-default abbrev-mode t)
|
(setq-default abbrev-mode t)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
In general, /fill/ the list, by moving the point to the /end/ of some word, and type ~C-x a g~ (or, in /normal state/, type ~SPC x d~):
|
In general, /fill/ the list, by moving the point to the /end/ of some word, and type ~C-x a g~ (or, in /normal state/, type ~SPC x d~):
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "x d" '("add abbrev" . kadd-global-abbrev))
|
(ha-leader "x d" '("add abbrev" . kadd-global-abbrev))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
The idea is that you can correct a typo /and remember/ it. Perhaps calling [[help:edit-abbrevs][edit-abbrevs]] to making any fixes to that list.
|
The idea is that you can correct a typo /and remember/ it. Perhaps calling [[help:edit-abbrevs][edit-abbrevs]] to making any fixes to that list.
|
||||||
|
|
||||||
Next, I create a special /auto-correcting function/ that takes advantage of Evil’s [[help:evil-prev-flyspell-error][evil-prev-flyspell-error]] to jump back to the last spelling mistake (as I often notice the mistake after entering a few words), and call the interactive [[help:ispell-word][ispell-word]]. What makes this delicious is that I then call [[help:define-global-abbrev][define-global-abbrev]] to store both the mistake and the correction so that automatically typing that mistake again, is corrected.
|
Next, I create a special /auto-correcting function/ that takes advantage of Evil’s [[help:evil-prev-flyspell-error][evil-prev-flyspell-error]] to jump back to the last spelling mistake (as I often notice the mistake after entering a few words), and call the interactive [[help:ispell-word][ispell-word]]. What makes this delicious is that I then call [[help:define-global-abbrev][define-global-abbrev]] to store both the mistake and the correction so that automatically typing that mistake again, is corrected.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-fix-last-spelling (count)
|
(defun ha-fix-last-spelling (count)
|
||||||
"Jump to the last misspelled word, and correct it.
|
"Jump to the last misspelled word, and correct it.
|
||||||
This adds the correction to the global abbrev table so that any
|
This adds the correction to the global abbrev table so that any
|
||||||
|
@ -635,12 +634,12 @@ Next, I create a special /auto-correcting function/ that takes advantage of Evil
|
||||||
(bad-word (match-string 0)))
|
(bad-word (match-string 0)))
|
||||||
(ispell-word)
|
(ispell-word)
|
||||||
(define-global-abbrev bad-word (buffer-substring-no-properties start-word (point)))))))
|
(define-global-abbrev bad-word (buffer-substring-no-properties start-word (point)))))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Since this auto-correction needs to happen in /insert/ mode, I have bound a few keys, including ~CMD-s~ and ~M-s~ (twice) to fixing this spelling mistake, and jumping back to where I am. If the spelling mistake is /obvious/, I use ~C-;~ to call [[help:flyspell-auto-correct-word][flyspell-auto-correct-word]]. However, I currently do not know how to use this cool feature with my =ha-fix-last-spelling= function (because I don’t know when that function is done).
|
Since this auto-correction needs to happen in /insert/ mode, I have bound a few keys, including ~CMD-s~ and ~M-s~ (twice) to fixing this spelling mistake, and jumping back to where I am. If the spelling mistake is /obvious/, I use ~C-;~ to call [[help:flyspell-auto-correct-word][flyspell-auto-correct-word]]. However, I currently do not know how to use this cool feature with my =ha-fix-last-spelling= function (because I don’t know when that function is done).
|
||||||
|
|
||||||
For this to work, we use [[https://www.emacswiki.org/emacs/FlySpell][flyspell]] mode to highlight the misspelled words, and the venerable [[https://www.emacswiki.org/emacs/InteractiveSpell][ispell]] for correcting.
|
For this to work, we use [[https://www.emacswiki.org/emacs/FlySpell][flyspell]] mode to highlight the misspelled words, and the venerable [[https://www.emacswiki.org/emacs/InteractiveSpell][ispell]] for correcting.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package flyspell
|
(use-package flyspell
|
||||||
:hook (text-mode . flyspell-mode)
|
:hook (text-mode . flyspell-mode)
|
||||||
:bind (("M-S" . ha-fix-last-spelling) ; This is j-k-s on the Moonlander. Hrm.
|
:bind (("M-S" . ha-fix-last-spelling) ; This is j-k-s on the Moonlander. Hrm.
|
||||||
|
@ -663,12 +662,12 @@ For this to work, we use [[https://www.emacswiki.org/emacs/FlySpell][flyspell]]
|
||||||
"s c" '("correct word" . flyspell-auto-correct-word)
|
"s c" '("correct word" . flyspell-auto-correct-word)
|
||||||
"s p" '("previous misspell" . evil-prev-flyspell-error)
|
"s p" '("previous misspell" . evil-prev-flyspell-error)
|
||||||
"s n" '("next misspell" . evil-next-flyspell-error)))
|
"s n" '("next misspell" . evil-next-flyspell-error)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Sure, the keys, ~[ s~ and ~] s~ can jump to misspelled words, and use ~M-$~ to correct them, but I'm getting used to these leaders.
|
Sure, the keys, ~[ s~ and ~] s~ can jump to misspelled words, and use ~M-$~ to correct them, but I'm getting used to these leaders.
|
||||||
|
|
||||||
According to [[http://endlessparentheses.com/ispell-and-apostrophes.html][Artur Malabarba]], we can turn on rounded apostrophe's, like =‘= (left single quotation mark). The idea is to not send the quote to the sub-process:
|
According to [[http://endlessparentheses.com/ispell-and-apostrophes.html][Artur Malabarba]], we can turn on rounded apostrophe's, like =‘= (left single quotation mark). The idea is to not send the quote to the sub-process:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun endless/replace-apostrophe (args)
|
(defun endless/replace-apostrophe (args)
|
||||||
"Don't send ’ to the subprocess."
|
"Don't send ’ to the subprocess."
|
||||||
(cons (replace-regexp-in-string
|
(cons (replace-regexp-in-string
|
||||||
|
@ -686,13 +685,13 @@ According to [[http://endlessparentheses.com/ispell-and-apostrophes.html][Artur
|
||||||
(cdr args))))
|
(cdr args))))
|
||||||
|
|
||||||
(advice-add #'ispell-parse-output :filter-args #'endless/replace-quote)
|
(advice-add #'ispell-parse-output :filter-args #'endless/replace-quote)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The end result? No misspellings. Isn‘t this nice?
|
The end result? No misspellings. Isn‘t this nice?
|
||||||
|
|
||||||
Of course I need a thesaurus, and I'm installing [[https://github.com/SavchenkoValeriy/emacs-powerthesaurus][powerthesaurus]]:
|
Of course I need a thesaurus, and I'm installing [[https://github.com/SavchenkoValeriy/emacs-powerthesaurus][powerthesaurus]]:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package powerthesaurus
|
(use-package powerthesaurus
|
||||||
:bind ("M-T" . powerthesaurus-lookup-dwim)
|
:bind ("M-T" . powerthesaurus-lookup-dwim)
|
||||||
:config
|
:config
|
||||||
|
@ -702,37 +701,38 @@ Of course I need a thesaurus, and I'm installing [[https://github.com/SavchenkoV
|
||||||
"s a" '("antonyms" . powerthesaurus-lookup-antonyms-dwim)
|
"s a" '("antonyms" . powerthesaurus-lookup-antonyms-dwim)
|
||||||
"s r" '("related" . powerthesaurus-lookup-related-dwim)
|
"s r" '("related" . powerthesaurus-lookup-related-dwim)
|
||||||
"s S" '("sentence" . powerthesaurus-lookup-sentences-dwim)))
|
"s S" '("sentence" . powerthesaurus-lookup-sentences-dwim)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
The key-bindings, keystrokes, and key-connections work well with ~M-T~ (notice the Shift), but to jump to specifics, we use a leader. Since the /definitions/ do not work, so let's use abo-abo's [[https://github.com/abo-abo/define-word][define-word]] project:
|
The key-bindings, keystrokes, and key-connections work well with ~M-T~ (notice the Shift), but to jump to specifics, we use a leader. Since the /definitions/ do not work, so let's use abo-abo's [[https://github.com/abo-abo/define-word][define-word]] project:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package define-word
|
(use-package define-word
|
||||||
:config
|
:config
|
||||||
(ha-local-leader :keymaps 'text-mode-map
|
(ha-local-leader :keymaps 'text-mode-map
|
||||||
"s d" '("define this" . define-word-at-point)
|
"s d" '("define this" . define-word-at-point)
|
||||||
"s D" '("define word" . define-word)))
|
"s D" '("define word" . define-word)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Grammar and Prose Linting
|
** Grammar and Prose Linting
|
||||||
Flagging cliches, weak phrasing and other poor grammar choices.
|
Flagging cliches, weak phrasing and other poor grammar choices.
|
||||||
*** Writegood
|
*** Writegood
|
||||||
The [[https://github.com/bnbeckwith/writegood-mode][writegood-mode]] is effective at highlighting passive and weasel words, but isn’t integrated into =flycheck=:
|
The [[https://github.com/bnbeckwith/writegood-mode][writegood-mode]] is effective at highlighting passive and weasel words, but isn’t integrated into =flycheck=:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package writegood-mode
|
(use-package writegood-mode
|
||||||
:hook ((org-mode . writegood-mode)))
|
:hook ((org-mode . writegood-mode)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
And it reports obnoxious messages.
|
||||||
|
|
||||||
We install the =write-good= NPM:
|
We install the =write-good= NPM:
|
||||||
#+BEGIN_SRC shell
|
#+begin_src shell
|
||||||
npm install -g write-good
|
npm install -g write-good
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And check that the following works:
|
And check that the following works:
|
||||||
#+BEGIN_SRC sh :results output
|
#+begin_src sh :results output
|
||||||
write-good --text="So it is what it is."
|
write-good --text="So it is what it is."
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Now, let’s connect it to flycheck:
|
Now, let’s connect it to flycheck:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package flycheck
|
(use-package flycheck
|
||||||
:config
|
:config
|
||||||
(flycheck-define-checker write-good
|
(flycheck-define-checker write-good
|
||||||
|
@ -743,16 +743,16 @@ Now, let’s connect it to flycheck:
|
||||||
((warning line-start (file-name) ":" line ":" column ":" (message) line-end))
|
((warning line-start (file-name) ":" line ":" column ":" (message) line-end))
|
||||||
:modes (markdown-mode org-mode text-mode))
|
:modes (markdown-mode org-mode text-mode))
|
||||||
|
|
||||||
#+END_SRC
|
|
||||||
(add-to-list 'flycheck-checkers 'write-good))
|
(add-to-list 'flycheck-checkers 'write-good))
|
||||||
|
#+end_src
|
||||||
*** Proselint
|
*** Proselint
|
||||||
With overlapping goals to =write-good=, the [[https://github.com/amperser/proselint/][proselint]] project, once installed, can check for some English phrasings. I like =write-good= better, but I want this available for its level of /pedantic-ness/.
|
With overlapping goals to =write-good=, the [[https://github.com/amperser/proselint/][proselint]] project, once installed, can check for some English phrasings. I like =write-good= better, but I want this available for its level of /pedantic-ness/.
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
brew install proselint
|
brew install proselint
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Next, create a configuration file, =~/.config/proselint/config= file, to turn on/off checks:
|
Next, create a configuration file, =~/.config/proselint/config= file, to turn on/off checks:
|
||||||
#+BEGIN_SRC js :tangle ~/.config/proselint/config.json :mkdirp yes
|
#+begin_src js :tangle ~/.config/proselint/config.json :mkdirp yes
|
||||||
{
|
{
|
||||||
"checks": {
|
"checks": {
|
||||||
"typography.diacritical_marks": false,
|
"typography.diacritical_marks": false,
|
||||||
|
@ -760,12 +760,11 @@ Next, create a configuration file, =~/.config/proselint/config= file, to turn on
|
||||||
"consistency.spacing": false
|
"consistency.spacing": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And tell [[https://www.flycheck.org/][flycheck]] to use this:
|
And tell [[https://www.flycheck.org/][flycheck]] to use this:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package flycheck
|
(use-package flycheck
|
||||||
#+END_SRC
|
|
||||||
:config
|
:config
|
||||||
(add-to-list 'flycheck-checkers 'proselint)
|
(add-to-list 'flycheck-checkers 'proselint)
|
||||||
;; And create the chain of checkers so that both work:
|
;; And create the chain of checkers so that both work:
|
||||||
|
@ -812,15 +811,16 @@ Add =textlint= to the /chain/ for Org files:
|
||||||
:config
|
:config
|
||||||
(setq flycheck-textlint-config (format "%s/.textlintrc" (getenv "HOME")))
|
(setq flycheck-textlint-config (format "%s/.textlintrc" (getenv "HOME")))
|
||||||
(flycheck-add-next-checker 'proselint 'textlint))
|
(flycheck-add-next-checker 'proselint 'textlint))
|
||||||
|
#+end_src
|
||||||
** Distraction-Free Writing
|
** Distraction-Free Writing
|
||||||
[[https://christopherfin.com/writing/emacs-writing.html][Christopher Fin's essay]] inspired me to clean my writing room.
|
[[https://christopherfin.com/writing/emacs-writing.html][Christopher Fin's essay]] inspired me to clean my writing room.
|
||||||
*** Write-room
|
*** Write-room
|
||||||
For a complete focused, /distraction-free/ environment, for writing or concentrating, I'm using [[https://github.com/joostkremers/writeroom-mode][Writeroom-mode]]:
|
For a complete focused, /distraction-free/ environment, for writing or concentrating, I'm using [[https://github.com/joostkremers/writeroom-mode][Writeroom-mode]]:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package writeroom-mode
|
(use-package writeroom-mode
|
||||||
:hook (writeroom-mode-disable . winner-undo)
|
:hook (writeroom-mode-disable . winner-undo)
|
||||||
:config
|
:init
|
||||||
(ha-leader "t W" '("writeroom" . writeroom-mode))
|
(ha-leader "t W" '("writeroom" . writeroom-mode))
|
||||||
(ha-leader :keymaps 'writeroom-mode-map
|
(ha-leader :keymaps 'writeroom-mode-map
|
||||||
"=" '("adjust width" . writeroom-adjust-width)
|
"=" '("adjust width" . writeroom-adjust-width)
|
||||||
|
@ -830,23 +830,22 @@ For a complete focused, /distraction-free/ environment, for writing or concentra
|
||||||
("C-M-<" . writeroom-decrease-width)
|
("C-M-<" . writeroom-decrease-width)
|
||||||
("C-M->" . writeroom-increase-width)
|
("C-M->" . writeroom-increase-width)
|
||||||
("C-M-=" . writeroom-adjust-width)))
|
("C-M-=" . writeroom-adjust-width)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Olivetti
|
*** Olivetti
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
The [[https://github.com/rnkn/olivetti][olivetti project]] sets wide margins and centers the text. It isn’t better than Writeroom, but, it works well with Logos (below).
|
The [[https://github.com/rnkn/olivetti][olivetti project]] sets wide margins and centers the text. It isn’t better than Writeroom, but, it works well with Logos (below).
|
||||||
|
#+begin_src emacs-lisp
|
||||||
(use-package olivetti
|
(use-package olivetti
|
||||||
:init
|
:init
|
||||||
(setq-default olivetti-body-width 100)
|
(setq-default olivetti-body-width 100)
|
||||||
:config
|
|
||||||
(ha-leader "t O" '("olivetti" . olivetti-mode))
|
(ha-leader "t O" '("olivetti" . olivetti-mode))
|
||||||
:bind (:map olivetti-mode-map
|
:bind (:map olivetti-mode-map
|
||||||
("C-M-<" . olivetti-shrink)
|
("C-M-<" . olivetti-shrink)
|
||||||
("C-M->" . olivetti-expand)
|
("C-M->" . olivetti-expand)
|
||||||
("C-M-=" . olivetti-set-width)))
|
("C-M-=" . olivetti-set-width)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Logos
|
*** Logos
|
||||||
Trying out [[https://protesilaos.com/][Protesilaos Stavrou]]’s [[https://protesilaos.com/emacs/logos][logos project]] as a replacement for [[https://github.com/joostkremers/writeroom-mode][Writeroom-mode]]:
|
Trying out [[https://protesilaos.com/][Protesilaos Stavrou]]’s [[https://protesilaos.com/emacs/logos][logos project]] as a replacement for [[https://github.com/joostkremers/writeroom-mode][Writeroom-mode]]:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package logos
|
(use-package logos
|
||||||
:straight (:type git :protocol ssh :host gitlab :repo "protesilaos/logos")
|
:straight (:type git :protocol ssh :host gitlab :repo "protesilaos/logos")
|
||||||
:init
|
:init
|
||||||
|
@ -870,13 +869,13 @@ Trying out [[https://protesilaos.com/][Protesilaos Stavrou]]’s [[https://prote
|
||||||
(:states 'normal
|
(:states 'normal
|
||||||
"g [" 'logos-backward-page-dwim
|
"g [" 'logos-backward-page-dwim
|
||||||
"g ]" 'logos-forward-page-dwim))
|
"g ]" 'logos-forward-page-dwim))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's provide a name, to allow =require= to work:
|
Let's provide a name, to allow =require= to work:
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-org)
|
(provide 'ha-org)
|
||||||
;;; ha-org.el ends here
|
;;; ha-org.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Personal Password Generator
|
#+TITLE: Personal Password Generator
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2021-01-11
|
#+DATE: 2021-01-11
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming version for Emacs code to generate and store passwords.
|
A literate programming version for Emacs code to generate and store passwords.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-passwords --- Emacs code to generate and store passwords. -*- lexical-binding: t; -*-
|
;;; ha-passwords --- Emacs code to generate and store passwords. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2021-2022 Howard X. Abrams
|
;; © 2021-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,11 +22,10 @@ A literate programming version for Emacs code to generate and store passwords.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
Let's assume that I store a bunch of words in data files:
|
Let's assume that I store a bunch of words in data files:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defvar ha-passwords-data-files (list (expand-file-name "adjectives.txt"
|
(defvar ha-passwords-data-files (list (expand-file-name "adjectives.txt"
|
||||||
(expand-file-name "data" hamacs-source-dir))
|
(expand-file-name "data" hamacs-source-dir))
|
||||||
(expand-file-name "colors.txt"
|
(expand-file-name "colors.txt"
|
||||||
|
@ -38,32 +36,30 @@ Let's assume that I store a bunch of words in data files:
|
||||||
|
|
||||||
(defvar ha-passwords-data nil
|
(defvar ha-passwords-data nil
|
||||||
"Contains a list of lists of words that we can choose.")
|
"Contains a list of lists of words that we can choose.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
You can see where I'm going with this, can't you? Let's read them into list variables.
|
You can see where I'm going with this, can't you? Let's read them into list variables.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defun ha-passwords--read-data-file (filename)
|
(defun ha-passwords--read-data-file (filename)
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert-file-contents filename)
|
(insert-file-contents filename)
|
||||||
(split-string (buffer-string) "\n" t)))
|
(split-string (buffer-string) "\n" t)))
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Now we just get three or so words from our list of lists:
|
Now we get three or so words from our list of lists:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(defun ha-passwords-words ()
|
(defun ha-passwords-words ()
|
||||||
(unless ha-passwords-data
|
(unless ha-passwords-data
|
||||||
(setq ha-passwords-data
|
(setq ha-passwords-data
|
||||||
(--map (ha-passwords--read-data-file it) ha-passwords-data-files)))
|
(--map (ha-passwords--read-data-file it) ha-passwords-data-files)))
|
||||||
|
|
||||||
(--map (nth (random (length it)) it) ha-passwords-data))
|
(--map (nth (random (length it)) it) ha-passwords-data))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let's make a password:
|
Let's make a password:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-passwords-generate (&optional separator)
|
(defun ha-passwords-generate (&optional separator)
|
||||||
(unless separator
|
(unless separator
|
||||||
(setq separator "-"))
|
(setq separator "-"))
|
||||||
|
@ -76,27 +72,27 @@ Let's make a password:
|
||||||
(s-capitalize)
|
(s-capitalize)
|
||||||
(s-append (nth choice choices))
|
(s-append (nth choice choices))
|
||||||
(s-append (number-to-string number)))))
|
(s-append (number-to-string number)))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun generate-password (&optional separator)
|
(defun generate-password (&optional separator)
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((passphrase (ha-passwords-generate separator)))
|
(let ((passphrase (ha-passwords-generate separator)))
|
||||||
(kill-new passphrase)
|
(kill-new passphrase)
|
||||||
(message "Random password: %s" passphrase)))
|
(message "Random password: %s" passphrase)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Keybindings
|
* Keybindings
|
||||||
Got make it easy to call:
|
Got make it easy to call:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "a g" '("generate passwd" . generate-password))
|
(ha-leader "a g" '("generate passwd" . generate-password))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
This will =provide= a code name, so that we can =require= this.
|
This will =provide= a code name, so that we can =require= this.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-passwords)
|
(provide 'ha-passwords)
|
||||||
;;; ha-passwords.el ends here
|
;;; ha-passwords.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: A literate programming version for Emacs code to generate and store passwords.
|
#+DESCRIPTION: A literate programming version for Emacs code to generate and store passwords.
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Emacs Lisp Configuration
|
#+TITLE: Emacs Lisp Configuration
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2022-05-11
|
#+DATE: 2022-05-11
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file for configuring Emacs for Lisp programming.
|
A literate programming file for configuring Emacs for Lisp programming.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-lisp --- configuring Emacs for Lisp programming. -*- lexical-binding: t; -*-
|
;;; ha-lisp --- configuring Emacs for Lisp programming. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2022 Howard X. Abrams
|
;; © 2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,45 +22,45 @@ A literate programming file for configuring Emacs for Lisp programming.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
While I program in a lot of languages, I seem to be writing all my helper tools and scripts in … Emacs Lisp. So I’m cranking this up to 11.
|
While I program in a lot of languages, I seem to be writing all my helper tools and scripts in … Emacs Lisp. I’m cranking this up to 11.
|
||||||
|
|
||||||
New, /non-literal/ source code comes from [[file:templates/emacs-lisp-mode.el][emacs-lisp-mode template]]:
|
New, /non-literal/ source code comes from [[file:templates/emacs-lisp-mode.el][emacs-lisp-mode template]]:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-auto-insert-file (rx ".el" eol) "emacs-lisp-mode.el")
|
(ha-auto-insert-file (rx ".el" eol) "emacs-lisp-mode.el")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Syntax Display
|
* Syntax Display
|
||||||
** Dim those Parenthesis
|
** Dim those Parenthesis
|
||||||
The [[https://github.com/tarsius/paren-face][paren-face]] project lowers the color level of parenthesis which I find better.
|
The [[https://github.com/tarsius/paren-face][paren-face]] project lowers the color level of parenthesis which I find better.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package paren-face
|
(use-package paren-face
|
||||||
:hook (emacs-lisp-mode . paren-face-mode))
|
:hook (emacs-lisp-mode . paren-face-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Show code examples with the [[https://github.com/xuchunyang/elisp-demos][elisp-demos]] package. This is really helpful.
|
Show code examples with the [[https://github.com/xuchunyang/elisp-demos][elisp-demos]] package.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package elisp-demos
|
(use-package elisp-demos
|
||||||
:config
|
:config
|
||||||
(advice-add 'describe-function-1 :after #'elisp-demos-advice-describe-function-1))
|
(advice-add 'describe-function-1 :after #'elisp-demos-advice-describe-function-1))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Navigation and Editing
|
* Navigation and Editing
|
||||||
** Goto Definitions
|
** Goto Definitions
|
||||||
Wilfred’s [[https://github.com/Wilfred/elisp-def][elisp-def]] project does a better job at jumping to the definition of a symbol at the point, so:
|
Wilfred’s [[https://github.com/Wilfred/elisp-def][elisp-def]] project does a better job at jumping to the definition of a symbol at the point, so:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package elisp-def
|
(use-package elisp-def
|
||||||
:hook (emacs-lisp-mode . elisp-def-mode))
|
:hook (emacs-lisp-mode . elisp-def-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
This /should work/ with [[help:evil-goto-definition][evil-goto-defintion]], as that calls this list from [[help:evil-goto-definition-functions][evil-goto-definition-functions]]:
|
This /should work/ with [[help:evil-goto-definition][evil-goto-defintion]], as that calls this list from [[help:evil-goto-definition-functions][evil-goto-definition-functions]]:
|
||||||
- [[help:evil-goto-definition-imenu][evil-goto-definition-imenu]]
|
- [[help:evil-goto-definition-imenu][evil-goto-definition-imenu]]
|
||||||
- [[help:evil-goto-definition-semantic][evil-goto-definition-semantic]]
|
- [[help:evil-goto-definition-semantic][evil-goto-definition-semantic]]
|
||||||
- [[help:evil-goto-definition-xref][evil-goto-definition-xref]] … and here is where this package will be called
|
- [[help:evil-goto-definition-xref][evil-goto-definition-xref]] … to show what calls a function
|
||||||
- [[help:evil-goto-definition-search][evil-goto-definition-search]]
|
- [[help:evil-goto-definition-search][evil-goto-definition-search]]
|
||||||
|
|
||||||
I love packages that add functionality but I don’t have to learn anything. However, I’m running into an issue where I do a lot of my Emacs Lisp programming in org files, and would like to jump to the function definition where it is defined in the org file. Since [[https://github.com/BurntSushi/ripgrep][ripgrep]] is pretty fast, I’ll call it instead of attempting to build a [[https://stackoverflow.com/questions/41933837/understanding-the-ctags-file-format][CTAGS]] table. Oooh, the =rg= takes a =—json= option, which makes it easier to parse.
|
While I love packages that add functionality and I don’t have to learn anything, I’m running into an issue where I do a lot of my Emacs Lisp programming in org files, and would like to jump to the function definition /defined in the org file/. Since [[https://github.com/BurntSushi/ripgrep][ripgrep]] is pretty fast, I’ll call it instead of attempting to build a [[https://stackoverflow.com/questions/41933837/understanding-the-ctags-file-format][CTAGS]] table. Oooh, the =rg= takes a =—json= option, which makes it easier to parse.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-org-code-block-jump (str pos)
|
(defun ha-org-code-block-jump (str pos)
|
||||||
"Go to a literate org file containing a symbol, STR.
|
"Go to a literate org file containing a symbol, STR.
|
||||||
The POS is ignored."
|
The POS is ignored."
|
||||||
|
@ -86,25 +85,25 @@ I love packages that add functionality but I don’t have to learn anything. How
|
||||||
(goto-line line))))
|
(goto-line line))))
|
||||||
|
|
||||||
(add-to-list 'evil-goto-definition-functions 'ha-org-code-block-jump)
|
(add-to-list 'evil-goto-definition-functions 'ha-org-code-block-jump)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And in case I need to call it directly:
|
And in case I need to call it directly:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-goto-definition ()
|
(defun ha-goto-definition ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(evil-inner-WORD))
|
(evil-inner-WORD))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Clever Parenthesis
|
** Clever Parenthesis
|
||||||
We need to make sure we keep the [[https://github.com/Fuco1/smartparens][smartparens]] project always in /strict mode/, because who wants to worry about paren-matching:
|
We need to make sure we keep the [[https://github.com/Fuco1/smartparens][smartparens]] project always in /strict mode/, because who wants to worry about paren-matching:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package smartparens
|
(use-package smartparens
|
||||||
:custom
|
:custom
|
||||||
(smartparens-global-strict-mode t)
|
(smartparens-global-strict-mode t)
|
||||||
:hook
|
:hook
|
||||||
(prog-mode . smartparens-strict-mode))
|
(prog-mode . smartparens-strict-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The [[https://github.com/luxbock/evil-cleverparens][evil-cleverparens]] solves having me create keybindings to the [[https://github.com/Fuco1/smartparens][smartparens]] project by updating the evil states with Lisp-specific bindings.
|
The [[https://github.com/luxbock/evil-cleverparens][evil-cleverparens]] solves having me create keybindings to the [[https://github.com/Fuco1/smartparens][smartparens]] project by updating the evil states with Lisp-specific bindings.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package evil-cleverparens
|
(use-package evil-cleverparens
|
||||||
:after smartparens
|
:after smartparens
|
||||||
:custom
|
:custom
|
||||||
|
@ -118,26 +117,26 @@ The [[https://github.com/luxbock/evil-cleverparens][evil-cleverparens]] solves h
|
||||||
:hook
|
:hook
|
||||||
(prog-mode . evil-cleverparens-mode)) ;; All the languages!
|
(prog-mode . evil-cleverparens-mode)) ;; All the languages!
|
||||||
;; Otherwise: (emacs-lisp-mode . evil-cleverparens-mode)
|
;; Otherwise: (emacs-lisp-mode . evil-cleverparens-mode)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The /trick/ to being effective with the [[https://www.emacswiki.org/emacs/ParEdit][paredit-family]] of extensions is learning the keys. The killer “app” is the slurp/barf sequence. Use the ~<~ key, in normal mode, to barf (or jettison)… in other words, /move/ the paren closer to the point. For instance:
|
The /trick/ to being effective with the [[https://www.emacswiki.org/emacs/ParEdit][paredit-family]] of extensions is learning the keys. The killer “app” is the slurp/barf sequence. Use the ~<~ key, in normal mode, to barf (or jettison)… in other words, /move/ the paren closer to the point. For instance:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(+ 41 (* ‖1 3)) ⟹ (+ 41 (* ‖1) 3)
|
(+ 41 (* ‖1 3)) ⟹ (+ 41 (* ‖1) 3)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Use the ~>~ key to /slurp/ in outside objects into the current expression… in other words, move the paren away from the point. For instance:
|
Use the ~>~ key to /slurp/ in outside objects into the current expression… in other words, move the paren away from the point. For instance:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(+ 41 (* ‖1) 3) ⟹ (+ 41 (* ‖1 3))
|
(+ 41 (* ‖1) 3) ⟹ (+ 41 (* ‖1 3))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
*Opening Parens.* Those two keys seem straight-forward, but they behave differently when the are on the opening parens.
|
*Opening Parens.* Those two keys seem straight-forward, but they behave differently when the are on the opening parens.
|
||||||
When the point (symbolized by ~‖~) is /on/ the opening paren, ~<~ moves the paren to the left. For instance:
|
When the point (symbolized by ~‖~) is /on/ the opening paren, ~<~ moves the paren to the left. For instance:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(+ 41 ‖(* 1 3)) ⟹ (+ ‖(41 * 1 3))
|
(+ 41 ‖(* 1 3)) ⟹ (+ ‖(41 * 1 3))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And the ~>~ moves the paren to the right. For instance:
|
And the ~>~ moves the paren to the right. For instance:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(+ 41 ‖(* 1 3)) ⟹ (+ 41 * ‖(1 3))
|
(+ 41 ‖(* 1 3)) ⟹ (+ 41 * ‖(1 3))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
I would like to have a list of what keybindings that work in =normal= mode:
|
I would like to have a list of what keybindings that work in =normal= mode:
|
||||||
- ~M-h~ / ~M-l~ move back/forward by functions
|
- ~M-h~ / ~M-l~ move back/forward by functions
|
||||||
|
@ -159,13 +158,13 @@ The other advantage is moving around by s-expressions. This takes a little getti
|
||||||
- ~(~ and ~)~ move up to the parent s-expression
|
- ~(~ and ~)~ move up to the parent s-expression
|
||||||
|
|
||||||
We need a real-world example. Let’s suppose we entered this:
|
We need a real-world example. Let’s suppose we entered this:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(format "The sum of %d %d is %d" a b (+ a b))
|
(format "The sum of %d %d is %d" a b (+ a b))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
But we forgot to define the =a= and =b= variables. One approach, after Escaping into the normal state, is to hit ~(~ to just to the beginning of the s-expression, and then type, ~M-(~ to wrap the expression, and type ~i~ to go into insert mode:
|
But we forgot to define the =a= and =b= variables. One approach, after Escaping into the normal state, is to hit ~(~ to just to the beginning of the s-expression, and then type, ~M-(~ to wrap the expression, and type ~i~ to go into insert mode:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(‖ (format "The sum of %d %d is %d" a b (+ a b)))
|
(‖ (format "The sum of %d %d is %d" a b (+ a b)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And now we can enter the =let= expression.
|
And now we can enter the =let= expression.
|
||||||
|
|
||||||
Other nifty keybindings that I need to commit to muscle memory include:
|
Other nifty keybindings that I need to commit to muscle memory include:
|
||||||
|
@ -179,14 +178,14 @@ Other nifty keybindings that I need to commit to muscle memory include:
|
||||||
|
|
||||||
** Eval Current Expression
|
** Eval Current Expression
|
||||||
The [[https://github.com/xiongtx/eros][eros]] package stands for Evaluation Result OverlayS for Emacs Lisp, and basically shows what each s-expression is near the cursor position instead of in the mini-buffer at the bottom of the window.
|
The [[https://github.com/xiongtx/eros][eros]] package stands for Evaluation Result OverlayS for Emacs Lisp, and basically shows what each s-expression is near the cursor position instead of in the mini-buffer at the bottom of the window.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package eros
|
(use-package eros
|
||||||
:hook (emacs-lisp-mode . eros-mode))
|
:hook (emacs-lisp-mode . eros-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
A feature I enjoyed from Spacemacs is the ability to evaluate the s-expression currently containing the point. Not sure how they made it, but [[help:evil-cp-next-closing ][evil-cp-next-closing]] from cleverparens can help:
|
A feature I enjoyed from Spacemacs is the ability to evaluate the s-expression currently containing the point. Not sure how they made it, but [[help:evil-cp-next-closing ][evil-cp-next-closing]] from cleverparens can help:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-eval-current-expression ()
|
(defun ha-eval-current-expression ()
|
||||||
"Evaluates the expression the point is currently 'in'.
|
"Evaluates the expression the point is currently 'in'.
|
||||||
It does this, by jumping to the end of the current
|
It does this, by jumping to the end of the current
|
||||||
|
@ -197,21 +196,20 @@ finds at that point."
|
||||||
(evil-cp-next-closing)
|
(evil-cp-next-closing)
|
||||||
(evil-cp-forward-sexp)
|
(evil-cp-forward-sexp)
|
||||||
(call-interactively 'eval-last-sexp)))
|
(call-interactively 'eval-last-sexp)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And we just need to bind it.
|
And we just need to bind it.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-prog-leader
|
(ha-prog-leader
|
||||||
"e c" '("current" . ha-eval-current-expression))
|
"e c" '("current" . ha-eval-current-expression))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
|
|
||||||
Let's =provide= a name so we can =require= this file:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-programming-elisp)
|
(provide 'ha-programming-elisp)
|
||||||
;;; ha-programming-elisp.el ends here
|
;;; ha-programming-elisp.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: configuring Emacs for Lisp programming.
|
#+DESCRIPTION: configuring Emacs for Lisp programming.
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Configuring Python in Emacs
|
#+TITLE: Configuring Python in Emacs
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2021-11-16
|
#+DATE: 2021-11-16
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file for configuring Python.
|
A literate programming file for configuring Python.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-programming-python --- Python configuration. -*- lexical-binding: t; -*-
|
;;; ha-programming-python --- Python configuration. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2021-2022 Howard X. Abrams
|
;; © 2021-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,21 +22,21 @@ A literate programming file for configuring Python.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
The critical part of Python integration with Emacs is running LSP in Python using [[file:ha-programming.org::*direnv][direnv]]. And the only question to ask is if the Python we run it in Docker or in a virtual environment.
|
The critical part of Python integration with Emacs is running LSP in Python using [[file:ha-programming.org::*direnv][direnv]]. And the question to ask is if the Python we run it in Docker or in a virtual environment.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(general-create-definer ha-python-leader
|
(general-create-definer ha-python-leader
|
||||||
:states '(normal visual motion)
|
:states '(normal visual motion)
|
||||||
:keymaps 'python-mode-map
|
:keymaps 'python-mode-map
|
||||||
:prefix "SPC m"
|
:prefix "SPC m"
|
||||||
:global-prefix "<f17>"
|
:global-prefix "<f17>"
|
||||||
:non-normal-prefix "S-SPC")
|
:non-normal-prefix "S-SPC")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
While Emacs supplies a Python editing environment, we’ll still use =use-package= to grab the latest:
|
While Emacs supplies a Python editing environment, we’ll still use =use-package= to grab the latest:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package python
|
(use-package python
|
||||||
:after projectile
|
:after projectile
|
||||||
:mode ("[./]flake8\\'" . conf-mode)
|
:mode ("[./]flake8\\'" . conf-mode)
|
||||||
|
@ -53,7 +52,7 @@ While Emacs supplies a Python editing environment, we’ll still use =use-packag
|
||||||
;; create these files for my Python projects:
|
;; create these files for my Python projects:
|
||||||
(add-to-list 'projectile-project-root-files "requirements-dev.txt")
|
(add-to-list 'projectile-project-root-files "requirements-dev.txt")
|
||||||
(add-to-list 'projectile-project-root-files "requirements-test.txt"))
|
(add-to-list 'projectile-project-root-files "requirements-test.txt"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Virtual Environment
|
** Virtual Environment
|
||||||
For a local virtual machine, simply put the following in your =.envrc= file:
|
For a local virtual machine, simply put the following in your =.envrc= file:
|
||||||
#+begin_src conf
|
#+begin_src conf
|
||||||
|
@ -62,9 +61,9 @@ layout_python3
|
||||||
That is pretty slick and simple.
|
That is pretty slick and simple.
|
||||||
|
|
||||||
The old way, that we still use if you need a particular version of Python, is to install [[https://github.com/pyenv/pyenv][pyenv]] globally:
|
The old way, that we still use if you need a particular version of Python, is to install [[https://github.com/pyenv/pyenv][pyenv]] globally:
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
pip install pyenv
|
pip install pyenv
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And have this in your =.envrc= file:
|
And have this in your =.envrc= file:
|
||||||
#+begin_src conf
|
#+begin_src conf
|
||||||
|
@ -86,12 +85,12 @@ use_python() {
|
||||||
#+end_src
|
#+end_src
|
||||||
** Editing Python Code
|
** Editing Python Code
|
||||||
Let’s integrate this [[https://github.com/wbolster/evil-text-object-python][Python support for evil-text-object]] project:
|
Let’s integrate this [[https://github.com/wbolster/evil-text-object-python][Python support for evil-text-object]] project:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package evil-text-object-python
|
(use-package evil-text-object-python
|
||||||
:hook (python-mode . evil-text-object-python-add-bindings))
|
:hook (python-mode . evil-text-object-python-add-bindings))
|
||||||
|
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
This allows me to delete a Python “block” using ~dal~.
|
This allows me to delete a Python “block” using ~dal~.
|
||||||
** Docker Environment
|
** Docker Environment
|
||||||
Docker really allows you to isolate your project's environment. The downside is that you are using Docker and probably a bloated container. On my work laptop, a Mac, this creates a behemoth virtual machine that immediately spins the fans like a wind tunnel.
|
Docker really allows you to isolate your project's environment. The downside is that you are using Docker and probably a bloated container. On my work laptop, a Mac, this creates a behemoth virtual machine that immediately spins the fans like a wind tunnel.
|
||||||
|
@ -109,7 +108,7 @@ CONTAINER_EXTRA_ARGS="--env SOME_ENV_VAR=${SOME_ENV_VAR}"
|
||||||
container_layout
|
container_layout
|
||||||
#+end_src
|
#+end_src
|
||||||
** Unit Tests
|
** Unit Tests
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package python-pytest
|
(use-package python-pytest
|
||||||
:after python
|
:after python
|
||||||
:commands python-pytest-dispatch
|
:commands python-pytest-dispatch
|
||||||
|
@ -123,7 +122,7 @@ container_layout
|
||||||
"t T" '("function" . python-pytest-function)
|
"t T" '("function" . python-pytest-function)
|
||||||
"t r" '("repeat" . python-pytest-repeat)
|
"t r" '("repeat" . python-pytest-repeat)
|
||||||
"t p" '("dispatch" . python-pytest-dispatch)))
|
"t p" '("dispatch" . python-pytest-dispatch)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Python Dependencies
|
** Python Dependencies
|
||||||
Each Python project's =requirements-dev.txt= file would reference the [[https://pypi.org/project/python-lsp-server/][python-lsp-server]] (not the /unmaintained/ project, =python-language-server=):
|
Each Python project's =requirements-dev.txt= file would reference the [[https://pypi.org/project/python-lsp-server/][python-lsp-server]] (not the /unmaintained/ project, =python-language-server=):
|
||||||
|
|
||||||
|
@ -132,7 +131,7 @@ python-lsp-server[all]
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
*Note:* This does mean, you would have a =tox.ini= with this line:
|
*Note:* This does mean, you would have a =tox.ini= with this line:
|
||||||
#+BEGIN_SRC conf
|
#+begin_src conf
|
||||||
[tox]
|
[tox]
|
||||||
minversion = 1.6
|
minversion = 1.6
|
||||||
skipsdist = True
|
skipsdist = True
|
||||||
|
@ -146,7 +145,7 @@ python-lsp-server[all]
|
||||||
commands = stestr run {posargs}
|
commands = stestr run {posargs}
|
||||||
stestr slowest
|
stestr slowest
|
||||||
# ...
|
# ...
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Pyright
|
*** Pyright
|
||||||
I’m using the Microsoft-supported [[https://github.com/Microsoft/pyright][pyright]] package instead. Adding this to my =requirements.txt= files:
|
I’m using the Microsoft-supported [[https://github.com/Microsoft/pyright][pyright]] package instead. Adding this to my =requirements.txt= files:
|
||||||
#+begin_src conf :tangle no
|
#+begin_src conf :tangle no
|
||||||
|
@ -155,16 +154,16 @@ pyright
|
||||||
|
|
||||||
The [[https://github.com/emacs-lsp/lsp-pyright][pyright package]] works with LSP.
|
The [[https://github.com/emacs-lsp/lsp-pyright][pyright package]] works with LSP.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package lsp-pyright
|
(use-package lsp-pyright
|
||||||
:hook (python-mode . (lambda () (require 'lsp-pyright)))
|
:hook (python-mode . (lambda () (require 'lsp-pyright)))
|
||||||
:init (when (executable-find "python3")
|
:init (when (executable-find "python3")
|
||||||
(setq lsp-pyright-python-executable-cmd "python3")))
|
(setq lsp-pyright-python-executable-cmd "python3")))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* LSP Integration of Python
|
* LSP Integration of Python
|
||||||
Now that the [[file:ha-programming.org::*Language Server Protocol (LSP) Integration][LSP Integration]] is complete, we can stitch the two projects together, by calling =lsp=. I oscillate between automatically turning on LSP mode with every Python file, but I sometimes run into issues when starting, so I turn it on with ~SPC m w s~.
|
Now that the [[file:ha-programming.org::*Language Server Protocol (LSP) Integration][LSP Integration]] is complete, we can stitch the two projects together, by calling =lsp=. I oscillate between automatically turning on LSP mode with every Python file, but I sometimes run into issues when starting, so I turn it on with ~SPC m w s~.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package lsp-mode
|
(use-package lsp-mode
|
||||||
;; :hook ((python-mode . lsp)))
|
;; :hook ((python-mode . lsp)))
|
||||||
:config
|
:config
|
||||||
|
@ -258,11 +257,11 @@ Now that the [[file:ha-programming.org::*Language Server Protocol (LSP) Integrat
|
||||||
"wq" '("shutdown server" . lsp-workspace-shutdown)
|
"wq" '("shutdown server" . lsp-workspace-shutdown)
|
||||||
"wr" '("restart server" . lsp-workspace-restart)
|
"wr" '("restart server" . lsp-workspace-restart)
|
||||||
"ws" '("start server" . lsp)))
|
"ws" '("start server" . lsp)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Project Configuration
|
* Project Configuration
|
||||||
I work with a lot of projects with my team where I need to /configure/ the project such that LSP and my Emacs setup works. Let's suppose I could point a function at a project directory, and have it /set it up/:
|
I work with a lot of projects with my team where I need to /configure/ the project such that LSP and my Emacs setup works. Let's suppose I could point a function at a project directory, and have it /set it up/:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-python-configure-project (proj-directory)
|
(defun ha-python-configure-project (proj-directory)
|
||||||
"Configure PROJ-DIRECTORY for LSP and Python."
|
"Configure PROJ-DIRECTORY for LSP and Python."
|
||||||
(interactive "DPython Project: ")
|
(interactive "DPython Project: ")
|
||||||
|
@ -302,14 +301,14 @@ I work with a lot of projects with my team where I need to /configure/ the proje
|
||||||
(unless (f-exists? ".dir-locals.el")
|
(unless (f-exists? ".dir-locals.el")
|
||||||
(with-temp-file ".dir-locals.el"
|
(with-temp-file ".dir-locals.el"
|
||||||
(insert "((nil . ((projectile-enable-caching . t))))")))))
|
(insert "((nil . ((projectile-enable-caching . t))))")))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's =provide= a name so we can =require= this file:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-programming-python)
|
(provide 'ha-programming-python)
|
||||||
;;; ha-programming-python.el ends here
|
;;; ha-programming-python.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: A literate programming file for configuring Python.
|
#+DESCRIPTION: A literate programming file for configuring Python.
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Programming in Scheme for SICP
|
#+TITLE: Programming in Scheme for SICP
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2022-03-01
|
#+DATE: 2022-03-01
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file configuring Emacs.
|
A literate programming file configuring Emacs.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-programming-scheme --- Configuration for Scheme. -*- lexical-binding: t; -*-
|
;;; ha-programming-scheme --- Configuration for Scheme. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2022 Howard X. Abrams
|
;; © 2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,22 +22,21 @@ A literate programming file configuring Emacs.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Introduction
|
* Introduction
|
||||||
First, install MIT-Scheme, the Lisp dialect used throughout the SICP book:
|
First, install MIT-Scheme, the Lisp dialect used throughout the SICP book:
|
||||||
=brew install mit-scheme= or =sudo apt install mit-scheme= .
|
=brew install mit-scheme= or =sudo apt install mit-scheme= .
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
brew install mit-scheme
|
brew install mit-scheme
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Or better yet, let’s use Guile:
|
Or better yet, let’s use Guile:
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
brew install guile
|
brew install guile
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Geiser (Scheme Interface)
|
* Geiser (Scheme Interface)
|
||||||
The [[https://www.nongnu.org/geiser/][geiser project]] attempts to be the interface between Emacs and various Schemes. Since I can’t decide which to use, I’ll install/configure them all.
|
The [[https://www.nongnu.org/geiser/][geiser project]] attempts to be the interface between Emacs and all the Schemes in the world. Since I can’t decide which to use, I’ll install/configure them all.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(use-package geiser
|
(use-package geiser
|
||||||
:init
|
:init
|
||||||
(setq geiser-mit-binary "/usr/local/bin/scheme"
|
(setq geiser-mit-binary "/usr/local/bin/scheme"
|
||||||
|
@ -50,22 +48,22 @@ The [[https://www.nongnu.org/geiser/][geiser project]] attempts to be the interf
|
||||||
(use-package geiser-mit)
|
(use-package geiser-mit)
|
||||||
(use-package geiser-guile)
|
(use-package geiser-guile)
|
||||||
(use-package geiser-racket))
|
(use-package geiser-racket))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Org Mode
|
** Org Mode
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:header-args:scheme: :session *scheming* :results value replace
|
:header-args:scheme: :session *scheming* :results value replace
|
||||||
:END:
|
:END:
|
||||||
Do we need a Scheme work for Org Babel? According to [[https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-scheme.html][this document]], we just need to make sure we add the =:session= variable to start the REPL.
|
Do we need a Scheme work for Org Babel? According to [[https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-scheme.html][this document]], we just need to make sure we add the =:session= variable to start the REPL.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ob-scheme
|
(use-package ob-scheme
|
||||||
:straight (:type built-in)
|
:straight (:type built-in)
|
||||||
:config
|
:config
|
||||||
(add-to-list 'org-babel-load-languages '(scheme . t)))
|
(add-to-list 'org-babel-load-languages '(scheme . t)))
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Since the version of Scheme hasn't been updated with the deprecation, and subsequent removal of =org-babel-get-header=, we include it here:
|
Since the version of Scheme hasn't been updated with the deprecation, and subsequent removal of =org-babel-get-header=, we include it here:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun org-babel-get-header (params key &optional others)
|
(defun org-babel-get-header (params key &optional others)
|
||||||
(delq nil
|
(delq nil
|
||||||
(mapcar
|
(mapcar
|
||||||
|
@ -73,80 +71,80 @@ Since the version of Scheme hasn't been updated with the deprecation, and subseq
|
||||||
params)))
|
params)))
|
||||||
|
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let’s test it out by defining a variable:
|
Let’s test it out by defining a variable:
|
||||||
#+BEGIN_SRC scheme
|
#+begin_src scheme
|
||||||
(define a 42)
|
(define a 42)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
And simply using it:
|
And simply using it:
|
||||||
#+BEGIN_SRC scheme :var b=8
|
#+begin_src scheme :var b=8
|
||||||
(+ a b)
|
(+ a b)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
: ;Value: 50
|
: ;Value: 50
|
||||||
|
|
||||||
And what about Scheme-specific stuff needed for SICP?
|
And what about Scheme-specific stuff needed for SICP?
|
||||||
#+BEGIN_SRC scheme
|
#+begin_src scheme
|
||||||
(inc 42)
|
(inc 42)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Install SICP
|
** Install SICP
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:header-args:scheme: :session sicp :results value replace
|
:header-args:scheme: :session sicp :results value replace
|
||||||
:END:
|
:END:
|
||||||
Let’s get the book available as an Info page:
|
Let’s get the book available as an Info page:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package sicp)
|
(use-package sicp)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Still having difficulty getting the Scheme REPL to output the results back into this document. Let’s try Racket...
|
Still having difficulty getting the Scheme REPL to output the results back into this document. Let’s try Racket...
|
||||||
|
|
||||||
Normally, I would just [[info:SICP][read the book]], however, if we want to read the [[file:~/.emacs.d/straight/build/sicp/sicp.info][sicp.info]] file, we need this, at least, temporarily:
|
Normally, I would just [[info:SICP][read the book]], however, if we want to read the [[file:~/.emacs.d/straight/build/sicp/sicp.info][sicp.info]] file, we need this, at least, temporarily:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-to-list 'auto-mode-alist '("\\.info\\'" . Info-mode))
|
(add-to-list 'auto-mode-alist '("\\.info\\'" . Info-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Racket
|
* Racket
|
||||||
Actually, let’s do this with [[https://racket-lang.org/][Racket]]:
|
Actually, let’s do this with [[https://racket-lang.org/][Racket]]:
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
brew install racket
|
brew install racket
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
While Racket, as a Scheme, should work with Geiser (below), let’s also get [[https://racket-mode.com/][racket-mode]] working:
|
While Racket, as a Scheme, should work with Geiser (below), let’s also get [[https://racket-mode.com/][racket-mode]] working:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package racket-mode
|
(use-package racket-mode
|
||||||
:config (setq racket-program "/usr/local/bin/racket"))
|
:config (setq racket-program "/usr/local/bin/racket"))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Can we get Racket working with Org?
|
Can we get Racket working with Org?
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ob-racket
|
(use-package ob-racket
|
||||||
:straight (:type git :protocol ssh :host github :repo "DEADB17/ob-racket")
|
:straight (:type git :protocol ssh :host github :repo "DEADB17/ob-racket")
|
||||||
:after org
|
:after org
|
||||||
:config
|
:config
|
||||||
(add-to-list 'org-babel-load-languages '(racket . t)))
|
(add-to-list 'org-babel-load-languages '(racket . t)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Try It Out
|
** Try It Out
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:HEADER-ARGS:racket: :session racketeering :results value replace :lang racket
|
:HEADER-ARGS:racket: :session racketeering :results value replace :lang racket
|
||||||
:END:
|
:END:
|
||||||
Working for values?
|
Working for values?
|
||||||
#+BEGIN_SRC racket
|
#+begin_src racket
|
||||||
(* 6 7)
|
(* 6 7)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
: 42
|
: 42
|
||||||
|
|
||||||
Working for output?
|
Working for output?
|
||||||
#+BEGIN_SRC racket :results output replace
|
#+begin_src racket :results output replace
|
||||||
(define str-1 "hello")
|
(define str-1 "hello")
|
||||||
(define str-2 "world")
|
(define str-2 "world")
|
||||||
(define all (string-join (list str-1 str-2) ", "))
|
(define all (string-join (list str-1 str-2) ", "))
|
||||||
(display (string-titlecase all))
|
(display (string-titlecase all))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
: Hello, World
|
: Hello, World
|
||||||
|
@ -158,16 +156,16 @@ The interface is horrendously slow, as the =:session= doesn’t seem to work, an
|
||||||
:header-args:racket: :session *rsicp* :results value replace :lang sicp
|
:header-args:racket: :session *rsicp* :results value replace :lang sicp
|
||||||
:END:
|
:END:
|
||||||
If using [[https://docs.racket-lang.org/sicp-manual/SICP_Language.html][Racket for SICP]], install the SICP language:
|
If using [[https://docs.racket-lang.org/sicp-manual/SICP_Language.html][Racket for SICP]], install the SICP language:
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
raco pkg install --auto --update-deps sicp
|
raco pkg install --auto --update-deps sicp
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
We now can give it a =#lang sicp= (or better yet, use the =:lang= header) to define certain SICP-specify features:
|
We now can give it a =#lang sicp= (or better yet, use the =:lang= header) to define certain SICP-specify features:
|
||||||
|
|
||||||
Let’s try this now:
|
Let’s try this now:
|
||||||
#+BEGIN_SRC racket
|
#+begin_src racket
|
||||||
(inc 42)
|
(inc 42)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
: 43
|
: 43
|
||||||
|
@ -175,10 +173,10 @@ Let’s try this now:
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's =provide= a name so we can =require= this file:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-programming-scheme)
|
(provide 'ha-programming-scheme)
|
||||||
;;; ha-programming-scheme.el ends here
|
;;; ha-programming-scheme.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: A literate programming file configuring Emacs.
|
#+DESCRIPTION: A literate programming file configuring Emacs.
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: General Programming Configuration
|
#+TITLE: General Programming Configuration
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-10-26
|
#+DATE: 2020-10-26
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate programming file for helping me program.
|
A literate programming file for helping me program.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; general-programming --- Configuration for general languages. -*- lexical-binding: t; -*-
|
;;; general-programming --- Configuration for general languages. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,24 +22,22 @@ A literate programming file for helping me program.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Introduction
|
* Introduction
|
||||||
|
Seems that all programming interfaces and workflows behave similarly. One other helper routine is a =general= macro for org-mode files:
|
||||||
Seems that all programming interfaces and workflows behave similarly. However, one other helper routine is a =general= macro for org-mode files:
|
#+begin_src emacs-lisp
|
||||||
#+BEGIN_SRC emacs-lisp
|
|
||||||
(general-create-definer ha-prog-leader
|
(general-create-definer ha-prog-leader
|
||||||
:states '(normal visual motion)
|
:states '(normal visual motion)
|
||||||
:keymaps 'prog-mode-map
|
:keymaps 'prog-mode-map
|
||||||
:prefix "SPC m"
|
:prefix "SPC m"
|
||||||
:global-prefix "<f17>"
|
:global-prefix "<f17>"
|
||||||
:non-normal-prefix "S-SPC")
|
:non-normal-prefix "S-SPC")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* General
|
* General
|
||||||
The following work for all programming languages.
|
The following work for all programming languages.
|
||||||
** direnv
|
** direnv
|
||||||
Farm off commands into /virtual environments/:
|
Farm off commands into /virtual environments/:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package direnv
|
(use-package direnv
|
||||||
:init
|
:init
|
||||||
(setq direnv--executable "/usr/local/bin/direnv"
|
(setq direnv--executable "/usr/local/bin/direnv"
|
||||||
|
@ -48,18 +45,18 @@ Farm off commands into /virtual environments/:
|
||||||
direnv-show-paths-in-summary t)
|
direnv-show-paths-in-summary t)
|
||||||
:config
|
:config
|
||||||
(direnv-mode))
|
(direnv-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Spell Checking Comments
|
** Spell Checking Comments
|
||||||
The [[https://www.emacswiki.org/emacs/FlySpell#h5o-2][flyspell-prog-mode]] checks for misspellings in comments.
|
The [[https://www.emacswiki.org/emacs/FlySpell#h5o-2][flyspell-prog-mode]] checks for misspellings in comments.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package flyspell
|
(use-package flyspell
|
||||||
:hook (prog-mode . flyspell-prog-mode))
|
:hook (prog-mode . flyspell-prog-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Flycheck
|
** Flycheck
|
||||||
Why use [[https://www.flycheck.org/][flycheck]] over the built-in =flymake=? Speed used to be the advantage, but I’m now pushing much of this to LSP, so speed is less of an issue. What about when I am not using LSP? Also, since I’ve hooked grammar checkers, I need this with global keybindings.
|
Why use [[https://www.flycheck.org/][flycheck]] over the built-in =flymake=? Speed used to be the advantage, but I’m now pushing much of this to LSP, so speed is less of an issue. What about when I am not using LSP? Also, since I’ve hooked grammar checkers, I need this with global keybindings.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package flycheck
|
(use-package flycheck
|
||||||
:init
|
:init
|
||||||
(setq next-error-message-highlight t)
|
(setq next-error-message-highlight t)
|
||||||
|
@ -96,17 +93,17 @@ Why use [[https://www.flycheck.org/][flycheck]] over the built-in =flymake=? Spe
|
||||||
"P v" '("verify-setup" . flycheck-verify-setup)
|
"P v" '("verify-setup" . flycheck-verify-setup)
|
||||||
"P x" '("disable-checker" . flycheck-disable-checker)
|
"P x" '("disable-checker" . flycheck-disable-checker)
|
||||||
"P t" '("toggle flycheck" . flycheck-mode)))
|
"P t" '("toggle flycheck" . flycheck-mode)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Documentation
|
** Documentation
|
||||||
I’ve used the [[http://kapeli.com/][Dash]] API Documentation browser (an external application) with Emacs, available for Mac.
|
I’ve used the [[http://kapeli.com/][Dash]] API Documentation browser (an external application) with Emacs, available for Mac.
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package dash-at-point
|
(use-package dash-at-point
|
||||||
:commands (dash-at-point)
|
:commands (dash-at-point)
|
||||||
:general (:states 'normal "gD" 'dash-at-point))
|
:general (:states 'normal "gD" 'dash-at-point))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
I’m interested in using [[https://devdocs.io/][devdocs]] instead, which is similar, but keeps it all /inside/ Emacs (and works on my Linux system). Two Emacs projects compete for this position. The Emacs [[https://github.com/astoff/devdocs.el][devdocs]] project is active, and seems to work well. Its advantage is a special mode for moving around the documentation.
|
I’m interested in using [[https://devdocs.io/][devdocs]] instead, which is similar, but keeps it all /inside/ Emacs (and works on my Linux system). Two Emacs projects compete for this position. The Emacs [[https://github.com/astoff/devdocs.el][devdocs]] project is active, and seems to work well. Its advantage is a special mode for moving around the documentation.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package devdocs
|
(use-package devdocs
|
||||||
:after evil
|
:after evil
|
||||||
:general (:states 'normal "gD" 'devdocs-lookup)
|
:general (:states 'normal "gD" 'devdocs-lookup)
|
||||||
|
@ -120,11 +117,11 @@ I’m interested in using [[https://devdocs.io/][devdocs]] instead, which is sim
|
||||||
"d u" '("update" . devdocs-update-all)
|
"d u" '("update" . devdocs-update-all)
|
||||||
"d x" '("uninstall" . devdocs-delete)
|
"d x" '("uninstall" . devdocs-delete)
|
||||||
"d s" '("search" . devdocs-search)))
|
"d s" '("search" . devdocs-search)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The [[https://github.com/blahgeek/emacs-devdocs-browser][devdocs-browser]] project acts similar, but with slightly different command names. Its advantage is that it allows for downloading docs and having it available offline, in fact, you can’t search for a function, until you download its pack. This is slightly faster because of this.
|
The [[https://github.com/blahgeek/emacs-devdocs-browser][devdocs-browser]] project acts similar, but with slightly different command names. Its advantage is that it allows for downloading docs and having it available offline, in fact, you can’t search for a function, until you download its pack. This is slightly faster because of this.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package devdocs-browser
|
(use-package devdocs-browser
|
||||||
:general (:states 'normal "gD" 'devdocs-browser-open)
|
:general (:states 'normal "gD" 'devdocs-browser-open)
|
||||||
|
|
||||||
|
@ -140,10 +137,10 @@ The [[https://github.com/blahgeek/emacs-devdocs-browser][devdocs-browser]] proje
|
||||||
"d U" '("upgrade" . devdocs-browser-upgrade-doc)
|
"d U" '("upgrade" . devdocs-browser-upgrade-doc)
|
||||||
"d o" '("download" . devdocs-browser-download-offline-data)
|
"d o" '("download" . devdocs-browser-download-offline-data)
|
||||||
"d O" '("remove download" . devdocs-browser-remove-offline-data)))
|
"d O" '("remove download" . devdocs-browser-remove-offline-data)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Code Folding
|
** Code Folding
|
||||||
While Emacs has many options for viewing and moving around code, sometimes, it is nice to /collapse/ all functions, and then start to expand them one at a time. For this, we could enable the built-in [[https://www.emacswiki.org/emacs/HideShow][hide-show feature]]:
|
While Emacs has options for viewing and moving around code, sometimes, we could /collapse/ all functions, and then start to expand them one at a time. For this, we could enable the built-in [[https://www.emacswiki.org/emacs/HideShow][hide-show feature]]:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package hide-show
|
(use-package hide-show
|
||||||
:straight (:type built-in)
|
:straight (:type built-in)
|
||||||
:init
|
:init
|
||||||
|
@ -151,14 +148,14 @@ While Emacs has many options for viewing and moving around code, sometimes, it i
|
||||||
hs-hide-initial-comment-block t
|
hs-hide-initial-comment-block t
|
||||||
hs-isearch-open t)
|
hs-isearch-open t)
|
||||||
:hook (prog-mode . hs-minor-mode))
|
:hook (prog-mode . hs-minor-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
However, hide-show doesn’t work with complex YAML files. The [[https://github.com/gregsexton/origami.el][origami]] mode works better /out-of-the-box/, as it works with Python and Lisp, but falls back to indents as the format, which works really well.
|
Note that =hide-show= doesn’t work with complex YAML files. The [[https://github.com/gregsexton/origami.el][origami]] mode works better /out-of-the-box/, as it works with Python and Lisp, but falls back to indents as the format, which works well.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package origami
|
(use-package origami
|
||||||
:init
|
:init
|
||||||
(setq origami-fold-replacement "⤵")
|
(setq origami-fold-replacement "⤵")
|
||||||
:hook (prog-mode . origami-mode))
|
:hook (prog-mode . origami-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
To take advantage of this, type:
|
To take advantage of this, type:
|
||||||
- ~z m~ :: To collapse everything
|
- ~z m~ :: To collapse everything
|
||||||
- ~z r~ :: To open everything
|
- ~z r~ :: To open everything
|
||||||
|
@ -171,7 +168,7 @@ Note: Yes, we could use [[https://github.com/mrkkrp/vimish-fold][vimish-fold]] (
|
||||||
The [[https://microsoft.github.io/language-server-protocol/][LSP]] is a way to connect /editors/ (like Emacs) to /languages/ (like Lisp)… wait, no, it was originally designed for VS Code and probably Python, but we now abstract away [[https://github.com/davidhalter/jedi][Jedi]] and the [[http://tkf.github.io/emacs-jedi/latest/][Emacs integration to Jedi]] (and duplicate everything for Ruby, and Clojure, and…).
|
The [[https://microsoft.github.io/language-server-protocol/][LSP]] is a way to connect /editors/ (like Emacs) to /languages/ (like Lisp)… wait, no, it was originally designed for VS Code and probably Python, but we now abstract away [[https://github.com/davidhalter/jedi][Jedi]] and the [[http://tkf.github.io/emacs-jedi/latest/][Emacs integration to Jedi]] (and duplicate everything for Ruby, and Clojure, and…).
|
||||||
|
|
||||||
Instead, we install [[https://emacs-lsp.github.io/lsp-mode/][LSP Mode]] (and friends), which simplifies my configuration:
|
Instead, we install [[https://emacs-lsp.github.io/lsp-mode/][LSP Mode]] (and friends), which simplifies my configuration:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package lsp-mode
|
(use-package lsp-mode
|
||||||
:commands lsp
|
:commands lsp
|
||||||
:init
|
:init
|
||||||
|
@ -181,12 +178,12 @@ Instead, we install [[https://emacs-lsp.github.io/lsp-mode/][LSP Mode]] (and fri
|
||||||
company-idle-delay 0.0 ; Are thing fast enough to do this?
|
company-idle-delay 0.0 ; Are thing fast enough to do this?
|
||||||
lsp-keymap-prefix "s-m")
|
lsp-keymap-prefix "s-m")
|
||||||
:hook ((lsp-mode . lsp-enable-which-key-integration)))
|
:hook ((lsp-mode . lsp-enable-which-key-integration)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
I will want to start adding commands under my =SPC m= mode-specific key sequence leader, but in the meantime, all LSP-related keybindings are available under ~⌘-m~. See [[https://emacs-lsp.github.io/lsp-mode/page/keybindings/][this page]] for the default keybindings.
|
I will want to start adding commands under my =SPC m= mode-specific key sequence leader, but in the meantime, all LSP-related keybindings are available under ~⌘-m~. See [[https://emacs-lsp.github.io/lsp-mode/page/keybindings/][this page]] for the default keybindings.
|
||||||
*** UI
|
*** UI
|
||||||
The [[https://github.com/emacs-lsp/lsp-ui][lsp-ui]] project offers much of the display and interface to LSP:
|
The [[https://github.com/emacs-lsp/lsp-ui][lsp-ui]] project offers much of the display and interface to LSP:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package lsp-ui
|
(use-package lsp-ui
|
||||||
:commands lsp-ui-mode
|
:commands lsp-ui-mode
|
||||||
:config
|
:config
|
||||||
|
@ -194,15 +191,15 @@ The [[https://github.com/emacs-lsp/lsp-ui][lsp-ui]] project offers much of the d
|
||||||
lsp-ui-sideline-show-hover t
|
lsp-ui-sideline-show-hover t
|
||||||
lsp-ui-sideline-show-diagnostics t)
|
lsp-ui-sideline-show-diagnostics t)
|
||||||
:hook (lsp-mode . lsp-ui-mode))
|
:hook (lsp-mode . lsp-ui-mode))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Company Completion
|
*** Company Completion
|
||||||
The [[https://github.com/tigersoldier/company-lsp][company-lsp]] offers a [[http://company-mode.github.io/][company]] completion backend for [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]]:
|
The [[https://github.com/tigersoldier/company-lsp][company-lsp]] offers a [[http://company-mode.github.io/][company]] completion backend for [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]]:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package company-lsp
|
(use-package company-lsp
|
||||||
:config
|
:config
|
||||||
(push 'company-lsp company-backends))
|
(push 'company-lsp company-backends))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
To options that might be interesting:
|
To options that might be interesting:
|
||||||
- =company-lsp-async=: When set to non-nil, fetch completion candidates asynchronously.
|
- =company-lsp-async=: When set to non-nil, fetch completion candidates asynchronously.
|
||||||
- =company-lsp-enable-snippet=: Set it to non-nil if you want to enable snippet expansion on completion. Set it to nil to disable this feature.
|
- =company-lsp-enable-snippet=: Set it to non-nil if you want to enable snippet expansion on completion. Set it to nil to disable this feature.
|
||||||
|
@ -210,7 +207,7 @@ To options that might be interesting:
|
||||||
*** iMenu
|
*** iMenu
|
||||||
The [[https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-imenu.el][lsp-imenu]] project offers a =lsp-ui-imenu= function for jumping to functions:
|
The [[https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-imenu.el][lsp-imenu]] project offers a =lsp-ui-imenu= function for jumping to functions:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package lsp-ui-imenu
|
(use-package lsp-ui-imenu
|
||||||
:straight nil
|
:straight nil
|
||||||
:after lsp-ui
|
:after lsp-ui
|
||||||
|
@ -219,35 +216,35 @@ The [[https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-imenu.el][lsp-imenu
|
||||||
"g" '(:ignore t :which-key "goto")
|
"g" '(:ignore t :which-key "goto")
|
||||||
"g m" '("imenu" . lsp-ui-imenu))
|
"g m" '("imenu" . lsp-ui-imenu))
|
||||||
(add-hook 'lsp-after-open-hook 'lsp-enable-imenu))
|
(add-hook 'lsp-after-open-hook 'lsp-enable-imenu))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Treemacs
|
*** Treemacs
|
||||||
The [[https://github.com/emacs-lsp/lsp-treemacs][lsp-treemacs]] offers a project-specific structure oriented to the code:
|
The [[https://github.com/emacs-lsp/lsp-treemacs][lsp-treemacs]] offers a project-specific structure oriented to the code:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package lsp-treemacs
|
(use-package lsp-treemacs
|
||||||
:config
|
:config
|
||||||
(ha-prog-leader
|
(ha-prog-leader
|
||||||
"0" '("treemacs" . lsp-treemacs-symbols)))
|
"0" '("treemacs" . lsp-treemacs-symbols)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Origami Folding
|
*** Origami Folding
|
||||||
The [[https://github.com/emacs-lsp/lsp-origami][lsp-origami]] project integrates the [[https://github.com/gregsexton/origami.el][origami]] project with LSP for /better code folding/:
|
The [[https://github.com/emacs-lsp/lsp-origami][lsp-origami]] project integrates the [[https://github.com/gregsexton/origami.el][origami]] project with LSP for /better code folding/:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package lsp-origami
|
(use-package lsp-origami
|
||||||
:hook (lsp-after-open . lsp-origami-try-enable))
|
:hook (lsp-after-open . lsp-origami-try-enable))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*** Debugging
|
*** Debugging
|
||||||
Do we want to use a debugger?
|
Do we want to use a debugger?
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package dap-mode
|
(use-package dap-mode
|
||||||
:init
|
:init
|
||||||
(require 'dap-python))
|
(require 'dap-python))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Function Call Notifications
|
** Function Call Notifications
|
||||||
As I've mentioned [[http://www.howardism.org/Technical/Emacs/beep-for-emacs.html][on my website]], I've created a [[file:~/website/Technical/Emacs/beep-for-emacs.org][beep function]] that notifies when long running processes complete.
|
As I've mentioned [[http://www.howardism.org/Technical/Emacs/beep-for-emacs.html][on my website]], I've created a [[file:~/website/Technical/Emacs/beep-for-emacs.org][beep function]] that notifies when long running processes complete.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package alert
|
(use-package alert
|
||||||
:init
|
:init
|
||||||
(setq alert-default-style
|
(setq alert-default-style
|
||||||
|
@ -265,20 +262,20 @@ As I've mentioned [[http://www.howardism.org/Technical/Emacs/beep-for-emacs.html
|
||||||
compile
|
compile
|
||||||
shell-command))
|
shell-command))
|
||||||
(advice-add func :around #'beep-when-runs-too-long)))
|
(advice-add func :around #'beep-when-runs-too-long)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
While that code /advices/ the publishing and compile commands, I may want to add more.
|
While that code /advices/ the publishing and compile commands, I may want to add more.
|
||||||
** iEdit
|
** iEdit
|
||||||
While there are language-specific ways to rename variables and functions, [[https://github.com/victorhge/iedit][iedit]] is often sufficient.
|
While there are language-specific ways to rename variables and functions, [[https://github.com/victorhge/iedit][iedit]] is often sufficient.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package iedit
|
(use-package iedit
|
||||||
:config
|
:config
|
||||||
(ha-leader "s e" '("iedit" . iedit-mode)))
|
(ha-leader "s e" '("iedit" . iedit-mode)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Commenting
|
** Commenting
|
||||||
I like =comment-dwim= (~M-;~), and I like =comment-box=, but I have an odd personal style that I like to codify:
|
I like =comment-dwim= (~M-;~), and I like =comment-box=, but I have an odd personal style that I like to codify:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-comment-line (&optional start end)
|
(defun ha-comment-line (&optional start end)
|
||||||
(interactive "r")
|
(interactive "r")
|
||||||
(when (or (null start) (not (region-active-p)))
|
(when (or (null start) (not (region-active-p)))
|
||||||
|
@ -293,14 +290,14 @@ I like =comment-dwim= (~M-;~), and I like =comment-box=, but I have an odd perso
|
||||||
(insert "\n------------------------------------------------------------------------")
|
(insert "\n------------------------------------------------------------------------")
|
||||||
(comment-region (point-min) (point-max))
|
(comment-region (point-min) (point-max))
|
||||||
(widen)))
|
(widen)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
And a keybinding:
|
And a keybinding:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-prog-leader "c" '("comment line" . ha-comment-line))
|
(ha-prog-leader "c" '("comment line" . ha-comment-line))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Evaluation
|
** Evaluation
|
||||||
While I like [[help:eval-print-last-sexp][eval-print-last-sexp]], I would like a bit of formatting in order to /keep the results/ in the file.
|
While I like [[help:eval-print-last-sexp][eval-print-last-sexp]], I would like a bit of formatting in order to /keep the results/ in the file.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-eval-print-last-sexp (&optional internal-arg)
|
(defun ha-eval-print-last-sexp (&optional internal-arg)
|
||||||
"Evaluate the expression located before the point.
|
"Evaluate the expression located before the point.
|
||||||
The results are inserted back into the buffer at the end
|
The results are inserted back into the buffer at the end
|
||||||
|
@ -315,10 +312,10 @@ While I like [[help:eval-print-last-sexp][eval-print-last-sexp]], I would like a
|
||||||
(dotimes (i 2)
|
(dotimes (i 2)
|
||||||
(next-line)
|
(next-line)
|
||||||
(join-line)))
|
(join-line)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Typical keybindings for all programming modes:
|
Typical keybindings for all programming modes:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-prog-leader
|
(ha-prog-leader
|
||||||
"e" '(:ignore t :which-key "eval")
|
"e" '(:ignore t :which-key "eval")
|
||||||
"e ;" '("expression" . eval-expression)
|
"e ;" '("expression" . eval-expression)
|
||||||
|
@ -327,10 +324,10 @@ Typical keybindings for all programming modes:
|
||||||
"e r" '("region" . eval-region)
|
"e r" '("region" . eval-region)
|
||||||
"e e" '("last s-exp" . eval-last-sexp)
|
"e e" '("last s-exp" . eval-last-sexp)
|
||||||
"e p" '("print s-exp" . ha-eval-print-last-sexp))
|
"e p" '("print s-exp" . ha-eval-print-last-sexp))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
** Ligatures
|
** Ligatures
|
||||||
The idea of using math symbols for a programming languages keywords is /cute/, but can be confusing, so I use it sparingly:
|
The idea of using math symbols for a programming languages keywords is /cute/, but can be confusing, so I use it sparingly:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-prettify-prog ()
|
(defun ha-prettify-prog ()
|
||||||
"Extends the `prettify-symbols-alist' for programming."
|
"Extends the `prettify-symbols-alist' for programming."
|
||||||
(mapc (lambda (pair) (push pair prettify-symbols-alist))
|
(mapc (lambda (pair) (push pair prettify-symbols-alist))
|
||||||
|
@ -341,83 +338,83 @@ The idea of using math symbols for a programming languages keywords is /cute/, b
|
||||||
(prettify-symbols-mode))
|
(prettify-symbols-mode))
|
||||||
|
|
||||||
(add-hook 'prog-mode-hook 'ha-prettify-prog)
|
(add-hook 'prog-mode-hook 'ha-prettify-prog)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
Eventually, I want to follow [[https://www.masteringemacs.org/article/unicode-ligatures-color-emoji][Mickey Petersen's essay]] on getting full ligatures working, but right now, they don’t work on the Mac, and that is my current workhorse.
|
Eventually, I want to follow [[https://www.masteringemacs.org/article/unicode-ligatures-color-emoji][Mickey Petersen's essay]] on getting full ligatures working, but right now, they don’t work on the Mac, and that is my current workhorse.
|
||||||
** Task Runner
|
** Task Runner
|
||||||
I've replaced my home-grown compilation list code with a more versatile [[https://github.com/emacs-taskrunner/emacs-taskrunner][Taskrunner project]].
|
I've replaced my home-grown compilation list code with a more versatile [[https://github.com/emacs-taskrunner/emacs-taskrunner][Taskrunner project]].
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(setq ivy-taskrunner-notifications-on t
|
(setq ivy-taskrunner-notifications-on t
|
||||||
ivy-taskrunner-doit-bin-path "/usr/local/bin/doit")
|
ivy-taskrunner-doit-bin-path "/usr/local/bin/doit")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Doom provides basic support, but we need more keybindings:
|
Doom provides basic support, but we need more keybindings:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(map! :leader :prefix "p"
|
(map! :leader :prefix "p"
|
||||||
:desc "Project tasks" "Z" 'ivy-taskrunner
|
:desc "Project tasks" "Z" 'ivy-taskrunner
|
||||||
:desc "Reun last task" "z" 'ivy-taskrunner-rerun-last-command)
|
:desc "Reun last task" "z" 'ivy-taskrunner-rerun-last-command)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
While my company is typically using =Rakefile= and =Makefile= in the top-level project, I want to have my personal tasks set per-project as well. For that, I thought about using [[https://pydoit.org/][doit]], where I would just create a =dodo.py= file that contains:
|
While my company is typically using =Rakefile= and =Makefile= in the top-level project, I want to have my personal tasks set per-project as well. For that, I thought about using [[https://pydoit.org/][doit]], where I would just create a =dodo.py= file that contains:
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle no
|
#+begin_src python :tangle no
|
||||||
def hello():
|
def hello():
|
||||||
"""This command greets you."""
|
"""This command greets you."""
|
||||||
return {
|
return {
|
||||||
'actions': [ 'echo hello' ],
|
'actions': [ 'echo hello' ],
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Display Configuration
|
** Display Configuration
|
||||||
Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications:
|
Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package doom-modeline
|
(use-package doom-modeline
|
||||||
:config
|
:config
|
||||||
(setq doom-modeline-lsp t
|
(setq doom-modeline-lsp t
|
||||||
doom-modeline-env-version t))
|
doom-modeline-env-version t))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Languages
|
* Languages
|
||||||
Simple to configure languages go here. More advanced stuff will go in their own files… eventually.
|
Simple to configure languages go here. More advanced stuff will go in their own files… eventually.
|
||||||
** Ansible
|
** Ansible
|
||||||
Doing a lot of [[https://github.com/yoshiki/yaml-mode][YAML work]], but this project needs a new maintainer.
|
Doing a lot of [[https://github.com/yoshiki/yaml-mode][YAML work]], but this project needs a new maintainer.
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package yaml-mode
|
(use-package yaml-mode
|
||||||
:mode (rx ".y" (optional "a") "ml" string-end))
|
:mode (rx ".y" (optional "a") "ml" string-end))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Ansible uses Jinja, so we install the [[https://github.com/paradoxxxzero/jinja2-mode][jinja2-mode]]:
|
Ansible uses Jinja, so we install the [[https://github.com/paradoxxxzero/jinja2-mode][jinja2-mode]]:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package jinja2-mode
|
(use-package jinja2-mode
|
||||||
:mode (rx ".j2" string-end))
|
:mode (rx ".j2" string-end))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Do I consider all YAML files an Ansible file needing [[https://github.com/k1LoW/emacs-ansible][ansible-mode]]?
|
Do I consider all YAML files an Ansible file needing [[https://github.com/k1LoW/emacs-ansible][ansible-mode]]?
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ansible
|
(use-package ansible
|
||||||
:init
|
:init
|
||||||
(setq ansible-vault-password-file "~/.ansible-vault-passfile")
|
(setq ansible-vault-password-file "~/.ansible-vault-passfile")
|
||||||
;; :hook (yaml-mode . ansible-mode)
|
;; :hook (yaml-mode . ansible-mode)
|
||||||
:config
|
:config
|
||||||
(ha-leader "t y" 'ansible))
|
(ha-leader "t y" 'ansible))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
The [[help:ansible-vault-password-file][ansible-vault-password-file]] variable needs to change /per project/, so let’s use the =.dir-locals.el= file, for instance:
|
The [[help:ansible-vault-password-file][ansible-vault-password-file]] variable needs to change /per project/, so let’s use the =.dir-locals.el= file, for instance:
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
((nil . ((ansible-vault-password-file . "playbooks/.vault-password"))))
|
((nil . ((ansible-vault-password-file . "playbooks/.vault-password"))))
|
||||||
|
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
However, let’s have all YAML files able to access Ansible’s documentation using the [[https://github.com/emacsorphanage/ansible-doc][ansible-doc]] project:
|
However, let’s have all YAML files able to access Ansible’s documentation using the [[https://github.com/emacsorphanage/ansible-doc][ansible-doc]] project:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ansible-doc
|
(use-package ansible-doc
|
||||||
:hook (yaml-mode . ansible-doc-mode)
|
:hook (yaml-mode . ansible-doc-mode)
|
||||||
:config
|
:config
|
||||||
(ha-local-leader :keymaps 'yaml-mode-map
|
(ha-local-leader :keymaps 'yaml-mode-map
|
||||||
"d" '(:ignore t :which-key "docs")
|
"d" '(:ignore t :which-key "docs")
|
||||||
"d d" 'ansible-doc))
|
"d d" 'ansible-doc))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The [[https://github.com/emacsmirror/poly-ansible][poly-ansible]] project uses [[https://polymode.github.io/][polymode]], gluing [[https://github.com/paradoxxxzero/jinja2-mode][jinja2-mode]] into [[https://github.com/yoshiki/yaml-mode][yaml-mode]].
|
The [[https://github.com/emacsmirror/poly-ansible][poly-ansible]] project uses [[https://polymode.github.io/][polymode]], gluing [[https://github.com/paradoxxxzero/jinja2-mode][jinja2-mode]] into [[https://github.com/yoshiki/yaml-mode][yaml-mode]].
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package polymode)
|
(use-package polymode)
|
||||||
|
|
||||||
(use-package poly-ansible
|
(use-package poly-ansible
|
||||||
|
@ -425,7 +422,7 @@ The [[https://github.com/emacsmirror/poly-ansible][poly-ansible]] project uses [
|
||||||
:straight (:host github :repo "emacsmirror/poly-ansible")
|
:straight (:host github :repo "emacsmirror/poly-ansible")
|
||||||
:hook ((yaml-mode . poly-ansible-mode)
|
:hook ((yaml-mode . poly-ansible-mode)
|
||||||
(poly-ansible-mode . font-lock-update)))
|
(poly-ansible-mode . font-lock-update)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Shell Scripts
|
** Shell Scripts
|
||||||
|
|
||||||
|
@ -433,7 +430,7 @@ While I don't like writing them, I can't get away from them.
|
||||||
|
|
||||||
While filename extensions work fine most of the time, I don't like to pre-pend =.sh= to the few shell scripts I write, and instead, would like to associate =shell-mode= with all files in a =bin= directory:
|
While filename extensions work fine most of the time, I don't like to pre-pend =.sh= to the few shell scripts I write, and instead, would like to associate =shell-mode= with all files in a =bin= directory:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package sh-mode
|
(use-package sh-mode
|
||||||
:straight (:type built-in)
|
:straight (:type built-in)
|
||||||
:mode (rx (or (seq ".sh" eol)
|
:mode (rx (or (seq ".sh" eol)
|
||||||
|
@ -443,24 +440,23 @@ While filename extensions work fine most of the time, I don't like to pre-pend =
|
||||||
"/bin/")) "sh-mode.sh")
|
"/bin/")) "sh-mode.sh")
|
||||||
:hook
|
:hook
|
||||||
(after-save . executable-make-buffer-file-executable-if-script-p))
|
(after-save . executable-make-buffer-file-executable-if-script-p))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
*Note:* we make the script /executable/ by default. See [[https://emacsredux.com/blog/2021/09/29/make-script-files-executable-automatically/][this essay]] for details, but it appears that the executable bit is only turned on if the script has a shebang at the top of the file.
|
*Note:* we make the script /executable/ by default. See [[https://emacsredux.com/blog/2021/09/29/make-script-files-executable-automatically/][this essay]] for details, but it appears that the executable bit is only turned on if the script has a shebang at the top of the file.
|
||||||
** Fish Shell
|
** Fish Shell
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package fish-mode
|
(use-package fish-mode
|
||||||
:mode (rx ".fish" eol)
|
:mode (rx ".fish" eol)
|
||||||
:config
|
:config
|
||||||
(ha-auto-insert-file (rx ".fish") "fish-mode.sh")
|
(ha-auto-insert-file (rx ".fish") "fish-mode.sh")
|
||||||
:hook
|
:hook
|
||||||
(fish-mode . (lambda () (add-hook 'before-save-hook 'fish_indent-before-save))))
|
(fish-mode . (lambda () (add-hook 'before-save-hook 'fish_indent-before-save))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Provide a name in order to =require= this code.
|
Provide a name to =require= this code.
|
||||||
|
#+begin_src emacs-lisp :exports none
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
|
||||||
(provide 'ha-programming)
|
(provide 'ha-programming)
|
||||||
;;; ha-programming.el ends here
|
;;; ha-programming.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
117
ha-remoting.org
117
ha-remoting.org
|
@ -1,15 +1,14 @@
|
||||||
#+TITLE: Remote Access to Systems
|
#+TITLE: Remote Access to Systems
|
||||||
#+AUTHOR: Howard X. Abrams
|
#+AUTHOR: Howard X. Abrams
|
||||||
#+DATE: 2020-09-25
|
#+DATE: 2020-09-25
|
||||||
#+FILETAGS: :emacs:
|
|
||||||
|
|
||||||
A literate configuration for accessing remote systems.
|
A literate configuration for accessing remote systems.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; ha-remoting --- Accessing remote systems. -*- lexical-binding: t; -*-
|
;;; ha-remoting --- Accessing remote systems. -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © 2020-2022 Howard X. Abrams
|
;; © 2020-2022 Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
@ -23,14 +22,14 @@ A literate configuration for accessing remote systems.
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Local Terminals
|
* Local Terminals
|
||||||
The following section configures my Terminal experience, both inside and outside Emacs.
|
The following section configures my Terminal experience, both inside and outside Emacs.
|
||||||
** Eshell
|
** Eshell
|
||||||
I used to use [[http://www.howardism.org/Technical/Emacs/eshell.html][Eshell all the time]], but now I've migrated most of /work/ directly into Emacs (rewriting all those shell scripts a Emacs Lisp code). However, a shell is pretty good for my brain at organizing files (old habits, maybe).
|
I used to use [[http://www.howardism.org/Technical/Emacs/eshell.html][Eshell all the time]], but now I've migrated most of /work/ directly into Emacs (rewriting all those shell scripts a Emacs Lisp code). A shell is pretty good for my brain at organizing files (old habits, maybe).
|
||||||
|
|
||||||
First, my /aliases/ follow me around, and the following creates the alias file, =~/.emacs.d/eshell/alias=:
|
First, my /aliases/ follow me around, and the following creates the alias file, =~/.emacs.d/eshell/alias=:
|
||||||
#+BEGIN_SRC shell :tangle (identity eshell-aliases-file) :mkdirp yes
|
#+begin_src shell :tangle (identity eshell-aliases-file) :mkdirp yes
|
||||||
alias ll ls -l $*
|
alias ll ls -l $*
|
||||||
alias clear recenter 0
|
alias clear recenter 0
|
||||||
alias emacs 'find-file $1'
|
alias emacs 'find-file $1'
|
||||||
|
@ -38,10 +37,10 @@ First, my /aliases/ follow me around, and the following creates the alias file,
|
||||||
alias ee 'find-file-other-window $1'
|
alias ee 'find-file-other-window $1'
|
||||||
alias grep 'rg -n -H --no-heading -e "$*"'
|
alias grep 'rg -n -H --no-heading -e "$*"'
|
||||||
alias find 'echo Please use fd instead.' # :-)
|
alias find 'echo Please use fd instead.' # :-)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Since that file already exists (probably), the following command may not be necessary:
|
Since that file already exists (probably), the following command may not be necessary:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package eshell
|
(use-package eshell
|
||||||
:custom
|
:custom
|
||||||
(eshell-kill-on-exit t)
|
(eshell-kill-on-exit t)
|
||||||
|
@ -49,11 +48,11 @@ Since that file already exists (probably), the following command may not be nece
|
||||||
|
|
||||||
:hook
|
:hook
|
||||||
(eshell-exit . (lambda () (delete-window))))
|
(eshell-exit . (lambda () (delete-window))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
I usually want a new window running Eshell, that is smaller than the current buffer:
|
I usually want a new window running Eshell, that is smaller than the current buffer:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun eshell-there (parent)
|
(defun eshell-there (parent)
|
||||||
"Open an eshell session in a PARENT directory
|
"Open an eshell session in a PARENT directory
|
||||||
in a smaller window named after this directory."
|
in a smaller window named after this directory."
|
||||||
|
@ -68,10 +67,10 @@ I usually want a new window running Eshell, that is smaller than the current buf
|
||||||
|
|
||||||
(insert (concat "ls"))
|
(insert (concat "ls"))
|
||||||
(eshell-send-input)))
|
(eshell-send-input)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
We either want to start the shell in the same parent as the current buffer, or at the root of the project:
|
We either want to start the shell in the same parent as the current buffer, or at the root of the project:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun eshell-here ()
|
(defun eshell-here ()
|
||||||
"Opens up a new shell in the directory associated with the
|
"Opens up a new shell in the directory associated with the
|
||||||
current buffer's file. Rename the eshell buffer name to match
|
current buffer's file. Rename the eshell buffer name to match
|
||||||
|
@ -85,10 +84,10 @@ We either want to start the shell in the same parent as the current buffer, or a
|
||||||
"Open a new shell in the project root directory, in a smaller window."
|
"Open a new shell in the project root directory, in a smaller window."
|
||||||
(interactive)
|
(interactive)
|
||||||
(eshell-there (projectile-project-root)))
|
(eshell-there (projectile-project-root)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Add my org-specific predicates, see this [[http://www.howardism.org/Technical/Emacs/eshell-fun.html][this essay]] for the details:
|
Add my org-specific predicates, see this [[http://www.howardism.org/Technical/Emacs/eshell-fun.html][this essay]] for the details:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun eshell-org-file-tags ()
|
(defun eshell-org-file-tags ()
|
||||||
"Helps the eshell parse the text the point is currently on,
|
"Helps the eshell parse the text the point is currently on,
|
||||||
looking for parameters surrounded in single quotes. Returns a
|
looking for parameters surrounded in single quotes. Returns a
|
||||||
|
@ -119,7 +118,7 @@ Add my org-specific predicates, see this [[http://www.howardism.org/Technical/Em
|
||||||
(defvar eshell-predicate-alist nil
|
(defvar eshell-predicate-alist nil
|
||||||
"A list of predicates than can be applied to a globbing pattern.")
|
"A list of predicates than can be applied to a globbing pattern.")
|
||||||
(add-to-list 'eshell-predicate-alist '(?T . (eshell-org-file-tags)))
|
(add-to-list 'eshell-predicate-alist '(?T . (eshell-org-file-tags)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Remote Terminals
|
* Remote Terminals
|
||||||
Sure =iTerm= is nice for connecting and running commands on remote systems, however, it lacks a command line option that allows you to select and manipulate the displayed text without a mouse. This is where Emacs can shine.
|
Sure =iTerm= is nice for connecting and running commands on remote systems, however, it lacks a command line option that allows you to select and manipulate the displayed text without a mouse. This is where Emacs can shine.
|
||||||
|
|
||||||
|
@ -129,9 +128,9 @@ When calling the =ha-ssh= function, it opens a =vterm= window which, unlike othe
|
||||||
|
|
||||||
Preload a list of favorite/special hostnames with multiple calls to:
|
Preload a list of favorite/special hostnames with multiple calls to:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(ha-ssh-add-favorite-host "Devbox 42" "10.0.1.42")
|
(ha-ssh-add-favorite-host "Devbox 42" "10.0.1.42")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Then calling =ha-ssh= function, a list of hostnames is available to quickly jump on a system (with the possibility of fuzzy matching if you have Helm or Ivy installed).
|
Then calling =ha-ssh= function, a list of hostnames is available to quickly jump on a system (with the possibility of fuzzy matching if you have Helm or Ivy installed).
|
||||||
|
|
||||||
|
@ -145,14 +144,14 @@ Use the /favorite host/ list to quickly edit a file on a remote system using Tra
|
||||||
|
|
||||||
Working with remote shell connections programmatically, for instance:
|
Working with remote shell connections programmatically, for instance:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(let ((win-name "some-host"))
|
(let ((win-name "some-host"))
|
||||||
(ha-ssh "some-host.in.some.place" win-name)
|
(ha-ssh "some-host.in.some.place" win-name)
|
||||||
(ha-ssh-send "source ~/.bash_profile" win-name)
|
(ha-ssh-send "source ~/.bash_profile" win-name)
|
||||||
(ha-ssh-send "clear" win-name))
|
(ha-ssh-send "clear" win-name))
|
||||||
;; ...
|
;; ...
|
||||||
(ha-ssh-exit win-name)
|
(ha-ssh-exit win-name)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Actually the =win-name= in this case is optional, as it will use a good default.
|
Actually the =win-name= in this case is optional, as it will use a good default.
|
||||||
|
|
||||||
|
@ -163,7 +162,7 @@ I'm not giving up on Eshell, but I am playing around with [[https://github.com/a
|
||||||
|
|
||||||
VTerm has an issue (at least for me) with ~M-Backspace~ not deleting the previous word, and yeah, I want to make sure that both keystrokes do the same thing.
|
VTerm has an issue (at least for me) with ~M-Backspace~ not deleting the previous word, and yeah, I want to make sure that both keystrokes do the same thing.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package vterm
|
(use-package vterm
|
||||||
:init
|
:init
|
||||||
(setq vterm-shell "/usr/local/bin/fish")
|
(setq vterm-shell "/usr/local/bin/fish")
|
||||||
|
@ -178,7 +177,7 @@ VTerm has an issue (at least for me) with ~M-Backspace~ not deleting the previou
|
||||||
(lambda () (interactive) (vterm-send-key (kbd "C-w")))))
|
(lambda () (interactive) (vterm-send-key (kbd "C-w")))))
|
||||||
|
|
||||||
(advice-add 'vterm-copy-mode :after 'evil-normal-state))
|
(advice-add 'vterm-copy-mode :after 'evil-normal-state))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The advantage of running terminals in Emacs is the ability to copy text without a mouse. For that, hit ~C-c C-t~ to enter a special copy-mode. If I go into this mode, I might as well also go into normal mode to move the cursor.
|
The advantage of running terminals in Emacs is the ability to copy text without a mouse. For that, hit ~C-c C-t~ to enter a special copy-mode. If I go into this mode, I might as well also go into normal mode to move the cursor.
|
||||||
|
|
||||||
|
@ -188,7 +187,7 @@ Hrm. Seems that I might want a function to copy the output of the last command t
|
||||||
** Variables
|
** Variables
|
||||||
Let's begin by defining some variables used for communication between the functions.
|
Let's begin by defining some variables used for communication between the functions.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defvar ha-latest-ssh-window-name nil
|
(defvar ha-latest-ssh-window-name nil
|
||||||
"The window-name of the latest ssh session. Most commands default to the last session.")
|
"The window-name of the latest ssh session. Most commands default to the last session.")
|
||||||
|
|
||||||
|
@ -197,19 +196,19 @@ Let's begin by defining some variables used for communication between the functi
|
||||||
(defvar ha-ssh-favorite-hostnames '()
|
(defvar ha-ssh-favorite-hostnames '()
|
||||||
"A list of tuples (associate list) containing a hostname and its IP address.
|
"A list of tuples (associate list) containing a hostname and its IP address.
|
||||||
See =ha-ssh-add-favorite-host= for easily adding to this list.")
|
See =ha-ssh-add-favorite-host= for easily adding to this list.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Also, let's make it easy for me to change my default shell:
|
Also, let's make it easy for me to change my default shell:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defvar ha-ssh-shell (shell-command-to-string "type -p fish")
|
(defvar ha-ssh-shell (shell-command-to-string "type -p fish")
|
||||||
"The executable to the shell I want to use locally.")
|
"The executable to the shell I want to use locally.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Interactive Interface to Remote Systems
|
** Interactive Interface to Remote Systems
|
||||||
|
|
||||||
The function, =ha-ssh= pops up a list of /favorite hosts/ and then uses the =vterm= functions to automatically SSH into the chosen host:
|
The function, =ha-ssh= pops up a list of /favorite hosts/ and then uses the =vterm= functions to automatically SSH into the chosen host:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh (hostname &optional window-name)
|
(defun ha-ssh (hostname &optional window-name)
|
||||||
"Start a SSH session to a given HOSTNAME (with an optionally specified WINDOW-NAME).
|
"Start a SSH session to a given HOSTNAME (with an optionally specified WINDOW-NAME).
|
||||||
If called interactively, it presents the user with a list
|
If called interactively, it presents the user with a list
|
||||||
|
@ -228,11 +227,11 @@ returned by =ha-ssh-choose-host=."
|
||||||
(vterm-send-return))
|
(vterm-send-return))
|
||||||
|
|
||||||
(pop-to-buffer ha-latest-ssh-window-name))
|
(pop-to-buffer ha-latest-ssh-window-name))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Of course, we need a function that =interactive= can call to get that list, and my thought is to call =helm= if it is available, otherwise, assume that ido/ivy will take over the =completing-read= function:
|
Of course, we need a function that =interactive= can call to get that list, and my thought is to call =helm= if it is available, otherwise, assume that ido/ivy will take over the =completing-read= function:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-choose-host ()
|
(defun ha-ssh-choose-host ()
|
||||||
"Prompts the user for a host, and if it is in the cache, return
|
"Prompts the user for a host, and if it is in the cache, return
|
||||||
its IP address, otherwise, return the input given.
|
its IP address, otherwise, return the input given.
|
||||||
|
@ -246,11 +245,11 @@ This is used in calls to =interactive= to select a host."
|
||||||
:fuzzy t :history ha-ssh-host-history)
|
:fuzzy t :history ha-ssh-host-history)
|
||||||
(completing-read "Hostname: " ha-ssh-favorite-hostnames nil 'confirm nil 'ha-ssh-host-history))))
|
(completing-read "Hostname: " ha-ssh-favorite-hostnames nil 'confirm nil 'ha-ssh-host-history))))
|
||||||
(alist-get hostname ha-ssh-favorite-hostnames hostname nil 'equal)))
|
(alist-get hostname ha-ssh-favorite-hostnames hostname nil 'equal)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Simply calling =vterm= fails to load my full environment, so this allows me to start the terminal in a particular directory (defaulting to the root of the current project):
|
Simply calling =vterm= fails to load my full environment, so this allows me to start the terminal in a particular directory (defaulting to the root of the current project):
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-shell (&optional directory)
|
(defun ha-shell (&optional directory)
|
||||||
"Creates and tidies up a =vterm= terminal shell in side window."
|
"Creates and tidies up a =vterm= terminal shell in side window."
|
||||||
(interactive (list (read-directory-name "Starting Directory: " (projectile-project-root))))
|
(interactive (list (read-directory-name "Starting Directory: " (projectile-project-root))))
|
||||||
|
@ -264,22 +263,22 @@ Simply calling =vterm= fails to load my full environment, so this allows me to s
|
||||||
;; (ha-ssh-send "source ~/.bash_profile" buf-name)
|
;; (ha-ssh-send "source ~/.bash_profile" buf-name)
|
||||||
;; (ha-ssh-send "clear" buf-name)
|
;; (ha-ssh-send "clear" buf-name)
|
||||||
)))
|
)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before we leave this section, I realize that I would like a way to /add/ to my list of hosts:
|
Before we leave this section, I realize that I would like a way to /add/ to my list of hosts:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-add-favorite-host (hostname ip-address)
|
(defun ha-ssh-add-favorite-host (hostname ip-address)
|
||||||
"Add a favorite host to your list for easy pickin's."
|
"Add a favorite host to your list for easy pickin's."
|
||||||
(interactive "sHostname: \nsIP Address: ")
|
(interactive "sHostname: \nsIP Address: ")
|
||||||
(add-to-list 'ha-ssh-favorite-hostnames (cons hostname ip-address)))
|
(add-to-list 'ha-ssh-favorite-hostnames (cons hostname ip-address)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Programmatic Interface
|
** Programmatic Interface
|
||||||
|
|
||||||
The previous functions (as well as my own end of sprint demonstrations) often need to issue some commands to a running terminal session, which is a simple wrapper around a /send text/ and /send return/ sequence:
|
The previous functions (as well as my own end of sprint demonstrations) often need to issue some commands to a running terminal session, which is a simple wrapper around a /send text/ and /send return/ sequence:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-send (phrase &optional window-name)
|
(defun ha-ssh-send (phrase &optional window-name)
|
||||||
"Send command PHRASE to the currently running SSH instance.
|
"Send command PHRASE to the currently running SSH instance.
|
||||||
If you want to refer to another session, specify the correct WINDOW-NAME.
|
If you want to refer to another session, specify the correct WINDOW-NAME.
|
||||||
|
@ -296,11 +295,11 @@ This is really useful for scripts and demonstrations."
|
||||||
(progn
|
(progn
|
||||||
(term-send-raw-string phrase)
|
(term-send-raw-string phrase)
|
||||||
(term-send-input))))
|
(term-send-input))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
On the rare occasion that I write a shell script, or at least, need to execute some one-line shell commands from some document, I have a function that combines a /read line from buffer/ and then send it to the currently running terminal:
|
On the rare occasion that I write a shell script, or at least, need to execute some one-line shell commands from some document, I have a function that combines a /read line from buffer/ and then send it to the currently running terminal:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-send-line ()
|
(defun ha-ssh-send-line ()
|
||||||
"Copy the contents of the current line in the current buffer,
|
"Copy the contents of the current line in the current buffer,
|
||||||
and call =ha-ssh-send= with it. After sending the contents, it
|
and call =ha-ssh-send= with it. After sending the contents, it
|
||||||
|
@ -314,11 +313,11 @@ returns to the current line."
|
||||||
(ha-ssh-send trim-cmd)
|
(ha-ssh-send trim-cmd)
|
||||||
;; (sit-for 0.25)
|
;; (sit-for 0.25)
|
||||||
(pop-to-buffer buf)))
|
(pop-to-buffer buf)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Let's have a quick way to bugger out of the terminal:
|
Let's have a quick way to bugger out of the terminal:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-exit (&optional window-name)
|
(defun ha-ssh-exit (&optional window-name)
|
||||||
"End the SSH session specified by WINDOW-NAME (or if not, the latest session)."
|
"End the SSH session specified by WINDOW-NAME (or if not, the latest session)."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -331,13 +330,13 @@ Let's have a quick way to bugger out of the terminal:
|
||||||
(term-send-eof))
|
(term-send-eof))
|
||||||
(kill-buffer window-name)
|
(kill-buffer window-name)
|
||||||
(delete-window))
|
(delete-window))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** Editing Remote Files
|
** Editing Remote Files
|
||||||
|
|
||||||
TRAMP, when it works, is amazing that we can give it a reference to a remote directory, and have =find-file= magically autocomplete.
|
TRAMP, when it works, is amazing that we can give it a reference to a remote directory, and have =find-file= magically autocomplete.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-find-file (hostname)
|
(defun ha-ssh-find-file (hostname)
|
||||||
"Constructs a ssh-based, tramp-focus, file reference, and then calls =find-file=."
|
"Constructs a ssh-based, tramp-focus, file reference, and then calls =find-file=."
|
||||||
(interactive (list (ha-ssh-choose-host)))
|
(interactive (list (ha-ssh-choose-host)))
|
||||||
|
@ -351,18 +350,18 @@ TRAMP, when it works, is amazing that we can give it a reference to a remote dir
|
||||||
(if other-window
|
(if other-window
|
||||||
(find-file-other-window tramp-file)
|
(find-file-other-window tramp-file)
|
||||||
(find-file tramp-file))))
|
(find-file tramp-file))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
We can even edit it as root:
|
We can even edit it as root:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-find-root (hostname)
|
(defun ha-ssh-find-root (hostname)
|
||||||
"Constructs a ssh-based, tramp-focus, file reference, and then calls =find-file=."
|
"Constructs a ssh-based, tramp-focus, file reference, and then calls =find-file=."
|
||||||
(interactive (list (ha-ssh-choose-host)))
|
(interactive (list (ha-ssh-choose-host)))
|
||||||
(let ((tramp-ssh-ref (format "/ssh:%s|sudo:%s:" hostname hostname))
|
(let ((tramp-ssh-ref (format "/ssh:%s|sudo:%s:" hostname hostname))
|
||||||
(other-window (when (equal current-prefix-arg '(4)) t)))
|
(other-window (when (equal current-prefix-arg '(4)) t)))
|
||||||
(ha-ssh--find-file tramp-ssh-ref other-window)))
|
(ha-ssh--find-file tramp-ssh-ref other-window)))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
** OpenStack Interface
|
** OpenStack Interface
|
||||||
|
|
||||||
|
@ -370,20 +369,20 @@ Instead of making sure I have a list of remote systems already in the favorite h
|
||||||
|
|
||||||
We'll give =openstack= CLI a =--format json= option to make it easier for parsing:
|
We'll give =openstack= CLI a =--format json= option to make it easier for parsing:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package json)
|
(use-package json)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Need a variable to hold all our interesting hosts. Notice I use the word /overcloud/, but this is a name I've used for years to refer to /my virtual machines/ that I can get a listing of, and not get other VMs that I don't own.
|
Need a variable to hold all our interesting hosts. Notice I use the word /overcloud/, but this is a name I've used for years to refer to /my virtual machines/ that I can get a listing of, and not get other VMs that I don't own.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defvar ha-ssh-overcloud-cache-data nil
|
(defvar ha-ssh-overcloud-cache-data nil
|
||||||
"A vector of associated lists containing the servers in an Overcloud.")
|
"A vector of associated lists containing the servers in an Overcloud.")
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
If our cache data is empty, we could automatically retrieve this information, but only on the first time we attempt to connect. To do this, we'll =advice= the =ha-ssh-choose-host= function defined earlier:
|
If our cache data is empty, we could automatically retrieve this information, but only on the first time we attempt to connect. To do this, we'll =advice= the =ha-ssh-choose-host= function defined earlier:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-overcloud-query-for-hosts ()
|
(defun ha-ssh-overcloud-query-for-hosts ()
|
||||||
"If the overcloud cache hasn't be populated, ask the user if we want to run the command."
|
"If the overcloud cache hasn't be populated, ask the user if we want to run the command."
|
||||||
(when (not ha-ssh-overcloud-cache-data)
|
(when (not ha-ssh-overcloud-cache-data)
|
||||||
|
@ -391,11 +390,11 @@ If our cache data is empty, we could automatically retrieve this information, bu
|
||||||
(call-interactively 'ha-ssh-overcloud-cache-populate))))
|
(call-interactively 'ha-ssh-overcloud-cache-populate))))
|
||||||
|
|
||||||
(advice-add 'ha-ssh-choose-host :before 'ha-ssh-overcloud-query-for-hosts)
|
(advice-add 'ha-ssh-choose-host :before 'ha-ssh-overcloud-query-for-hosts)
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
We'll do the work of getting the /server list/ with this function:
|
We'll do the work of getting the /server list/ with this function:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-overcloud-cache-populate (cluster)
|
(defun ha-ssh-overcloud-cache-populate (cluster)
|
||||||
"Given an `os-cloud' entry, stores all available hostnames.
|
"Given an `os-cloud' entry, stores all available hostnames.
|
||||||
Calls `ha-ssh-add-favorite-host' for each host found."
|
Calls `ha-ssh-add-favorite-host' for each host found."
|
||||||
|
@ -412,21 +411,21 @@ We'll do the work of getting the /server list/ with this function:
|
||||||
(alist-get 'cedev13)
|
(alist-get 'cedev13)
|
||||||
(seq-first))))
|
(seq-first))))
|
||||||
(message "Call to `openstack' complete. Found %d hosts." (length json-data))))
|
(message "Call to `openstack' complete. Found %d hosts." (length json-data))))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
In case I change my virtual machines, I can repopulate that cache:
|
In case I change my virtual machines, I can repopulate that cache:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-overcloud-cache-repopulate ()
|
(defun ha-ssh-overcloud-cache-repopulate ()
|
||||||
"Repopulate the cache based on redeployment of my overcloud."
|
"Repopulate the cache based on redeployment of my overcloud."
|
||||||
(interactive)
|
(interactive)
|
||||||
(setq ha-ssh-overcloud-cache-data nil)
|
(setq ha-ssh-overcloud-cache-data nil)
|
||||||
(call-interactively 'ha-ssh-overcloud-cache-populate))
|
(call-interactively 'ha-ssh-overcloud-cache-populate))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
The primary interface:
|
The primary interface:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-ssh-overcloud (hostname)
|
(defun ha-ssh-overcloud (hostname)
|
||||||
"Log into an overcloud host given by HOSTNAME. Works better if
|
"Log into an overcloud host given by HOSTNAME. Works better if
|
||||||
you have previously run =ssh-copy-id= on the host. Remember, to
|
you have previously run =ssh-copy-id= on the host. Remember, to
|
||||||
|
@ -446,11 +445,11 @@ Emacs), hit =C-c C-k=."
|
||||||
(ha-ssh-send (format "export PS1='\\[\\e[34m\\]%s\\[\e[m\\] \\[\\e[33m\\]\\$\\[\\e[m\\] '"
|
(ha-ssh-send (format "export PS1='\\[\\e[34m\\]%s\\[\e[m\\] \\[\\e[33m\\]\\$\\[\\e[m\\] '"
|
||||||
window-label))
|
window-label))
|
||||||
(ha-ssh-send "clear")))
|
(ha-ssh-send "clear")))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Keybindings
|
* Keybindings
|
||||||
This file, so far, as been good-enough for a Vanilla Emacs installation, but to hook into Doom's leader for some sequence binding, this code isn't:
|
This file, so far, as been good-enough for a Vanilla Emacs installation, but to hook into Doom's leader for some sequence binding, this code isn't:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader
|
(ha-leader
|
||||||
"a e" '("eshell" . eshell-here)
|
"a e" '("eshell" . eshell-here)
|
||||||
"a E" '("top eshell" . eshell-project)
|
"a E" '("top eshell" . eshell-project)
|
||||||
|
@ -463,15 +462,15 @@ This file, so far, as been good-enough for a Vanilla Emacs installation, but to
|
||||||
"a s q" '("quit shell" . ha-ssh-exit)
|
"a s q" '("quit shell" . ha-ssh-exit)
|
||||||
"a s f" '("find-file" . ha-ssh-find-file)
|
"a s f" '("find-file" . ha-ssh-find-file)
|
||||||
"a s r" '("find-root" . ha-ssh-find-root))
|
"a s r" '("find-root" . ha-ssh-find-root))
|
||||||
#+END_SRC
|
#+end_src
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
|
|
||||||
Provide a name so we can =require= the file:
|
Provide a name so we can =require= the file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide 'ha-remoting)
|
(provide 'ha-remoting)
|
||||||
;;; ha-remoting.el ends here
|
;;; ha-remoting.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||||
|
|
||||||
|
|
|
@ -14,23 +14,25 @@
|
||||||
|
|
||||||
${2:A literate programming file configuring Emacs.}
|
${2:A literate programming file configuring Emacs.}
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; `(file-name-base (buffer-file-name)))`.el --- $2 -*- lexical-binding: t; -*-
|
;;; `(file-name-base (buffer-file-name)))`.el --- $2 -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; Copyright (C) `(format-time-string "%Y")` `user-full-name`
|
;; © `(format-time-string "%Y")` `user-full-name`
|
||||||
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;; Author: `user-full-name` <http://gitlab.com/howardabrams>
|
;; Author: `user-full-name` <http://gitlab.com/howardabrams>
|
||||||
;; Maintainer: `user-full-name` <`user-mail-address`>
|
;; Maintainer: `user-full-name` <`user-mail-address`>
|
||||||
;; Created: `(format-time-string "%B %e, %Y")`
|
;; Created: `(format-time-string "%B %e, %Y")`
|
||||||
;;
|
;;
|
||||||
;; This file is not part of GNU Emacs.
|
;; While obvious, GNU Emacs does not include this file
|
||||||
;;
|
;;
|
||||||
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
||||||
;; `(buffer-file-name)`
|
;; `(buffer-file-name)`
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Introduction
|
* Introduction
|
||||||
|
|
||||||
|
@ -40,12 +42,11 @@ $0
|
||||||
|
|
||||||
Let's provide a name so that the file can be required:
|
Let's provide a name so that the file can be required:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide '`(file-name-base (buffer-file-name)))`)
|
(provide '`(file-name-base (buffer-file-name)))`)
|
||||||
;;; `(file-name-base (buffer-file-name)))`.el ends here
|
;;; `(file-name-base (buffer-file-name)))`.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
|
||||||
|
|
||||||
#+DESCRIPTION: $2
|
#+DESCRIPTION: $2
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
# name: code-block
|
# name: code-block
|
||||||
# key: <s
|
# key: <s
|
||||||
# --
|
# --
|
||||||
#+BEGIN_SRC $1
|
#+begin_src $1
|
||||||
$0
|
$0
|
||||||
#+END_SRC
|
#+end_src
|
|
@ -2,6 +2,6 @@
|
||||||
# name: emacs-lisp-code
|
# name: emacs-lisp-code
|
||||||
# key: <sl
|
# key: <sl
|
||||||
# --
|
# --
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
$0
|
$0
|
||||||
#+END_SRC
|
#+end_src
|
|
@ -2,6 +2,6 @@
|
||||||
# name: example-block
|
# name: example-block
|
||||||
# key: <e
|
# key: <e
|
||||||
# --
|
# --
|
||||||
#+BEGIN_EXAMPLE
|
#+begin_example
|
||||||
$0
|
$0
|
||||||
#+END_EXAMPLE
|
#+end_example
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
# key: <g
|
# key: <g
|
||||||
# --
|
# --
|
||||||
|
|
||||||
#+BEGIN_SRC dot :file ${1:`(file-name-base (buffer-file-name)))`-`(ha-org-next-image-number)`}.${2:png} :exports file :results file
|
#+begin_src dot :file ${1:`(file-name-base (buffer-file-name)))`-`(ha-org-next-image-number)`}.${2:png} :exports file :results file
|
||||||
digraph G {
|
digraph G {
|
||||||
${0:A -> B};
|
${0:A -> B};
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+ATTR_ORG: :width 800px
|
#+attr_org: :width 800px
|
|
@ -2,10 +2,10 @@
|
||||||
# name: header
|
# name: header
|
||||||
# key: header
|
# key: header
|
||||||
# --
|
# --
|
||||||
#+TITLE: ${1:`(replace-regexp-in-string "-" " " (capitalize (file-name-nondirectory (file-name-sans-extension (buffer-file-name)))))`}
|
#+title: ${1:`(replace-regexp-in-string "-" " " (capitalize (file-name-nondirectory (file-name-sans-extension (buffer-file-name)))))`}
|
||||||
#+AUTHOR: `(user-full-name)`
|
#+author: `(user-full-name)`
|
||||||
#+EMAIL: `user-mail-address`
|
#+email: `user-mail-address`
|
||||||
#+DATE: `(format-time-string "%Y-%m-%d %B")`
|
#+date: `(format-time-string "%Y-%m-%d %B")`
|
||||||
#+TAGS: $2
|
#+tags: $2
|
||||||
|
|
||||||
$0
|
$0
|
|
@ -2,4 +2,4 @@
|
||||||
# name: name
|
# name: name
|
||||||
# key: name
|
# key: name
|
||||||
# --
|
# --
|
||||||
#+NAME: ${0}
|
#+name: ${0}
|
|
@ -5,12 +5,12 @@
|
||||||
# group: plantuml
|
# group: plantuml
|
||||||
# --
|
# --
|
||||||
|
|
||||||
#+BEGIN_SRC plantuml :file ${1:`(ha-org-next-image-number)`}.${2:png} :exports file :results file
|
#+begin_src plantuml :file ${1:`(ha-org-next-image-number)`}.${2:png} :exports file :results file
|
||||||
@startuml
|
@startuml
|
||||||
!include https://raw.githubusercontent.com/ptrkcsk/one-dark-plantuml-theme/v1.0.0/theme.puml
|
!include https://raw.githubusercontent.com/ptrkcsk/one-dark-plantuml-theme/v1.0.0/theme.puml
|
||||||
$0
|
$0
|
||||||
@enduml
|
@enduml
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+ATTR_ORG: :width 800px
|
#+attr_org: :width 800px
|
||||||
[[file:$1.$2]]
|
[[file:$1.$2]]
|
|
@ -2,6 +2,6 @@
|
||||||
# name: section-property
|
# name: section-property
|
||||||
# key: prop
|
# key: prop
|
||||||
# --
|
# --
|
||||||
:PROPERTIES:
|
:properties:
|
||||||
:header-args:${1:emacs-lisp} :${2:results} ${3:silent}
|
:header-args:${1:emacs-lisp} :${2:results} ${3:silent}
|
||||||
:END:
|
:end:
|
|
@ -2,6 +2,6 @@
|
||||||
# name: shell-script-code
|
# name: shell-script-code
|
||||||
# key: <ss
|
# key: <ss
|
||||||
# --
|
# --
|
||||||
#+BEGIN_SRC sh
|
#+begin_src sh
|
||||||
$0
|
$0
|
||||||
#+END_SRC
|
#+end_src
|
|
@ -2,4 +2,4 @@
|
||||||
# name: title
|
# name: title
|
||||||
# key: title
|
# key: title
|
||||||
# --
|
# --
|
||||||
#+TITLE: ${0}
|
#+title: ${0}
|
|
@ -1,15 +1,14 @@
|
||||||
;;; `(file-name-nondirectory (buffer-file-name))` --- $1 -*- lexical-binding: t; -*-
|
;;; `(file-name-nondirectory (buffer-file-name))` --- $1 -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © `(format-time-string "%Y")` Howard X. Abrams
|
;; © `(format-time-string "%Y")` Howard X. Abrams
|
||||||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
;;
|
;;
|
||||||
;;
|
|
||||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
;; Maintainer: Howard X. Abrams
|
;; Maintainer: Howard X. Abrams
|
||||||
;; Created: `(format-time-string "%e %B %Y")`
|
;; Created: `(format-time-string "%e %B %Y")`
|
||||||
;;
|
;;
|
||||||
;; This file is not part of GNU Emacs. Obviously. But you knew that.
|
;; Obviously, GNU Emacs does not include this file in its distribution.
|
||||||
;;
|
;;
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
;; This program is free software; you can redistribute it and/or modify
|
||||||
;; it under the terms of the GNU General Public License as published by
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
A literate programming file for ${2:configuring Emacs.}
|
A literate programming file for ${2:configuring Emacs.}
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; `(file-name-base (buffer-file-name)))` --- $2 -*- lexical-binding: t; -*-
|
;;; `(file-name-base (buffer-file-name)))` --- $2 -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
;; © `(format-time-string "%Y")` `user-full-name`
|
;; © `(format-time-string "%Y")` `user-full-name`
|
||||||
|
@ -20,27 +20,26 @@ A literate programming file for ${2:configuring Emacs.}
|
||||||
;; Maintainer: `user-full-name`
|
;; Maintainer: `user-full-name`
|
||||||
;; Created: `(format-time-string "%B %e, %Y")`
|
;; Created: `(format-time-string "%B %e, %Y")`
|
||||||
;;
|
;;
|
||||||
;; This file is not part of GNU Emacs.
|
;; While obvious, GNU Emacs does not include this file or project.
|
||||||
;;
|
;;
|
||||||
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
||||||
;; `(buffer-file-name)`
|
;; `(buffer-file-name)`
|
||||||
;; And tangle the file to recreate this one.
|
;; And tangle the file to recreate this one.
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
* Introduction
|
* Introduction
|
||||||
|
|
||||||
$0
|
$0
|
||||||
|
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
|
|
||||||
Let's =provide= a name so we can =require= this file:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
(provide '`(file-name-base (buffer-file-name)))`)
|
(provide '`(file-name-base (buffer-file-name)))`)
|
||||||
;;; `(file-name-base (buffer-file-name)))`.el ends here
|
;;; `(file-name-base (buffer-file-name)))`.el ends here
|
||||||
#+END_SRC
|
#+end_src
|
||||||
|
|
||||||
#+DESCRIPTION: $2
|
#+DESCRIPTION: $2
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue