Compare commits

..

6 commits

Author SHA1 Message Date
Howard Abrams
c20eda48a8 Getting rid of AI packages I don't use 2026-10-09 19:51:47 -07:00
Howard Abrams
82afd54a9c Getting EAT working well with better colors 2026-10-09 19:50:51 -07:00
Howard Abrams
97e9b86026 Fix critical bugs in my ha-code-note project 2026-10-09 19:16:35 -07:00
Howard Abrams
d9f3ec8806 The Prettify package converts words to letters
Things like ae won't work, as it is not a complete word.

Emojis are fine though.
2026-09-29 11:36:52 -07:00
Howard Abrams
db51a66d8c Minor bugs
Including increasing the GC value, and dropping the Fish shell package.
2026-09-29 11:36:13 -07:00
Howard Abrams
c40a3827b3 Limit Claude locations for agent-shell 2026-09-29 11:35:12 -07:00
15 changed files with 234 additions and 145 deletions

View file

@ -6,7 +6,7 @@
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 -*- lexical-binding: t; -*-
;; ;;
;; ██████████ ;; ██████████
;; ░░███░░░░░█ ;; ░░███░░░░░█
@ -51,7 +51,7 @@ Limit garbage collection before startup and then go back to the default value (8
(add-hook 'emacs-startup-hook (add-hook 'emacs-startup-hook
(lambda () (lambda ()
(setq gc-cons-threshold (* 100 1024 1024)))) (setq gc-cons-threshold (* 200 1024 1024))))
#+END_SRC #+END_SRC
** OS Path and Native Compilation ** OS Path and Native Compilation
@ -167,7 +167,7 @@ Much of my more complicated code comes from my website essays and other projects
#+end_src #+end_src
* Emacs Server Control * Emacs Server Control
I actually run two instances of Emacs on some systems, where one instance has all my work-related projects, perspectives, and packages installed (like LSP), and my personal instance has other packages running (like IRC and Mail). I need a function that can make that distinction, and based on that, it will set =server-start= appropriately, so that =emacsclient= can call into the correct one. I actually run two instances of Emacs on some systems, where one instance has all my work-related projects, perspectives, and packages installed (like the Language Server Protocol, LSP), and my personal instance has other packages running (like the Internet Relay Chat, IRC, and Mail). I need a function that can make that distinction, and based on that, it will set =server-start= appropriately, so that =emacsclient= can call into the correct one.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun ha-emacs-for-work? () (defun ha-emacs-for-work? ()
"Return non-nil when the Emacs instance is for work. "Return non-nil when the Emacs instance is for work.
@ -210,7 +210,6 @@ The following /defines/ the rest of my org-mode literate files, that I load late
"ha-org-literate.org" "ha-org-literate.org"
"ha-org-clipboard.org" "ha-org-clipboard.org"
"ha-capturing-notes.org" "ha-capturing-notes.org"
"ha-code-notes.org"
"ha-agendas.org" "ha-agendas.org"
"ha-data.org" "ha-data.org"
"ha-passwords.org" "ha-passwords.org"
@ -230,6 +229,7 @@ The following /defines/ the rest of my org-mode literate files, that I load late
"ha-org-publishing.org" "ha-org-publishing.org"
"ha-email.org" "ha-email.org"
"ha-aux-apps.org")) "ha-aux-apps.org"))
"ha-code-notes.org"
"ha-dashboard.org")) "ha-dashboard.org"))
"List of org files that complete the hamacs project.") "List of org files that complete the hamacs project.")
#+end_src #+end_src
@ -241,7 +241,7 @@ The list of /hamacs/ org-formatted files stored in =ha-hamacs-files= is selectiv
(if (not all) (if (not all)
ha-hamacs-files ha-hamacs-files
(thread-last (rx ".org" string-end) (thread-last (rx (not ".") (+? any) ".org" string-end)
(directory-files hamacs-source-dir nil) (directory-files hamacs-source-dir nil)
(append ha-hamacs-files) (append ha-hamacs-files)
(--filter (not (string-match (rx "README") it))) (--filter (not (string-match (rx "README") it)))

View file

@ -23,7 +23,7 @@ A literate programming file configuring critical applications.
;; And tangle the file to recreate this one. ;; And tangle the file to recreate this one.
;; ;;
;;; Code: ;;; Code:
#+end_src #+end_src
Can we call the following /applications/? I guess. Can we call the following /applications/? I guess.
* Agentic Interface * Agentic Interface
@ -158,14 +158,8 @@ And point Emacs to it:
(setq agent-shell-anthropic-claude-acp-command (setq agent-shell-anthropic-claude-acp-command
(if (file-exists-p "/opt/homebrew") (if (file-exists-p "/opt/homebrew")
(list (file-expand-wildcards "/opt/homebrew/bin/claude-agent-acp")) (file-expand-wildcards "/opt/homebrew/bin/claude-agent-acp")
'("/usr/local/bin/claude-agent-acp"))) '("/usr/local/bin/claude-agent-acp"))))
(when (file-exists-p "~/.zshenv-work")
(setq agent-shell-anthropic-claude-environment (agent-shell-make-environment-variables
:load-env "~/.zshenv-work"))))
;; /opt/homebrew/Cellar/node/26.0.0/bin/claude-agent-acp
#+END_SRC #+END_SRC
*** Cursor *** Cursor
@ -227,36 +221,6 @@ And let’s make that the default now:
:config :config
(setq agent-shell-preferred-agent-config (agent-shell-google-make-gemini-config))) (setq agent-shell-preferred-agent-config (agent-shell-google-make-gemini-config)))
#+END_SRC #+END_SRC
** AI Code Interface
While the =agent-shell= offers a /vibe-codey/ interface to Chatbots, the [[https://github.com/tninja/ai-code-interface.el][ai-code-interface]] offers a more /programmatic/ interface.
#+BEGIN_SRC emacs-lisp
(use-package ai-code
:straight (:host github :repo "tninja/ai-code-interface.el")
:config
;; use codex as backend, other options are 'claude-code, 'gemini,
;; 'github-copilot-cli, 'opencode, 'grok, 'cursor, 'kiro,
;; 'codebuddy, 'aider, 'eca, 'agent-shell, 'claude-code-ide,
;; 'claude-code-el
(ai-code-set-backend 'gemini)
;; Enable global keybinding for the main menu
(global-set-key (kbd "C-c a") #'ai-code-menu)
;; Optional: Enable @ file completion in comments and AI sessions
(ai-code-prompt-filepath-completion-mode 1)
;; Optional: Ask AI to run test after code changes, for a tighter build-test loop
;; (setq ai-code-auto-test-type 'ask-me)
;; Optional: In AI session buffers, SPC in Evil normal state triggers the prompt-enter UI
;; (with-eval-after-load 'evil (ai-code-backends-infra-evil-setup))
;; Optional: Set up Magit integration for AI commands in Magit popups
(with-eval-after-load 'magit
(ai-code-magit-setup-transients)))
#+END_SRC
* Git and Magit * Git and Magit
Can not live without [[https://magit.vc/][Magit]], a Git porcelain for Emacs. I stole the bulk of this work from Doom Emacs. Can not live without [[https://magit.vc/][Magit]], a Git porcelain for Emacs. I stole the bulk of this work from Doom Emacs.
#+begin_src emacs-lisp #+begin_src emacs-lisp

View file

@ -63,6 +63,22 @@ This allows me to /wax poetic/ with a parallel, but separate org file. Of course
If this isn’t good for you, check out [[https://github.com/agoodman42/montag][Montag]]. Same project, different approach using a single directory for all notes with [[https://www.orgroam.com/][org-roam]]. If this isn’t good for you, check out [[https://github.com/agoodman42/montag][Montag]]. Same project, different approach using a single directory for all notes with [[https://www.orgroam.com/][org-roam]].
Let’s create a pattern for what a notes file is, and how to recognize them:
#+BEGIN_SRC emacs-lisp
(defconst ha-code-notes-rx (rx (optional "/")
"." (one-or-more (not "/")) "-notes.org" string-end))
(defun ha-code-notes-file (file &optional parent)
"Return a FILE's 'code notes' filename.
Prepend the PARENT if given."
(cond
((and parent (string-match-p (rx "/" string-end) parent))
(format "%s.%s-notes.org" parent file))
(parent (format "%s/.%s-notes.org" parent file))
(t (format ".%s-notes.org" file))))
#+END_SRC
Another feature when looking at the notes in the org buffer, is to hit the same key to return to the source code file referencing the notes. Another feature when looking at the notes in the org buffer, is to hit the same key to return to the source code file referencing the notes.
# TODO Create custom settings to override default behavior. # TODO Create custom settings to override default behavior.
@ -109,17 +125,18 @@ This was far gnarlier than I originally thought, since IMenu only wants to /inte
(file qualified-name offset)" (file qualified-name offset)"
(let* ((here (point)) (let* ((here (point))
(entry (thread-last (imenu--make-index-alist t) (entry (ignore-errors
;; Flatten hierarchy labels with dot separators: (thread-last (imenu--make-index-alist t)
(ha-code-notes-location--flatten-index) ;; Flatten hierarchy labels with dot separators:
;; Filter to only entries that occur after point: (ha-code-notes-location--flatten-index)
(seq-filter (lambda (e) (<= (cdr e) here))) ;; Filter to only entries that occur after point:
;; Sort the remaining entries by position (seq-filter (lambda (e) (<= (cdr e) here)))
;; (since out flatten-index function ;; Sort the remaining entries by position
;; doesn't guarantee the order): ;; (since out flatten-index function
(seq-sort-by #'cdr #'>) ;; doesn't guarantee the order):
;; And the first entry on the list is our goal: (seq-sort-by #'cdr #'>)
car))) ;; And the first entry on the list is our goal:
car))))
(unless entry (unless entry
(error "No enclosing definition found for point")) (error "No enclosing definition found for point"))
(list (buffer-file-name) (list (buffer-file-name)
@ -131,8 +148,8 @@ The needed /trick/ is to flatten this IMenu hierarchy using this recursive beaut
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(defun ha-code-notes-location--flatten-index (alist &optional prefix) (defun ha-code-notes-location--flatten-index (alist &optional prefix)
"Flatten imenu ALIST into a list of (QUALIFIED-NAME . POSITION). "Flatten imenu ALIST into a list of (NAME . POSITION).
Where the qualified-name matches what which-function/imenu expect. Where the name matches what which-function/imenu expect.
For instance: For instance:
@ -142,47 +159,115 @@ The needed /trick/ is to flatten this IMenu hierarchy using this recursive beaut
((\"foo_class.method_one\" ...) (\"foo_class.method_two\" ...)...) ((\"foo_class.method_one\" ...) (\"foo_class.method_two\" ...)...)
This is called recursively, so PREFIX could be a class name, or Called recursively, where PREFIX could be a class name, or other higher
other higher abstraction." abstraction when the nesting represents a real outline (Org, Markdown).
;; Like `mapconcat' but lets us concat into something other than a string.
;; Note that `mapcan' uses `nconc' which _mutates_ the `alist'. Entries tagged with `imenu-kind' or `breadcrumb-kind' property (as Eglot
;; This is fine as a parameter that we then return: nests a function's local variables for Python) are already a flat
namespace of functions/variables/constants, so their own names are kept
bare and not qualified by an enclosing function's name."
(mapcan (mapcan
(lambda (entry) (lambda (entry)
;; Some imenu backends (e.g. python.el) annotate names with their (unless (or (null entry) (atom entry))
;; category, e.g. "Pair (class)" or "sum (def)". Strip that so (let* ((raw-name (car entry))
;; names match what `which-function'/`add-log-current-defun' (kind (and (stringp raw-name)
;; produce, and what gets stored as XREF_NAME in notes files. (or (get-text-property 0 'imenu-kind raw-name)
(let* ((name (replace-regexp-in-string (get-text-property 0 'breadcrumb-kind raw-name))))
(rx space "(" (one-or-more alpha) ")" string-end) (name (if (stringp raw-name)
"" (car entry))) (replace-regexp-in-string
(value (cdr entry)) (rx space "(" (one-or-more alpha) ")" string-end)
(qualified (if prefix (format "%s.%s" prefix name) name))) "" (substring-no-properties raw-name))
(if (listp value) (format "%s" raw-name)))
(ha-code-notes-location--flatten-index value qualified) (value (cdr entry))
(list (cons qualified (if (markerp value) (marker-position value) value)))))) (qualified (if (and prefix (not kind)) (format "%s.%s" prefix name) name)))
(cond
;; Case 1: Nested submenu (list of alist entries). Eglot
;; never gives the container itself a position among its
;; children, as Org does; it stashes it in the
;; `imenu-region' text property instead, so recover it
;; here. Children only inherit QUALIFIED as their prefix
;; when this entry has no `imenu-kind' of its own -- i.e.
;; when the nesting is a real outline, not Eglot's flat
;; function/variable/constant tagging.
((and (listp value) (consp (car value)))
(append
(let ((region (and (stringp raw-name)
(get-text-property 0 'imenu-region raw-name))))
(when region (list (cons qualified (car region)))))
(ha-code-notes-location--flatten-index value (unless kind qualified))))
;; Case 2: Direct marker or integer position
((integer-or-marker-p value)
(list (cons qualified (if (markerp value) (marker-position value) value))))
;; Case 3: Overlay or element containing a position in car/cdr
((overlayp value)
(list (cons qualified (overlay-start value))))
((and (consp value) (integer-or-marker-p (car value)))
(list (cons qualified (if (markerp (car value))
(marker-position (car value))
(car value)))))
;; Fallback: ignore non-positional Imenu metadata entries
(t nil)))))
alist)) alist))
#+END_SRC #+END_SRC
This flatten feature has been a pain in my side. An org-mode formatted file works well, for instance, running the following on this document:
#+BEGIN_SRC emacs-lisp :tangle no :results replace value raw :export both :wrap example
(ha-code-notes-location--flatten-index (imenu--make-index-alist t))
#+END_SRC
#+RESULTS:
#+begin_example
((*Rescan* . -99) (Introduction . 946) (Helper Functions.Relative Code Locations . 3719) (Helper Functions.Org Properties . 13220) (Helper Functions . 3592) (Write a Note.Return to Source Code . 22408) (Write a Note.Fringe Indicators for Notes . 24001) (Write a Note . 17005) (Technical Artifacts . 27464))
#+end_example
But running the same expression on a Python file (via Eglot) nests the local variables and parameters of each function as children in the index, each tagged with an =imenu-kind= text property on its name, e.g. a function like this:
#+begin_example
(#("parse_args" 0 10 (imenu-region (1245 . 1627) imenu-kind "Function" breadcrumb-region (1245 . 1627) breadcrumb-kind "Function"))
(#("argv" 0 4 (imenu-region (1260 . 1289) imenu-kind "Variable" ...)) . 1260)
(#("parser" 0 6 (imenu-region (1365 . 1371) imenu-kind "Variable" ...)) . 1365))
#+end_example
Naively flattening this treats =argv= and =parser= as if they were nested methods, producing useless entries like ~parse_args.argv~. Worse, the function itself never had its own position among its children (unlike Org, which gives a parent headline a self-pointing entry), so there was no way to jump straight to ~parse_args~ at all.
The fix: the presence of an =imenu-kind=/=breadcrumb-kind= property means the nesting is Eglot's flat function/variable/constant tagging, not a real outline -- so a child's name is never qualified by its parent's. When recursing into a nested submenu, the container's own position is recovered from its =imenu-region= text property, and the name is stripped of text properties. That turns the above into clean, bare entries for every name -- function, variable, and constant alike:
#+begin_example
((parse_args . 1245) (argv . 1260) (parser . 1365) (registry_credentials . 1630) ...)
#+end_example
Once inside a source file, we can jump to one of these /relative locations/: Once inside a source file, we can jump to one of these /relative locations/:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(defun ha-code-notes-location-goto (file name offset) (defun ha-code-notes-location-goto (file name offset)
"Move point to the position described by relative location. "Move point to the position described by relative location.
FILE is the filename to load, may be nil to use current buffer. FILE is the filename to load, may be nil to use current buffer.
NAME is a function name or other definition, e.g. ClassName.method NAME is a function name or other definition, e.g. ClassName.method
OFFSET is the number of lines below NAME to position the point." OFFSET is the number of lines below NAME to position the point."
(when (and file (not (equal file (buffer-file-name)))) (when (and file (not (equal file (buffer-file-name))))
(find-file-other-window file)) (find-file-other-window file))
(condition-case t
(ha-code-notes--location-goto name offset)
(message "Definition `%s' no longer found in %s" name file))
(ignore-errors
))
(defun ha-code-notes--location-goto (name &optional offset)
"Use `imenu' interface to goto NAME location.
If OFFSET given, move that many lines below."
(let* ((index (ha-code-notes-location--flatten-index (imenu--make-index-alist t))) (let* ((index (ha-code-notes-location--flatten-index (imenu--make-index-alist t)))
(entry (assoc name index))) (entry (assoc name index)))
(if (not entry) (when entry
(message "Definition `%s' no longer found in %s" name file)
(goto-char (cdr entry)) (goto-char (cdr entry))
(when offset (when offset
(forward-line offset))))) (forward-line offset)))))
#+END_SRC #+END_SRC
To verify that this works: To verify that this works:
@ -297,8 +382,7 @@ This function defines what the notes filename should look like, loads it in a si
;; Keep in mind the `orig-parent' has a final slash, so the ;; Keep in mind the `orig-parent' has a final slash, so the
;; initial . here marks it as hidden: ;; initial . here marks it as hidden:
(note-file (format "%s.%s-notes.org" (note-file (ha-code-notes-file orig-base orig-parent))
orig-parent orig-base))
(header (which-function)) (header (which-function))
(offset (ha-code-notes-defun-rel-line))) (offset (ha-code-notes-defun-rel-line)))
@ -322,7 +406,7 @@ Use the builtin autoinsert feature to inject a basic template at the beginning o
(use-package autoinsert (use-package autoinsert
:config :config
(define-auto-insert (define-auto-insert
(cons (rx "/." (one-or-more (not "/")) "-notes.org" string-end) "Org Notes Template") (cons ha-code-notes-rx "Org Notes Template")
'("Short description: " '("Short description: "
"#+TITLE: " "#+TITLE: "
(s-titleized-words (s-replace-regexp (rx (any "-" "_")) " " (s-titleized-words (s-replace-regexp (rx (any "-" "_")) " "
@ -435,10 +519,7 @@ And give us keybinding that will either go to the notes (if we are in some code)
"Open the notes buffer, or return to the code." "Open the notes buffer, or return to the code."
(interactive) (interactive)
(when (buffer-file-name) (when (buffer-file-name)
(if (string-match (rx "/." ; A hidden file (if (string-match ha-code-notes-rx (buffer-file-name))
(one-or-more (not "/"))
"-notes.org" string-end)
(buffer-file-name))
(ha-code-notes-return) (ha-code-notes-return)
(ha-code-notes)))) (ha-code-notes))))
@ -472,22 +553,27 @@ A code file with an associated notes file is easy to forget about. Let's mark, i
(defun ha-code-notes--fringe () (defun ha-code-notes--fringe ()
"Mark, in the fringe, every line in this buffer that has a note. "Mark, in the fringe, every line in this buffer that has a note.
Notes live in the paired `.BASE-notes.org' file (see Notes live in the paired `.BASE-notes.org' file (see
`ha-code-notes') as headings whose XREF property matches this `ha-code-notes') as headings whose XREF property matches this
file, XREF_NAME names the function (inherited by subheadings from file, XREF_NAME names the function (inherited by subheadings from
their parent), and XREF_LINE is a line offset from that function's their parent), and XREF_LINE is a line offset from that function's
start, computed by `ha-code-notes-defun-rel-line'. We resolve each start, computed by `ha-code-notes-defun-rel-line'. We resolve each
pair back to an absolute line via `ha-code-notes-location-goto', since the function pair back to an absolute line via `ha-code-notes-location-goto', since the function
may have moved since the note was taken." may have moved since the note was taken."
(mapc #'delete-overlay ha-code-notes--fringe-overlays) (mapc #'delete-overlay ha-code-notes--fringe-overlays)
(setq ha-code-notes--fringe-overlays nil) (setq ha-code-notes--fringe-overlays nil)
(let* ((orig-file (buffer-file-name)) (let* ((orig-file (buffer-file-name))
(note-file (and orig-file (note-file (and orig-file
(format "%s.%s-notes.org" (ha-code-notes-file
(file-name-directory orig-file) (file-name-directory orig-file)
(file-name-base orig-file)))) (file-name-base orig-file))))
notes) notes)
(when (and note-file (file-exists-p note-file)) ;; Only run if this is an actual file AND its notes file exists:
(when (and orig-file
note-file
(file-exists-p note-file)
(not (string-match-p ha-code-notes-rx orig-file)))
(with-temp-buffer (with-temp-buffer
(insert-file-contents note-file) (insert-file-contents note-file)
(org-mode) (org-mode)
@ -516,7 +602,7 @@ New notes and edited notes should refresh the markers too, so we hook into savin
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(defun ha-code-notes--fringe-notes-refresh-all () (defun ha-code-notes--fringe-notes-refresh-all ()
"Refresh fringe note markers in every buffer after saving a notes file." "Refresh fringe note markers in every buffer after saving a notes file."
(when (string-match (rx "-notes.org" string-end) (buffer-file-name)) (when (string-match ha-code-notes-rx (buffer-file-name))
(dolist (buf (buffer-list)) (dolist (buf (buffer-list))
(with-current-buffer buf (with-current-buffer buf
(when buffer-file-name (when buffer-file-name

View file

@ -535,17 +535,18 @@ The nerd font package takes a popular font like "Iosevka" and jams a bunch of th
** Symbols and Emojis ** Symbols and Emojis
Display these two symbols as one character, as using [[Ligatures]] often stretches wider, and the following are nice to be collapsed: Display these two symbols as one character, as using [[Ligatures]] often stretches wider, and the following are nice to be collapsed into a single glyph:
#+begin_src emacs-lisp #+begin_src emacs-lisp
(add-hook 'text-mode-hook (lambda () (add-hook 'text-mode-hook (lambda ()
(dolist (pair '(("!?" . "‽") (dolist (pair '(("!?" . "‽")
("ae" . "æ")
("..." . "…") ; ??
("??" . "⁇") ("??" . "⁇")
;; ("<<" . "«") ("<<" . "«")
;; (">>" . "»") (">>" . "»")
("AE" . "Æ"))) (":-)" . "🙂")
(":-D" . "😃")
(";-)" . "😉")
("..." . "…")))
(push pair prettify-symbols-alist)))) (push pair prettify-symbols-alist))))
#+end_src #+end_src

View file

@ -366,7 +366,7 @@ This expands on my global [[file:ha-config.org::*Bookmarks][Bookmarks]]:
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package bookmark-in-project (use-package bookmark-in-project
:bindd :bind
(("C-x r m" . bookmark-in-project-toggle) (("C-x r m" . bookmark-in-project-toggle)
("C-x r M" . ha-bookmark-set)) ("C-x r M" . ha-bookmark-set))
:config :config

View file

@ -2,7 +2,7 @@
#+author: Howard Abrams #+author: Howard Abrams
#+date: 2024-07-07 #+date: 2024-07-07
#+filetags: emacs hamacs #+filetags: emacs hamacs
#+lastmod: [2026-08-05 Wed] #+lastmod: [2026-09-22 Tue]
A literate programming file for literate programming in Emacs Org Files. A literate programming file for literate programming in Emacs Org Files.
@ -19,16 +19,15 @@ A literate programming file for literate programming in Emacs Org Files.
;; ;;
;; While obvious, GNU Emacs does not include this file or project. ;; While obvious, GNU Emacs does not include this file or project.
;; ;;
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
;; ~/src/hamacs/ha-org-literate.org
;; Using `find-file-at-point', and tangle the file to recreate this.
;;
;;; Commentary: ;;; Commentary:
;; ;;
;; This file contains a collection of functions to easy some of the ;; This file contains a collection of functions to easy some of the
;; sharp edges when doing literate programming in Org files. ;; sharp edges when doing literate programming in Org files.
;; ;;
;; *NB:* Do not edit this file. Instead, edit the original
;; literate file at:
;; ~/src/hamacs/ha-org-literate.org
;; And tangle the file to recreate this one.
;;
;;; Code: ;;; Code:
#+end_src #+end_src
* Introduction * Introduction
@ -937,13 +936,9 @@ Let's =provide= a name so we can =require= this file:
#+DESCRIPTION: literate programming in Emacs Org Files. #+DESCRIPTION: literate programming in Emacs Org Files.
#+PROPERTY: header-args:sh :tangle no #+PROPERTY: header-args:sh :tangle no
#+PROPERTY: header-args:emacs-lisp :tangle yes :comments link #+PROPERTY: header-args:emacs-lisp :tangle yes
#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes #+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes
#+OPTIONS: num:nil toc:t todo:nil tasks:nil tags:nil date:nil #+OPTIONS: num:nil toc:t todo:nil tasks:nil tags:nil date:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil #+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js #+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
# Local Variables:
# jinx-local-words: "parseable"
# End:

View file

@ -3,7 +3,7 @@
#+date: 2020-09-18 #+date: 2020-09-18
#+tags: emacs org #+tags: emacs org
#+startup: inlineimages #+startup: inlineimages
#+lastmod: [2026-08-10 Mon] #+lastmod: [2026-10-09 Fri]
A literate programming file for configuring org-mode and those files. A literate programming file for configuring org-mode and those files.
@ -940,7 +940,7 @@ Since the /definitions/ do not work, so let's use the [[https://github.com/abo-a
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package define-word (use-package define-word
:config :config
(ha-leader :keymaps 'text-mode-map (ha-leader
"s d" '(:ignore t :which-key "dictionary") "s d" '(:ignore t :which-key "dictionary")
"s d d" '("define this word" . define-word-at-point) "s d d" '("define this word" . define-word-at-point)
"s d a" '("define any word" . define-word))) "s d a" '("define any word" . define-word)))
@ -1183,7 +1183,8 @@ I create a configuration file in my home directory:
"stop-words": false, "stop-words": false,
"terminology": { "severity": "warning" }, "terminology": { "severity": "warning" },
"unexpanded-acronym": { "severity": "warning" }, "unexpanded-acronym": { "severity": "warning" },
"write-good": false "write-good": false,
"unexpanded-acronym": false
} }
} }
#+end_src #+end_src

View file

@ -1498,16 +1498,6 @@ Integration with the [[https://github.com/bash-lsp/bash-language-server][Bash LS
#+begin_src sh #+begin_src sh
brew install bash-language-server brew install bash-language-server
#+end_src #+end_src
*** Fish Shell
I think the [[https://fishshell.com/][fish shell]] is an interesting experiment (and I appreciate the basics that come with [[https://github.com/emacsmirror/fish-mode][fish-mode]]).
#+begin_src emacs-lisp
(use-package fish-mode
:mode (rx ".fish" eol)
:config
(ha-auto-insert-file (rx ".fish") "fish-mode.sh")
:hook
(fish-mode . (lambda () (add-hook 'before-save-hook 'fish_indent-before-save))))
#+end_src
* Technical Artifacts :noexport: * Technical Artifacts :noexport:
Provide a name to =require= this code. Provide a name to =require= this code.
#+begin_src emacs-lisp :exports none #+begin_src emacs-lisp :exports none

View file

@ -124,7 +124,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 :tangle no
(use-package vterm (use-package vterm
:config :config
(setq vterm-shell "zsh" (setq vterm-shell "zsh"
@ -162,7 +162,7 @@ An odd use case I have: working in a Terminal session in one buffer window, and
Now, I can type: ~s-G~ (with the shift), select the line with Avy, and type ~N~ to have it copy/paste into the buffer: Now, I can type: ~s-G~ (with the shift), select the line with Avy, and type ~N~ to have it copy/paste into the buffer:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp :tangle no
(use-package vterm (use-package vterm
:config :config
(defun ha-vterm-avy-paste-line () (defun ha-vterm-avy-paste-line ()
@ -180,7 +180,7 @@ Now, I can type: ~s-G~ (with the shift), select the line with Avy, and type ~N~
** Eat ** Eat
While not as fast as [[https://github.com/akermu/emacs-libvterm][vterm]], the [[https://codeberg.org/akib/emacs-eat][Emulate a Terminal]] project (eat) is fast enough, and doesn’t require a dedicate library that requires re-compilation. While offering [[https://elpa.nongnu.org/nongnu-devel/doc/eat.html][online documentation]], I’m glad for an [[info:eat#Top][Info version]]. While not as fast as [[https://github.com/akermu/emacs-libvterm][vterm]], the [[https://codeberg.org/akib/emacs-eat][Emulate a Terminal]] project (eat) is fast enough, and doesn’t require a dedicate library that requires re-compilation. While offering [[https://elpa.nongnu.org/nongnu-devel/doc/eat.html][online documentation]], I’m glad for an [[info:eat#Top][Info version]].
#+BEGIN_SRC emacs-lisp :tangle no #+BEGIN_SRC emacs-lisp
(use-package eat (use-package eat
:straight (:host codeberg :repo "akib/emacs-eat" :straight (:host codeberg :repo "akib/emacs-eat"
:files ("*.el" ("term" "term/*.el") "*.texi" :files ("*.el" ("term" "term/*.el") "*.texi"
@ -192,6 +192,25 @@ While not as fast as [[https://github.com/akermu/emacs-libvterm][vterm]], the [[
:bind (:map eat-semi-char-mode-map :bind (:map eat-semi-char-mode-map
("C-c C-t" . ha-eat-narrow-to-shell-prompt-dwim)) ("C-c C-t" . ha-eat-narrow-to-shell-prompt-dwim))
:config :config
;; Red:
(set-face-attribute 'eat-term-color-1 nil :foreground "#b78077")
(set-face-attribute 'eat-term-color-9 nil :foreground "#d45d4c")
;; Green:
(set-face-attribute 'eat-term-color-2 nil :foreground "#879a39")
(set-face-attribute 'eat-term-color-10 nil :foreground "#66800b")
;; Yellow:
(set-face-attribute 'eat-term-color-2 nil :foreground "#d0a215")
(set-face-attribute 'eat-term-color-10 nil :foreground "#ad8301")
;; Blue
(set-face-attribute 'eat-term-color-2 nil :foreground "#4385be")
(set-face-attribute 'eat-term-color-10 nil :foreground "#205ea6")
;; Magenta:
(set-face-attribute 'eat-term-color-2 nil :foreground "#ce5d97")
(set-face-attribute 'eat-term-color-10 nil :foreground "#a02f6f")
;; Cyan
(set-face-attribute 'eat-term-color-2 nil :foreground "#3aa99f")
(set-face-attribute 'eat-term-color-10 nil :foreground "#24837b")
(defun ha-eat-narrow-to-shell-prompt-dwim () (defun ha-eat-narrow-to-shell-prompt-dwim ()
(interactive) (interactive)
(if (buffer-narrowed-p) (widen) (eat-narrow-to-shell-prompt))) (if (buffer-narrowed-p) (widen) (eat-narrow-to-shell-prompt)))
@ -214,8 +233,6 @@ What about Evil mode?
TODO: Like =eshell=, the Bash in an EAT terminal has a command =_eat_msg= that takes a handler, and a /message/. Then set up an alist of =eat-message-handler-alist= to decide what to do with it. TODO: Like =eshell=, the Bash in an EAT terminal has a command =_eat_msg= that takes a handler, and a /message/. Then set up an alist of =eat-message-handler-alist= to decide what to do with it.
TODO: Need to /subtlize/ the =eat-term-color-bright-green= and other settings as it is way too garish.
Make sure you add the following for Bash: Make sure you add the following for Bash:
#+BEGIN_SRC bash :tangle no #+BEGIN_SRC bash :tangle no

View file

@ -438,6 +438,20 @@ Let’s make a /theme/:
`(term-color-bright-yellow ((t (:foreground ,yellow)))) `(term-color-bright-yellow ((t (:foreground ,yellow))))
`(term-color-bright-cyan ((t (:foreground ,slate)))) `(term-color-bright-cyan ((t (:foreground ,slate))))
`(ansi-color-red ((t (:foreground ,red2-lt :background nil))))
`(ansi-color-green ((t (:foreground ,green-lt :background nil))))
`(ansi-color-blue ((t (:foreground ,blue-lt :background nil))))
`(ansi-color-magenta ((t (:foreground ,purple-lt :background nil))))
`(ansi-color-yellow ((t (:foreground ,yellow-lt :background nil))))
`(ansi-color-cyan ((t (:foreground ,slate :background nil))))
`(ansi-color-bright-red ((t (:foreground ,red2 :background nil))))
`(ansi-color-bright-green ((t (:foreground ,green :background nil))))
`(ansi-color-bright-blue ((t (:foreground ,blue :background nil))))
`(ansi-color-bright-magenta ((t (:foreground ,purple :background nil))))
`(ansi-color-bright-yellow ((t (:foreground ,yellow :background nil))))
`(ansi-color-bright-cyan ((t (:foreground ,slate :background nil))))
`(ansi-color-bright-black ((t (:foreground ,gray-50 :background nil))))
`(sh-heredoc ((t (:foreground ,almond)))) `(sh-heredoc ((t (:foreground ,almond))))
`(sh-quoted-exec ((t (:foreground ,orange2-lt)))) `(sh-quoted-exec ((t (:foreground ,orange2-lt))))

View file

@ -2,7 +2,7 @@
#+author: Howard X. Abrams #+author: Howard X. Abrams
#+date: 2025-11-24 #+date: 2025-11-24
#+filetags: emacs hamacs #+filetags: emacs hamacs
#+lastmod: [2026-09-11 Fri] #+lastmod: [2026-10-09 Fri]
A literate programming file for configuring Hammerspoon. A literate programming file for configuring Hammerspoon.
@ -76,7 +76,7 @@ To create specific key bindings for starting applications, I can:
end) end)
hs.hotkey.bind({"alt", "ctrl", "shift"}, "F", function() hs.hotkey.bind({"alt", "ctrl", "shift"}, "F", function()
hs.application.launchOrFocus("Firefox") hs.application.launchOrFocus("Vivaldi")
end) end)
hs.hotkey.bind({"alt", "ctrl", "shift"}, "C", function() hs.hotkey.bind({"alt", "ctrl", "shift"}, "C", function()

View file

@ -115,6 +115,8 @@ cat > "$HAMACS_DEST/init.el" <<EOF
(add-to-list 'package-archives (add-to-list 'package-archives
'("elpa-dev" . "https://elpa.gnu.org/devel/")) '("elpa-dev" . "https://elpa.gnu.org/devel/"))
(setq package-enable-at-startup nil)
;; Configure straight https://github.com/raxod502/straight.el#getting-started ;; Configure straight https://github.com/raxod502/straight.el#getting-started
(defvar bootstrap-version) (defvar bootstrap-version)

View file

@ -5,3 +5,4 @@
#+END_SRC #+END_SRC
`yas-selected-text` `yas-selected-text`
#+BEGIN_SRC `(ha-org-block-language-and)` #+BEGIN_SRC `(ha-org-block-language-and)`

View file

@ -8,9 +8,6 @@
* Work Issues * Work Issues
$0 $0
* Onboarding Work
See [[file:Onboarding-Work.org][Onboard-Work]] for all details.
* Distractions and Support * Distractions and Support
Anything that doesn't fit the above goes here. Anything that doesn't fit the above goes here.

View file

@ -224,6 +224,12 @@ Using the =colorize= plugin (see [[Plugins][plugins section below]]), we customi
export ZSH_COLORIZE_STYLE="coffee" export ZSH_COLORIZE_STYLE="coffee"
#+END_SRC #+END_SRC
While we are at it, let’s make it easier to read the =ls= output:
#+BEGIN_SRC zsh
export LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=33:so=01;35:do=01;35:bd=33;01:cd=33;01:or=31;01:mi=00:su=37:sg=30:ca=00:tw=30:ow=34:st=37:ex=01;32:*.7z=01;31:*.ace=01;31:*.alz=01;31:*.apk=01;31:*.arc=01;31:*.arj=01;31:*.bz=01;31:*.bz2=01;31:*.cab=01;31:*.cpio=01;31:*.crate=01;31:*.deb=01;31:*.drpm=01;31:*.dwm=01;31:*.dz=01;31:*.ear=01;31:*.egg=01;31:*.esd=01;31:*.gz=01;31:*.jar=01;31:*.lha=01;31:*.lrz=01;31:*.lz=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.lzo=01;31:*.pyz=01;31:*.rar=01;31:*.rpm=01;31:*.rz=01;31:*.sar=01;31:*.swm=01;31:*.t7z=01;31:*.tar=01;31:*.taz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tgz=01;31:*.tlz=01;31:*.txz=01;31:*.tz=01;31:*.tzo=01;31:*.tzst=01;31:*.udeb=01;31:*.war=01;31:*.whl=01;31:*.wim=01;31:*.xz=01;31:*.z=01;31:*.zip=01;31:*.zoo=01;31:*.zst=01;31:*.avif=01;35:*.jpg=01;35:*.jpeg=01;35:*.jxl=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:*~=00;90:*#=00;90:*.bak=00;90:*.crdownload=00;90:*.dpkg-dist=00;90:*.dpkg-new=00;90:*.dpkg-old=00;90:*.dpkg-tmp=00;90:*.old=00;90:*.orig=00;90:*.part=00;90:*.rej=00;90:*.rpmnew=00;90:*.rpmorig=00;90:*.rpmsave=00;90:*.swp=00;90:*.tmp=00;90:*.ucf-dist=00;90:*.ucf-new=00;90:*.ucf-old=00;90:"
#+END_SRC
** Language Support ** Language Support
Anything special for particular languages. Anything special for particular languages.
@ -486,8 +492,15 @@ The =EDITOR= variable that some programs use to edit files from the command line
With these variables defined, we can create simple aliases: With these variables defined, we can create simple aliases:
#+BEGIN_SRC zsh #+BEGIN_SRC zsh
alias e="$EDITOR" if [[ -n "$INSIDE_EMACS" ]]
alias te="$EDITOR" then
# If we are already in Emacs, no need to stall the terminal:
e() { emacsclient --eval "(find-file-other-window \"$1\")" }
te() { emacsclient --eval "(find-file \"$1\")" }
else
alias e="$EDITOR"
alias te="$EDITOR"
fi
alias ee="emacsclient --create-frame" alias ee="emacsclient --create-frame"
alias eee="emacsclient --create-frame --no-wait" alias eee="emacsclient --create-frame --no-wait"
#+END_SRC #+END_SRC
@ -496,7 +509,7 @@ With these variables defined, we can create simple aliases:
To work with [[https://github.com/akermu/emacs-libvterm][VTerm in Emacs]], we need to create this function: To work with [[https://github.com/akermu/emacs-libvterm][VTerm in Emacs]], we need to create this function:
#+BEGIN_SRC zsh #+BEGIN_SRC zsh :tangle no
vterm_printf() { vterm_printf() {
if [ -n "$TMUX" ] \ if [ -n "$TMUX" ] \
&& { [ "${TERM%%-*}" = "tmux" ] \ && { [ "${TERM%%-*}" = "tmux" ] \
@ -515,7 +528,7 @@ To work with [[https://github.com/akermu/emacs-libvterm][VTerm in Emacs]], we ne
This allows us to execute Emacs commands: This allows us to execute Emacs commands:
#+BEGIN_SRC zsh #+BEGIN_SRC zsh :tangle no
vterm_cmd() { vterm_cmd() {
local vterm_elisp local vterm_elisp
vterm_elisp="" vterm_elisp=""
@ -529,7 +542,7 @@ This allows us to execute Emacs commands:
For instance: For instance:
#+BEGIN_SRC zsh #+BEGIN_SRC zsh :tangle no
if [[ "$INSIDE_EMACS" = 'vterm' ]] if [[ "$INSIDE_EMACS" = 'vterm' ]]
then then
alias clear='vterm_printf "51;Evterm-clear-scrollback";tput clear' alias clear='vterm_printf "51;Evterm-clear-scrollback";tput clear'
@ -540,6 +553,14 @@ For instance:
fi fi
#+END_SRC #+END_SRC
** Eat a Terminal
To work with [[:ha-remoting.org::*Eat][Eat]], we need to load up its integration library:
#+BEGIN_SRC zsh :tangle no
[ -n "$EAT_SHELL_INTEGRATION_DIR" ] && source "$EAT_SHELL_INTEGRATION_DIR/zsh"
#+END_SRC
The problem with the Eat integration is it prepends a =0= that doesn’t seem to signify anything useful.
* Aliases * Aliases
Assuming we’ve installed [[https://github.com/lsd-rs/lsd][lsd]], let’s make an alias for it: Assuming we’ve installed [[https://github.com/lsd-rs/lsd][lsd]], let’s make an alias for it: