Revisiting stenography and Twiddling

| learning, steno, twiddler, geek

I've been thinking about what I can learn alongside A+ - something that will be slow to learn but that might be fun to get the hang of. I think it will help me practise patience and develop my empathy with her as she learns fine motor skills too. Maybe I'll even be able to model persistence and self-acceptance.

At home, I practise steno on my Georgi keyboard while she does her homework, learns how to type, or writes stories. It works out pretty well, since I have to sound out words to chord them and I fingerspell slower than she types. I steno the words she wants me to spell for her, and I also steno the instructions on her homework. I steno my journal entries, too. I'd like to someday be able to write blog posts with steno. Not that I'm speed-limited now, but I'm curious about it and it's good to show A+ that I'm learning too. I made a webpage that lets me steno large text into a small textarea on my Android phone using Dotterel, displaying my cheat sheet and steno hints for the last few words using the main typeytype dictionary. That way, I can fingerspell words for A+ and then practise them as she copies the words. I'm also slowly going through The Art of Chording.

I've also dusted off my Twiddler 2 one-handed chording keyboard, since that's something I can do while looking elsewhere. Looking outside makes me feel a little happier in winter. Maybe I'll even figure out how to write while waiting for her outside, perhaps bundling up my hand in a small blanket to keep warm. I mostly remembered how to chord with my right hand using the default layout, but I wanted to experiment with alternative layouts. I started learning a modified Backspice layout, moving some letters around since I can't easily reach 000L with my short pinky. I couldn't download the Twiddler 2.1 configuration tool from the Tekgear website, so I just programmed it interactively.

To practice on the go, I set up Emacspeak in a Debian instance on UserLAnd on my Android phone, with audio output routed using pulseaudio to XServer XSDL via export PULSE_SERVER=tcp: in my UserLAnd ~/.profile. It worked surprisingly well. I could press chords and hear what letter I typed. When I pressed SPC, I heard the word read out. This was enough for me to be able to explore the layout and think of words I want to spell with the letters I've found so far. I've been having a hard time figuring out how to easily get files in and out of UserLAnd aside from scp, though, as the document provider doesn't seem to show up for me.

So I wrote a web-based tool that uses the Javascript Web Speech API to speak each letter as I type it and speak out the word after I press space–basically, the main things that I'd been using Emacspeak for. I also added a little cheat sheet that I could update on the fly, and I can have it read aloud by typing hlp and pressing SPC. I like this more self-directed, exploratory approach to learning the keymap. I press a chord and hear what letter it is, then think of words I want to spell with it and where those letters are. Here it is: twiddler.html (might not work on all browsers - I use it on Chrome on Android)

Based on conversations on Mastodon, I decided to get the Twiddler 3 Wrap + Bluetooth. I wonder if the Twiddler 3 will make it easier for me to reach the far button with my pinky finger, and I'm curious if Bluetooth can still get through however many layers I want to have so that I don't get too cold. I probably won't use the Twiddler to write stuff while ostensibly standing around with the other grown-ups at a playdate. It's good for kids to see grown-ups being friends. But if there's standing-around time while she's off being independent, or if I want to look outside, it might be interesting to use.

A+ sometimes gets frustrated with how slow writing is, or how she gets tripped up by a 3x3 perm she wants to learn. I'm glad I can slow down and learn something along with her.

2023-01-23 Emacs news

| emacs, emacs-news

[2023-01-23 Mon]: Added meetup

Links from, r/orgmode, r/spacemacs, r/planetemacs, Hacker News,,, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at Thank you!

2023-01-16 Emacs news

| emacs, emacs-news

Links from, r/orgmode, r/spacemacs, r/planetemacs, Hacker News,,, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at Thank you!

Using bug-hunter to quickly find a problem in my long Emacs configuration

| emacs

I noticed that author names in my mastodon.el timeline were no longer getting highlighted. Since it behaved correctly when I used emacs -Q, I knew the problem was somewhere in my configuration. Problem: my configuration is very long. (Uh, my .el seems to have grown to be about 460KB…) I started writing some code to help me bisect it, but fortunately I remembered using a package to do that a long time ago. After a little digging around, I found bug-hunter again. I patched it to allow me to specify a header and footer:

(defvar bug-hunter-header nil "Emacs Lisp sexp to add at the beginning of the file.")
(defvar bug-hunter-footer nil "Emacs Lisp sexp to add at the end of the file.")

(defun bug-hunter--print-to-temp (sexp)
  "Print SEXP to a temp file and return the file name."
  (let ((print-length nil)
        (print-level nil)
        (file (make-temp-file "bug-hunter")))
    (with-temp-file file
      (when bug-hunter-header (print bug-hunter-header (current-buffer)))
      (print sexp (current-buffer))
      (when bug-hunter-footer (print bug-hunter-footer (current-buffer))))

That allowed me to set up this header and footer:

(setq bug-hunter-header
         (use-package quelpa)
         (use-package quelpa-use-package)
         (use-package hydra :commands defhydra)
         (use-package use-package-hydra)))
(setq bug-hunter-footer '(load-file "/tmp/mastodon-test.el"))

where mastodon-test.el was this file:

(add-to-list 'load-path "~/vendor/mastodon.el/lisp")
(require 'mastodon)
(setq mastodon-active-user "sachac"
      mastodon-instance-url "")

I wasn't sure how to use bug-hunter's support for assertions because of the asynchronous retrieval of the Mastodon timeline, but at least I could use that code to set things up.

Then I used bug-hunter-file to split up the Emacs Lisp file tangled out of my literate configuration. All I had to do was wait for the Mastodon timeline to show up, quit Emacs, and answer y if I saw the bug or n if I didn't.

Here's what the result was:

You have asked to do an interactive hunt, here's how it goes.
1) I will start a new Emacs instance, which opens a new frame.
2) You will try to reproduce your problem on the new frame.
3) When you’re done, close that frame.
4) I will ask you if you managed to reproduce the problem.
5) We will repeat steps up to 13 times, so hang tight!
Doing some initial tests...
Initial tests done. Hunting for the cause...
"~/sync/emacs/Sacha.el", line 6893 pos 0:
  The assertion returned the following value here:
  Caused by the following expression:
    (use-package highlight-defined :ensure t :custom
      (highlight-defined-face-use-itself t)
      (help-mode . highlight-defined-mode)
      (emacs-lisp-mode . highlight-defined-mode))

That's weird, since highlight-defined shouldn't have affected mastodon, but okay. I'm going to skip using highlight-defined for now.

If you're tracking down a weird change in your Emacs configuration file, you might find bug-hunter useful too. It's available on ELPA, or you can get it from Github.

View org source for this post

Fixing my old ambiguous sketch references

| blogging, 11ty, emacs

At some point during the conversion of my blog from Wordpress to 11ty, I wanted to change my sketch links to use a custom shortcode instead of referring to the sketch in my old wp-uploads directory. Because Wordpress changed the filenames a little, I used the ID at the start of the filename. I forgot that many of my filenames from 2013 to 2015 just had the date without a uniquely identifying letter or number suffix, so many old references were ambiguous and my static site generator just linked to the first matching file. When I was listening to my old monthly reviews as part of my upcoming 10-year review, I noticed the repeated links. So I wrote these functions to help me find and replace markup of the form sketchLink "2013-10-06" with sketchLink "2013-10-06 Daily drawing - thinking on paper #drawing", replacing references to the same date with the next sketch in the list. I figured that would be enough to get the basic use case sorted out (usually a list of sketches in my monthly/weekly reviews), taking advantage of the my-list-sketches function I defined in my Emacs config.

