January 13, 2025

ToolsTools

App Defaults 2025

This was inspired by App Defaults ldstephens and he was inspired by Hemispheric Views - App Defaults.

Mail Client: Mail()
Mail Server: Gmail
Spam: SpamSieve
Notes: Emacs
To-Do: Emacs and Reminders()
Project-management: Emacs
Diary/Journal: Emacs
iPhone Photo Shooting: Camera+ Pro Camera & Editor
Photo Management: Photos()
Image Manipulation: Acorn 8
Music Player: Music (), Swinsian
Calendar: Calendar()
Contacts: Contacts()
Cloud File Storage: iCloud(), and Dropbox
RSS: Newsblur, NetNewsWire, Emacs
Browser: Safari(), Chrome
Chat: Messages(), Telegram
Bookmarks: pinboard.in, Emacs
Read It Later: Emacs
Reading epubs: ClearView X, Kindle
Reading pdf’s: Reader, PDF Expert
Podcast: Podcasts()
Text: Emacs, iA Writer, BBEdit
Markdown Previewer: Marked 2
Launcher: Alfred
Spreadsheets: Numbers()
Shopping Lists: Emacs
Password Management: Enpass
Weather: Weather()
File Rename: Better Rename
File Search: HoudahSpot
Netword Security: Little Snitch
File Management: Hazel
Macros: Alfred, Keyboard Maestro
Clipboard: Alfred
Snippets/Text-expansion: Alfred
Keep computer awake: Amphetamine
Delete Apps: AppCleaner
Crosswords: Black Ink 2
Calculator: PCalc, Calca
Youtube Downloader: Downie
File Dump: EagleFiler
Terminal: Ghostty
Video-player: IINA
Compressor/uncompressor: Keka
Window Management: Moom
Quicklook: Peek
Mindmaps: Scapple, Emacs
Screenshot: ScreenFloat
Writing Everything: Emacs

macosxguru at the gmail thingie.

Thanks to: Photo by cottonbro studio: https://www.pexels.com/photo/silver-and-blue-metal-tools-4480531/

macOS
January 2, 2025

EmacsEmacs

Much Ado about Emacs 006

These are some of the things which got my attention last week.

Constraining the movement of the cursor in the mini-buffer

The cursor in the mini-buffer needs to be constrained from moving around. Errant arrow-keys make life difficult. This is the solution, from the documentation of Daniel Mendler’s Vertico package:

#+begin_src emacs-lisp
  (setq minibuffer-prompt-properties
        '(read-only t cursor-intangible t face minibuffer-prompt))
  (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
#+end_src

Get rid of ^M

I have the need to copy some file names in the Finder and paste into an org-mode buffer.

This is what happens:

Evil fuckersEvil fuckers

What are these ^M characters? Did some research and they seemed to be DOS line-ending markers. What? DOS? Confused the hell out of me. I don’t have that in BBEdit. What is going on? More research led to this solution.

#+begin_src emacs-lisp
(defun dos2unix ()
  "Replace DOS eolns CR LF with Unix eolns CR"
  (interactive)
    (goto-char (point-min))
      (while (search-forward (string ?\C-m) nil t) (replace-match "\n")))
#+end_src

I run the dos2unix function to get rid of these evil things.

Outliner minor mode for everything

I love org-mode because it lets me have outliner behavior in my text editor. Like folding, hoisting, and so on. I got exposed to outline-minor-mode and decided to bring that to Markdown. The keybindings need work but this is what I am starting with:

#+begin_src emacs-lisp
(add-hook 'markdown-mode-hook 'outline-minor-mode)
;; Define outline-minor-mode key map
  (define-prefix-command 'cm-map nil "Outline-")
  (define-key outline-minor-mode-map (kbd "C-c @") 'cm-map)

  ;; Define key bindings for outline minor mode
  (define-key cm-map (kbd "t") 'outline-hide-body)     ; Hide all but headings
  (define-key cm-map (kbd "a") 'outline-show-all)      ; Show everything
  (define-key cm-map (kbd "c") 'outline-hide-entry)    ; Hide this entry's body
  (define-key cm-map (kbd "e") 'outline-show-entry)    ; Show this entry's body
  (define-key cm-map (kbd "l") 'outline-hide-leaves)   ; Hide all body lines
  (define-key cm-map (kbd "k") 'outline-show-branches) ; Show all entries
  (define-key cm-map (kbd "q") 'outline-hide-sublevels); Hide everything but top-level
  (define-key cm-map (kbd "o") 'outline-hide-other)    ; Hide other branches
#+end_src

reveal-in-osx-finder

Looking at some transients Howard Melman sent me, I came across a reference to reveal-in-osx-finder. Shows you the file you are working on in the Finder. Useful.

#+begin_src emacs-lisp
(use-package reveal-in-osx-finder)
(require 'reveal-in-osx-finder)
(global-set-key (kbd "C-c z") 'reveal-in-osx-finder)
#+end_src

cycle-spacing

Ran across this in Precise Word Spacing in macOS Emacs. It is a problem I face quite often and now I have a solution:

#+begin_src emacs-lisp
(keymap-global-set "M-SPC" #'cycle-spacing)
#+end_src

Transients and General

I use General for assigning my own keybindings to org-mode and markdown-mode. The default keybindings are too elaborate. General is not helpful if you don’t know what the options are that are available to you. Transients are handy in the process of discovery. The act of creating the transients helps you get familiar with the options that you can access. Howard Melman clued me in to the efficiency of this addition. Two examples of what he pointed me to.

Transient for C-x r

#+begin_src emacs-lisp
;;;; Transient for C-x r - rectangles, registers, bookmarks
(defun hrm-list-bookmarks ()
  (interactive)
  (call-interactively 'bookmark-bmenu-list))
(transient-define-prefix hrm-ctl-x-r-transient ()
  "Transient for C-x r commands"
  ["C-x r …"
   ["Rectangles"
    ("M-w" "Copy" copy-rectangle-as-kill)
    ("k" "Kill" kill-rectangle)
    ("y" "Yank" yank-rectangle)
    ("d" "Delete" delete-rectangle)
    ("o" "Open" open-rectangle)
    ("c" "Clear" clear-rectangle)
    ("t" "String" string-rectangle)
    ("N" "Number" rectangle-number-lines)
    (":" "Sum Down" calc-grab-sum-down) ; Unnecessary since I add it to rectangle-mark-mode-map
    ]
   ["To Register"
    ("SPC" "Point" point-to-register)
    ;; ("C-SPC" "Point" point-to-register)
    ;; ("C-@" "Point" point-to-register)
    ("s" "Region" copy-to-register)
    ("a" "Region Append" append-to-register) ; unbound
    ("p" "Region Prepend" prepend-to-register) ; unbound
    ("r" "Rectangle" copy-rectangle-to-register)
    ("w" "Window Config" window-configuration-to-register)
    ("f" "Frameset" frameset-to-register)
    ("n" "Number" number-to-register)
    ("+" "Increment" increment-register)
    ("K" "KMacro" kmacro-to-register)     ; C-x C-k K, can be here too
    ]
   ["From Register"
    ("j" "Jump" jump-to-register)
    ("i" "Insert" insert-register)
    ("x" "Consult" consult-register :if (lambda () (fboundp 'consult-register)))
    ]
   ["Bookmarks"
    ("m" "Set" bookmark-set)
    ;;("b" "Jump" bookmark-jump)        ; I bind C-x r b to consult-bookmark
    ("b" "Jump Consult" consult-bookmark)
    ("l" "List" hrm-list-bookmarks) ; list-bookmarks fails, probably because of call-interactively
    ("M" "Set if Unset" bookmark-set-no-overwrite)
    ("S" "Save" bookmark-save)
    ]
   ]
  )

(global-set-key (kbd "C-x R") #'hrm-ctl-x-r-transient)

#+end_src

Transient for M-g

#+begin_src emacs-lisp
      (transient-define-prefix hrm-goto-transient ()
        "Transient for navigation commands on M-g."
        ["Goto"
         ["Position #"
          ("g" "Line"             consult-goto-line)
          ("c" "Char"             avy-goto-char-timer)
          ("TAB" "Column"         move-to-column)
          ("t"  "Window Top/Bot"  move-to-window-line-top-bottom)
          ]
       ["Index Here"
        ("i" "Imenu"          consult-imenu)
        ("o" "Outline"        consult-outline) ; goto outline-regexp matches
        ("h" "Org Heading"    consult-org-heading :if-mode org-mode)
        ("m" "Mark"           consult-mark)     ; goto marker in mark-ring
       ]
     ["Index All"
      ("I" "Project Imenu"  consult-imenu-multi)
      ("M" "Global Mark"    consult-global-mark)
      ("T" "All Todo"       consult-todo-all)
      ]
    ["Here in"
    ("D" "Dired"   dired-jump)
    ("B" "IBuffer" ibuffer-jump)
    ("S" "Shell"   shell)       ; eshell?
    ("R" "Finder"  reveal-in-osx-finder :if (lambda () (fboundp 'reveal-in-osx-finder)))
    ]
   ["Avy"
    ("l" "Line" avy-goto-line)
    ("w" "Word" avy-goto-word-0)
    ("W" "Prompted Word" avy-goto-word-1)
    ]
  ])
      (global-set-key (kbd "M-G") 'hrm-goto-transient)
#+end_src

Lists of Some Other Changes

  • I installed the Spacemacs theme. I like the light version of the theme.
  • Also installed the Standard themes from Protesilaos. Love the light theme there.
  • Installed the Nano theme from Rougier. It is an impressively minimal look.
  • Installed the Embark package. Have little idea of what it does. I am reading up on it. Will discuss when I have a better idea of what that package is good for.

As you can tell, I am having fun and learning some new stuff.

Till next time.

macosxguru at the gmail thingie.

emacs
December 28, 2024

KittyKitty

2024 Review

The Major Changes

Two major changes happened over 2024. The introduction of the ZSA Moonlander Next-gen Ergonomics zsa.io to the hardware stack, and the other was GNU Emacs - GNU Project.

ZSA Moonlander

I had been using the Planck from ZSA. It is a great keyboard but I wanted to try out a split keyboard and had been drooling over the Moonlander for a while. I acquired it in July.

Took me a few weeks to get comfortable in it. Having used the Planck for about two years, I am used to the ortholinear setup. The Moonlander has so many extra keys, that it took some getting used to. Of course, that process was also accompanied by a ton of tweaks to the keyboard. The Moonlander is completely programmable through Oryx The ZSA Keyboard Configurator.

Programmable means choices. I had to answer basic questions like:

  • Where do I put the space bar?
  • What about the modifier keys? Do I need a right ⌘ key? Or a right ⌃ key?

Choices which had to be tried out for a while before I could make an informed one. Took a while and it is still an ongoing process.

I love the keyboard. Just absolutely love it. It has made my pain in my fingers and wrists go away. I am usually on the keyboard for more than 14 hours a day. Yeah, I know, I need a life. This is the best investment I have made on my health in a long while. Feels fantastic.

Things which make this keyboard perfect:

  • No Shift key required. Auto-shift is a god-send. A little longer press on a key and it types the character with the shift key held down. The downside? I can’t use any other keyboard. Using the keyboard on the Air, I find myself holding on to a key expecting the Auto-shift behavior and nothing happens. Deeply frustrating.
  • The ability to get the extra keys to do the usual things which I do on a regular basis is a killer feature. One key for Alfred - Productivity App for macOS. One key for Keyboard Maestro 11.0.3 Work Faster with Macros for macOS.
  • The Hyper key and the Meh key.
  • For the Emacs user, multiple Esc keys, and a dedicated C-g key.

If you are interested in improving your input device, I would recommend the Moonlander with glowing praise.

This is an interesting article on Your first month with a ZSA Keyboard.

If you want to check out my configuration, here it is.

Emacs

If you follow my blog, you know this story. I am all-in on Emacs at this stage. I wish I had made this move earlier on in life. But I am making up. Took a deep-dive into it for it to stick.

I will tell you a story.

I had just posted the article Part Five of My Battles with Emacs - Bicycle For Your Mind when I got email from someone I did not know. He recommended the Consult-notes package and gave me a bit of code:

#+begin_src emacs-lisp
(defun lookup-word-at-point ()
  "Lookup word at point in OSX Dictionary"
  (interactive)
  (call-process-shell-command (format "open dict:///%s/" (word-at-point))))
#+end_src

Out of the blue, one of the OG’s of the Emacs world, Mr. Howard Melman sent me email. Encouraging me and giving me advice. How cool is that? I was floored. There are a whole bunch of people who are Emacs-gurus and they help unknown newbies get comfortable with Emacs. I am so thankful to these folks. They make the journey rewarding. Thank you Mr. Melman.

Thank you Mr. Protesilaos Stavrou.
Thank you Mr. David Wilson.
Thank you Mr. Mike Zamansky.
Thank you Ms. Sasha Chua.
Thank you Mr. Rainer Konig.

Thank you all for teaching me stuff.

This list can be a lot longer. In fact, I will make this a recurring part of the Much Ado About Emacs series. There are a lot of people to thank.

Anyway, I am enjoying my time in Emacs. Learning new things, trying out new things. Loving the act of writing. An unexpected by-product? Emacs makes me write more. The environment is created by me (with a lot of help from other folks). There is no friction. It is perfectly designed for me and my writing. I love it here.

The Others

These are the ones which get used everyday.

I have a ton of other software installed but they get sporadic use.

macOS is blessed with a vibrant eco-system of software and I am thankful to the developers. They make my life better.

macosxguru at the gmail thingie.

Thanks: to Photo by Ludvig Hedenborg: https://www.pexels.com/photo/close-up-of-hands-holding-cute-kitten-16191918/

macOS
December 27, 2024

EmacsEmacs

Much Ado About Emacs 005

Tangling and Packages

In the last edition I had posted about a problem that I was facing. In short, when I deleted a package from my init file, the package was not deleted from the elpa directory where Emacs stores packages. I found that annoying. Having used Doom Emacs, a long time ago, I seem to remember that I didn’t do much else but delete the reference to the package in package.el. That got rid of the package, or at least I think it did. In my plain vanilla-setup, that was not happening.

There are two steps to the solution: Firstly you have to remove the use-package command from init.el. Secondly, M-x and type the command package-delete, select the package that you don’t want to use anymore and delete it by hitting ↵ (return). One good thing about this list, packages are listed as obsolete, dependencies or installed.

This two step process works out fine.

Notes and Note-taking

My note-taking needs are simple. They are:

  • I want to create and find notes quickly.
  • I would like to link between notes.
  • Tagging would be nice.

I am not looking for a graphical representation of my notes and the links between them. I don’t care to adhere to some knowledge management schema and its rules. In other words, I don’t care about atomic notes, fleeting notes, PARA, zettlekasten and all the other associated madness.

I don’t need denote, org-roam or howm. They are all great solutions. Not for me. Basic org-mode is all I need to create and access my notes. There are two things I added:

  1. An automatic Unique ID for all newly created org-files. I will talk about this in the next section.
  2. I brought back consult-notes. It is a nice interface to search for notes and gives me a preview of the note when selected. I like that.

Unique ID

I wanted an unique ID added to any org file I created. With help from Claude, I got this code for the unique ID:

#+begin_src emacs-lisp
;; First ensure org-id is loaded
(require 'org-id)

;; Configure org-id to create IDs using timestamps by default
(setq org-id-method 'ts)

;; Function to automatically add ID to new org files
(defun my/org-add-file-id ()
  "Add an ID property to the file if it doesn't have one."
  (interactive)
  (when (and (eq major-mode 'org-mode)
             (not (org-id-get-create)))
    (org-id-get-create)
    (save-buffer)))

;; Add hook to run when creating new org files
(add-hook 'org-mode-hook #'my/org-add-file-id)

;; Optional: Also ensure IDs are created for all headings
(defun my/org-add-ids-to-all-headings ()
  "Add IDs to all headings in current file that don't have one."
  (interactive)
  (org-map-entries 'org-id-get-create))

;; Optional: Add this to org-mode-hook if you want IDs on all headings
;; (add-hook 'org-mode-hook #'my/org-add-ids-to-all-headings)
#+end_src

This works great for newly created org files. Doesn’t work well with the capture templates that I have set up.

#+begin_src emacs-lisp
            ("b" "Bookmark" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Bookmark")
            ,(concat "* %^{Title}\n"
                      ":CAPTURED: %U\n"
                      ":END:\n\n"
                      "%a\n%i%?")
           :empty-lines-after 1)
#+end_src

The capture template bails with an error-message which points out that org-id-get-create expects a specified buffer. I am working on trying to fix that, in the meantime, org-id-create is a manual process.

Multiple Cursor

I had this installed for two weeks and never used it once. Deleted it.

Try Package

Included Try in the configuration. Seems like a good way of trying out packages without fully committing to them.

Move the Scroll in Emacs Without Moving the Position Cursor.

Added Move the scroll in Emacs without moving the position cursor. to the configuration.

#+begin_src emacs-lisp
  (use-package scroll-page-without-moving-point
    :straight (:host github :repo "tanrax/scroll-page-without-moving-point.el" :files ("scroll-page-without-moving-point.el"))
    :ensure t)
(global-set-key "\C-n" 'scroll-page-without-moving-point-down)
(global-set-key "\C-p" 'scroll-page-without-moving-point-up)
#+end_src

That is all I have for this week. You can see I am having fun.

macosxguru at the gmail thingie.

emacs
December 9, 2024

EmacsEmacs

Much Ado About Emacs 004

When I started building my Emacs configuration, I copied bits and pieces of code from a whole host of other people’s configurations. It made it possible for me to get started and be productive. I am grateful for the help I got from them. However, I ran out into some problems. One particular area of friction is keybindings. All of the individuals whose configuration I copied had their own logic behind the assignment of their keybindings. When you mix them together, the logic disappears and it all becomes a plethora of decisions which do not make sense. When it doesn’t make sense, it becomes more difficult to remember them. I needed to change that.

My Own Keymap

I came across, captainflasmr/Emacs-core: A stripped-down version of my primary Emacs configuration, it is designed to leverage only the default built-in features of Emacs. It is an attempt to replicate the features of packages in vanilla emacs through some clever code snippets. I learned a lot from it. It also taught me the benefit of designing my own keymap and making sense of what you assign to them. This is my first attempt at just that:

#+begin_src emacs-lisp
(defvar my-misc-keymap (make-sparse-keymap))
(global-set-key (kbd "M-o") my-misc-keymap)
    (define-key my-misc-keymap (kbd "+") #'tab-bar-new-tab)
    (define-key my-misc-keymap (kbd "-") #'tab-close)
    (define-key my-misc-keymap (kbd "b j") #'bookmark-jump)
    (define-key my-misc-keymap (kbd "b o") #'consult-bookmark)
    (define-key my-misc-keymap (kbd "b u") #'consult-buffer)
    (define-key my-misc-keymap (kbd "d") #'consult-dir)
    (define-key my-misc-keymap (kbd "g") #'consult-grep)
    (define-key my-misc-keymap (kbd "o h") #'consult-org-heading)
    (define-key my-misc-keymap (kbd "o a") #'consult-org-agenda)
    (define-key my-misc-keymap (kbd "o o") #'consult-outline)
    (define-key my-misc-keymap (kbd "r e") #'er/expand-region)
    (define-key my-misc-keymap (kbd "r c") #'er/contract-region)
    (define-key my-misc-keymap (kbd "r f") #'recentf-open-files)
    (define-key my-misc-keymap (kbd "r r") #'consult-register)
    (define-key my-misc-keymap (kbd "r s") #'consult-register-store)
    (define-key my-misc-keymap (kbd "/") #'my/comment-or-uncomment)
    (define-key my-misc-keymap (kbd "m l") #'my/mark-line)
    (define-key my-misc-keymap (kbd "m b") #'my/mark-block)
    (define-key my-misc-keymap (kbd "s") (lambda () (interactive) (switch-to-buffer "*scratch*")))
    (define-key my-misc-keymap (kbd "w") #'my/quick-window-jump)
#+end_src

Some functions which need to be explained.

Comment or Uncomment

This is from captainflasmr (CaptainFlasmr) and his Emacs-core repository.

#+begin_src emacs-lisp
(defun my/comment-or-uncomment ()
  "Comments or uncomments the current line or region."
  (interactive)
  (if (region-active-p)
      (comment-or-uncomment-region
       (region-beginning)(region-end))
    (comment-or-uncomment-region
     (line-beginning-position)(line-end-position))))
#+end_src

Mark Line

Again from captainflasmr (CaptainFlasmr) and his Emacs-core repository.

#+begin_src emacs-lisp
(defun my/mark-line ()
  "Mark whole line."
  (interactive)
  (beginning-of-line)
  (push-mark (point) nil t)
  (end-of-line))
#+end_src

Mark Block

Again from captainflasmr (CaptainFlasmr) and his Emacs-core repository.

#+begin_src emacs-lisp
(defun my/mark-block ()
  "Marking a block of text surrounded by a newline."
  (interactive)
  (when (not (region-active-p))
    (backward-char))
  (skip-chars-forward " \n\t")
  (re-search-backward "^[ \t]*\n" nil 1)
  (skip-chars-forward " \n\t")
  (when (not (region-active-p))
    (push-mark))
  (re-search-forward "^[ \t]*\n" nil 1)
  (skip-chars-backward " \n\t")
  (setq mark-active t))
#+end_src

ace-windows Replacement

I was using ace-windows to move between windows. This, again from captainflasmr (CaptainFlasmr) and his Emacs-core repository, is a replacement which works well.

#+begin_src emacs-lisp
(defun my/quick-window-jump ()
  "Jump to a window by typing its assigned character label.
Windows are labeled starting from the top-left window and proceed top to bottom left to right."
  (interactive)
  (let* ((window-list (my/get-windows))
         (window-keys (seq-take '("j" "k" "l" ";" "a" "s" "d" "f")
                                (length window-list)))
         (window-map (cl-pairlis window-keys window-list))
         (key (read-key (format "Select window [%s]: " (string-join window-keys ", ")))))
    (if-let ((selected-window (cdr (assoc (char-to-string key) window-map))))
        (select-window selected-window)
      (message "No window assigned to key: %c" key))))

(defun my/get-windows ()
  "Return a list of windows in the current frame, ordered from top to bottom, left to right."
  (sort (window-list nil 'no-mini)
        (lambda (w1 w2)
          (let ((edges1 (window-edges w1))
                (edges2 (window-edges w2)))
            (or (< (car edges1) (car edges2)) ; Compare top edges
                (and (= (car edges1) (car edges2)) ; If equal, compare left edges
                     (< (cadr edges1) (cadr edges2))))))))
#+end_src

Other Changes

  • I got rid of ace-windows.
  • Got rid of hydra and all the hydras I had designed. The two major ones were for dired and Markdown. Need to learn the keyboard commands and not rely on the hydras. Might create a general keymap for dired. Not sure about it yet.
  • Got rid of discover and makey from Mickey Petersen. Wasn’t supported by other packages and hence not useful.
  • Tried to install kickingvegascasual-suite Casual Suite - An umbrella package to support a single install point for all Casual user interfaces.. For some reason, it didn’t work at all and I did not bother to troubleshoot it. Might come back to it at some point, but it is not an urgent need.
  • Was curious about Emacs: Xah Fly Keys. Couldn’t get it to work and then read the documentation and decided not to go there. It will require a major change to the way I interact with Emacs and I am not sure I want to climb that mountain yet.

Pain-point

I have an org-file called Emacs.org which tangles to an init.el. I notice that if I take an installed package and set the elisp code to tangle: no, it disappears from the init.el. However the package still exists in my elpa directory and it is accessible to me through M-x. Doesn’t work, but it shows up in the command-list. Annoying. I have to delete the package from the elpa directory myself. Is this normal behavior or is my configuration missing something? Any help would be appreciated.

This is the code I am using for auto-tangling the org file on save. It is from the Emacs from Scratch series at System Crafters.

#+begin_src emacs-lisp
  ;; Automatically tangle our Emacs.org config file when we save it
  (defun efs/org-babel-tangle-config ()
    (when (string-equal (file-name-directory (buffer-file-name))
                        (expand-file-name user-emacs-directory))
      ;; Dynamic scoping to the rescue
      (let ((org-confirm-babel-evaluate nil))
        (org-babel-tangle))))

  (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'efs/org-babel-tangle-config)))
#+end_src

That is all I have for today.

macosxguru at the gmail thingie.

emacs