(defun my-replace-duplicate-sketch-list-references ()
  (goto-char (point-min))
  (let (seen)
    (while (re-search-forward "sketchLink \\\"\\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\\)\\\""
                              nil t)
      (if (assoc (match-string 1) seen)
          (setcdr (assoc (match-string 1) seen) (1+ (assoc-default (match-string 1) seen)))
        (setq seen (cons (cons (match-string 1) 1) seen))))
    (mapc (lambda (entry)
            (goto-char (point-min))
            (mapc (lambda (sketch)
                    (if (re-search-forward (format "sketchLink \\\"\\(%s\\)\\\""
                                                   (regexp-quote (car entry))) nil t)
                        (replace-match (save-match-data (file-name-sans-extension sketch))
                                       nil t nil 1)
                      (message "Skipping %s possible ref to %s"
                  (my-list-sketches (concat "^" (regexp-quote (car entry))) nil '("~/sync/sketches"))))

Sometimes I needed to delete the whole list and start again:

(defun my-insert-sketch-list-between (start-date end-date)
    (lambda (f)
      (format "<li>%s sketchLink \"%s\" %s</li>\n"
              (concat "{" "%")  ; avoid confusing 11ty when I export this
              (file-name-sans-extension f)
              (concat "%" "}")))
    (sort (seq-filter
           (lambda (f) (and (string< f end-date) (not (string< f start-date))))
           (my-list-sketches nil nil '("~/sync/sketches")))

I used find-grep-dired to search for sketchLink \"[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\" and then I just used a keyboard macro to process each file.

Anyway, really old monthly reviews like this one for October 2013 should mostly make sense again. I could probably pull out the correct references from the Wordpress database backup, but what I've got is probably okay. I would probably have gotten much grumpier trying to do this without Emacs Lisp. Yay Emacs!

View org source for this post

Slow days, weeks, months, years

| life

Some days are slow. Some weeks, some months, some years… Parenting gives me a sneak peek at what life is like being slow, and that's handy. I've written about being slow before. Every time I revisit this topic, I learn a little bit more. I can start to figure out the systems and perspectives that might help me as I grow older.

One of the nice things about a slow day is that it's easy to give myself permission to dwell on all the things I gloss over on fast days. I putter around the house, tidying up. I sit with A- as she reads, and I write my thoughts by hand. I update my ledger and doublecheck my budget. I read through my backlog of books and borrow some from A-'s pile so I can keep up with her interests. I learn more about my tools and try things out. I review and update my notes. I write journal entries even for these little moments, because small steps still add up over time.

What do fast days look like? I jump into a programming task and explore an idea, turning my notes into blog posts when I can. I fly around documentation and source code. When I reach out for something, I find it. I feel proud of what I've figured out. With A- , my fast days are when I have the energy and equanimity to help us have fun while taking care of our priorities.

On slow days, I let A- take more of the lead. I might say, "My brain is having a hard time being creative right now," and then we switch to something more physical or more straightforward. When she's grumpy and I don't have the energy to help her manage her feelings, we just let the big feelings wash over us.

It helps that Emacs News and similar things are compatible with slow days, as the hardest thinking I need to do then is just which category to use. Captioning videos and adding chapter markers are also straightforward. Writing about cool stuff is easier than writing and maintaining cool stuff.

Parenting is pretty compatible with slow days, too. When I focus on A- and appreciate the things she's learning and who she is as a person, she glows. There are plenty of resources I can tap, and I don't have to be "on" all the time.

Oh, is that why knitting, gardening, and reading are popular hobbies for older people, because it gets easier to be patient with things that take a while? Oooh. I wonder if that means I might have more patience for things that require compiling or training.

I'll have other slow days in the future, and that's okay. Some people even pay big money or make huge life changes in order to learn how to live more slowly. I'd like to still be happy with myself instead of frustrated when I'm in my 70s or 80s, so I think it will be worth figuring this out (slowly).

View org source for this post

2023-01-09 Emacs news

| emacs, emacs-news

Links from, r/orgmode, r/spacemacs, r/planetemacs, Hacker News,,, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at Thank you!