Compare commits
6 commits
d30ae9a78b
...
c20eda48a8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c20eda48a8 | ||
|
|
82afd54a9c | ||
|
|
97e9b86026 | ||
|
|
d9f3ec8806 | ||
|
|
db51a66d8c | ||
|
|
c40a3827b3 |
15 changed files with 234 additions and 145 deletions
|
|
@ -6,7 +6,7 @@
|
|||
A literate programming file for bootstraping my Emacs Configuration.
|
||||
|
||||
#+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
|
||||
(lambda ()
|
||||
(setq gc-cons-threshold (* 100 1024 1024))))
|
||||
(setq gc-cons-threshold (* 200 1024 1024))))
|
||||
#+END_SRC
|
||||
|
||||
** 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
|
||||
|
||||
* 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
|
||||
(defun ha-emacs-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-clipboard.org"
|
||||
"ha-capturing-notes.org"
|
||||
"ha-code-notes.org"
|
||||
"ha-agendas.org"
|
||||
"ha-data.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-email.org"
|
||||
"ha-aux-apps.org"))
|
||||
"ha-code-notes.org"
|
||||
"ha-dashboard.org"))
|
||||
"List of org files that complete the hamacs project.")
|
||||
#+end_src
|
||||
|
|
@ -241,7 +241,7 @@ The list of /hamacs/ org-formatted files stored in =ha-hamacs-files= is selectiv
|
|||
(if (not all)
|
||||
ha-hamacs-files
|
||||
|
||||
(thread-last (rx ".org" string-end)
|
||||
(thread-last (rx (not ".") (+? any) ".org" string-end)
|
||||
(directory-files hamacs-source-dir nil)
|
||||
(append ha-hamacs-files)
|
||||
(--filter (not (string-match (rx "README") it)))
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ A literate programming file configuring critical applications.
|
|||
;; And tangle the file to recreate this one.
|
||||
;;
|
||||
;;; Code:
|
||||
#+end_src
|
||||
#+end_src
|
||||
|
||||
Can we call the following /applications/? I guess.
|
||||
* Agentic Interface
|
||||
|
|
@ -158,14 +158,8 @@ And point Emacs to it:
|
|||
|
||||
(setq agent-shell-anthropic-claude-acp-command
|
||||
(if (file-exists-p "/opt/homebrew")
|
||||
(list (file-expand-wildcards "/opt/homebrew/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
|
||||
(file-expand-wildcards "/opt/homebrew/bin/claude-agent-acp")
|
||||
'("/usr/local/bin/claude-agent-acp"))))
|
||||
#+END_SRC
|
||||
|
||||
*** Cursor
|
||||
|
|
@ -227,36 +221,6 @@ And let’s make that the default now:
|
|||
:config
|
||||
(setq agent-shell-preferred-agent-config (agent-shell-google-make-gemini-config)))
|
||||
#+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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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]].
|
||||
|
||||
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.
|
||||
|
||||
# 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)"
|
||||
(let* ((here (point))
|
||||
(entry (thread-last (imenu--make-index-alist t)
|
||||
;; Flatten hierarchy labels with dot separators:
|
||||
(ha-code-notes-location--flatten-index)
|
||||
;; Filter to only entries that occur after point:
|
||||
(seq-filter (lambda (e) (<= (cdr e) here)))
|
||||
;; Sort the remaining entries by position
|
||||
;; (since out flatten-index function
|
||||
;; doesn't guarantee the order):
|
||||
(seq-sort-by #'cdr #'>)
|
||||
;; And the first entry on the list is our goal:
|
||||
car)))
|
||||
(entry (ignore-errors
|
||||
(thread-last (imenu--make-index-alist t)
|
||||
;; Flatten hierarchy labels with dot separators:
|
||||
(ha-code-notes-location--flatten-index)
|
||||
;; Filter to only entries that occur after point:
|
||||
(seq-filter (lambda (e) (<= (cdr e) here)))
|
||||
;; Sort the remaining entries by position
|
||||
;; (since out flatten-index function
|
||||
;; doesn't guarantee the order):
|
||||
(seq-sort-by #'cdr #'>)
|
||||
;; And the first entry on the list is our goal:
|
||||
car))))
|
||||
(unless entry
|
||||
(error "No enclosing definition found for point"))
|
||||
(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
|
||||
(defun ha-code-notes-location--flatten-index (alist &optional prefix)
|
||||
"Flatten imenu ALIST into a list of (QUALIFIED-NAME . POSITION).
|
||||
Where the qualified-name matches what which-function/imenu expect.
|
||||
"Flatten imenu ALIST into a list of (NAME . POSITION).
|
||||
Where the name matches what which-function/imenu expect.
|
||||
|
||||
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\" ...)...)
|
||||
|
||||
This is called recursively, so PREFIX could be a class name, or
|
||||
other higher abstraction."
|
||||
;; Like `mapconcat' but lets us concat into something other than a string.
|
||||
;; Note that `mapcan' uses `nconc' which _mutates_ the `alist'.
|
||||
;; This is fine as a parameter that we then return:
|
||||
Called recursively, where PREFIX could be a class name, or other higher
|
||||
abstraction when the nesting represents a real outline (Org, Markdown).
|
||||
|
||||
Entries tagged with `imenu-kind' or `breadcrumb-kind' property (as Eglot
|
||||
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
|
||||
(lambda (entry)
|
||||
;; Some imenu backends (e.g. python.el) annotate names with their
|
||||
;; category, e.g. "Pair (class)" or "sum (def)". Strip that so
|
||||
;; names match what `which-function'/`add-log-current-defun'
|
||||
;; produce, and what gets stored as XREF_NAME in notes files.
|
||||
(let* ((name (replace-regexp-in-string
|
||||
(rx space "(" (one-or-more alpha) ")" string-end)
|
||||
"" (car entry)))
|
||||
(value (cdr entry))
|
||||
(qualified (if prefix (format "%s.%s" prefix name) name)))
|
||||
(if (listp value)
|
||||
(ha-code-notes-location--flatten-index value qualified)
|
||||
(list (cons qualified (if (markerp value) (marker-position value) value))))))
|
||||
(unless (or (null entry) (atom entry))
|
||||
(let* ((raw-name (car entry))
|
||||
(kind (and (stringp raw-name)
|
||||
(or (get-text-property 0 'imenu-kind raw-name)
|
||||
(get-text-property 0 'breadcrumb-kind raw-name))))
|
||||
(name (if (stringp raw-name)
|
||||
(replace-regexp-in-string
|
||||
(rx space "(" (one-or-more alpha) ")" string-end)
|
||||
"" (substring-no-properties raw-name))
|
||||
(format "%s" raw-name)))
|
||||
(value (cdr entry))
|
||||
(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))
|
||||
#+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/:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-code-notes-location-goto (file name offset)
|
||||
"Move point to the position described by relative location.
|
||||
|
||||
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
|
||||
OFFSET is the number of lines below NAME to position the point."
|
||||
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
|
||||
OFFSET is the number of lines below NAME to position the point."
|
||||
(when (and file (not (equal file (buffer-file-name))))
|
||||
(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)))
|
||||
(entry (assoc name index)))
|
||||
(if (not entry)
|
||||
(message "Definition `%s' no longer found in %s" name file)
|
||||
(when entry
|
||||
(goto-char (cdr entry))
|
||||
(when offset
|
||||
(forward-line offset)))))
|
||||
(forward-line offset)))))
|
||||
#+END_SRC
|
||||
|
||||
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
|
||||
;; initial . here marks it as hidden:
|
||||
(note-file (format "%s.%s-notes.org"
|
||||
orig-parent orig-base))
|
||||
(note-file (ha-code-notes-file orig-base orig-parent))
|
||||
(header (which-function))
|
||||
(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
|
||||
:config
|
||||
(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: "
|
||||
"#+TITLE: "
|
||||
(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."
|
||||
(interactive)
|
||||
(when (buffer-file-name)
|
||||
(if (string-match (rx "/." ; A hidden file
|
||||
(one-or-more (not "/"))
|
||||
"-notes.org" string-end)
|
||||
(buffer-file-name))
|
||||
(if (string-match ha-code-notes-rx (buffer-file-name))
|
||||
(ha-code-notes-return)
|
||||
(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 ()
|
||||
"Mark, in the fringe, every line in this buffer that has a note.
|
||||
Notes live in the paired `.BASE-notes.org' file (see
|
||||
`ha-code-notes') as headings whose XREF property matches this
|
||||
file, XREF_NAME names the function (inherited by subheadings from
|
||||
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
|
||||
pair back to an absolute line via `ha-code-notes-location-goto', since the function
|
||||
may have moved since the note was taken."
|
||||
Notes live in the paired `.BASE-notes.org' file (see
|
||||
`ha-code-notes') as headings whose XREF property matches this
|
||||
file, XREF_NAME names the function (inherited by subheadings from
|
||||
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
|
||||
pair back to an absolute line via `ha-code-notes-location-goto', since the function
|
||||
may have moved since the note was taken."
|
||||
(mapc #'delete-overlay ha-code-notes--fringe-overlays)
|
||||
|
||||
(setq ha-code-notes--fringe-overlays nil)
|
||||
(let* ((orig-file (buffer-file-name))
|
||||
(note-file (and orig-file
|
||||
(format "%s.%s-notes.org"
|
||||
(file-name-directory orig-file)
|
||||
(file-name-base orig-file))))
|
||||
(ha-code-notes-file
|
||||
(file-name-directory orig-file)
|
||||
(file-name-base orig-file))))
|
||||
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
|
||||
(insert-file-contents note-file)
|
||||
(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
|
||||
(defun ha-code-notes--fringe-notes-refresh-all ()
|
||||
"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))
|
||||
(with-current-buffer buf
|
||||
(when buffer-file-name
|
||||
|
|
|
|||
|
|
@ -535,17 +535,18 @@ The nerd font package takes a popular font like "Iosevka" and jams a bunch of th
|
|||
|
||||
** 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
|
||||
(add-hook 'text-mode-hook (lambda ()
|
||||
(dolist (pair '(("!?" . "‽")
|
||||
("ae" . "æ")
|
||||
("..." . "…") ; ??
|
||||
("??" . "⁇")
|
||||
;; ("<<" . "«")
|
||||
;; (">>" . "»")
|
||||
("AE" . "Æ")))
|
||||
("<<" . "«")
|
||||
(">>" . "»")
|
||||
(":-)" . "🙂")
|
||||
(":-D" . "😃")
|
||||
(";-)" . "😉")
|
||||
("..." . "…")))
|
||||
(push pair prettify-symbols-alist))))
|
||||
#+end_src
|
||||
|
||||
|
|
|
|||
|
|
@ -366,7 +366,7 @@ This expands on my global [[file:ha-config.org::*Bookmarks][Bookmarks]]:
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package bookmark-in-project
|
||||
:bindd
|
||||
:bind
|
||||
(("C-x r m" . bookmark-in-project-toggle)
|
||||
("C-x r M" . ha-bookmark-set))
|
||||
:config
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#+author: Howard Abrams
|
||||
#+date: 2024-07-07
|
||||
#+filetags: emacs hamacs
|
||||
#+lastmod: [2026-08-05 Wed]
|
||||
#+lastmod: [2026-09-22 Tue]
|
||||
|
||||
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.
|
||||
;;
|
||||
;; *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:
|
||||
;;
|
||||
;; This file contains a collection of functions to easy some of the
|
||||
;; 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:
|
||||
#+end_src
|
||||
* Introduction
|
||||
|
|
@ -937,13 +936,9 @@ Let's =provide= a name so we can =require= this file:
|
|||
#+DESCRIPTION: literate programming in Emacs Org Files.
|
||||
|
||||
#+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
|
||||
|
||||
#+OPTIONS: num:nil toc:t todo:nil tasks:nil tags:nil date: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
|
||||
|
||||
# Local Variables:
|
||||
# jinx-local-words: "parseable"
|
||||
# End:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#+date: 2020-09-18
|
||||
#+tags: emacs org
|
||||
#+startup: inlineimages
|
||||
#+lastmod: [2026-08-10 Mon]
|
||||
#+lastmod: [2026-10-09 Fri]
|
||||
|
||||
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
|
||||
(use-package define-word
|
||||
:config
|
||||
(ha-leader :keymaps 'text-mode-map
|
||||
(ha-leader
|
||||
"s d" '(:ignore t :which-key "dictionary")
|
||||
"s d d" '("define this word" . define-word-at-point)
|
||||
"s d a" '("define any word" . define-word)))
|
||||
|
|
@ -1183,7 +1183,8 @@ I create a configuration file in my home directory:
|
|||
"stop-words": false,
|
||||
"terminology": { "severity": "warning" },
|
||||
"unexpanded-acronym": { "severity": "warning" },
|
||||
"write-good": false
|
||||
"write-good": false,
|
||||
"unexpanded-acronym": false
|
||||
}
|
||||
}
|
||||
#+end_src
|
||||
|
|
|
|||
|
|
@ -1498,16 +1498,6 @@ Integration with the [[https://github.com/bash-lsp/bash-language-server][Bash LS
|
|||
#+begin_src sh
|
||||
brew install bash-language-server
|
||||
#+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:
|
||||
Provide a name to =require= this code.
|
||||
#+begin_src emacs-lisp :exports none
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(use-package vterm
|
||||
:config
|
||||
(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:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(use-package vterm
|
||||
:config
|
||||
(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
|
||||
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
|
||||
:straight (:host codeberg :repo "akib/emacs-eat"
|
||||
: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
|
||||
("C-c C-t" . ha-eat-narrow-to-shell-prompt-dwim))
|
||||
: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 ()
|
||||
(interactive)
|
||||
(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: 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:
|
||||
|
||||
#+BEGIN_SRC bash :tangle no
|
||||
|
|
|
|||
14
ha-theme.org
14
ha-theme.org
|
|
@ -438,6 +438,20 @@ Let’s make a /theme/:
|
|||
`(term-color-bright-yellow ((t (:foreground ,yellow))))
|
||||
`(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-quoted-exec ((t (:foreground ,orange2-lt))))
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#+author: Howard X. Abrams
|
||||
#+date: 2025-11-24
|
||||
#+filetags: emacs hamacs
|
||||
#+lastmod: [2026-09-11 Fri]
|
||||
#+lastmod: [2026-10-09 Fri]
|
||||
|
||||
A literate programming file for configuring Hammerspoon.
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ To create specific key bindings for starting applications, I can:
|
|||
end)
|
||||
|
||||
hs.hotkey.bind({"alt", "ctrl", "shift"}, "F", function()
|
||||
hs.application.launchOrFocus("Firefox")
|
||||
hs.application.launchOrFocus("Vivaldi")
|
||||
end)
|
||||
|
||||
hs.hotkey.bind({"alt", "ctrl", "shift"}, "C", function()
|
||||
|
|
|
|||
|
|
@ -115,6 +115,8 @@ cat > "$HAMACS_DEST/init.el" <<EOF
|
|||
(add-to-list 'package-archives
|
||||
'("elpa-dev" . "https://elpa.gnu.org/devel/"))
|
||||
|
||||
(setq package-enable-at-startup nil)
|
||||
|
||||
;; Configure straight https://github.com/raxod502/straight.el#getting-started
|
||||
|
||||
(defvar bootstrap-version)
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@
|
|||
#+END_SRC
|
||||
`yas-selected-text`
|
||||
#+BEGIN_SRC `(ha-org-block-language-and)`
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@
|
|||
* Work Issues
|
||||
$0
|
||||
|
||||
* Onboarding Work
|
||||
See [[file:Onboarding-Work.org][Onboard-Work]] for all details.
|
||||
|
||||
* Distractions and Support
|
||||
Anything that doesn't fit the above goes here.
|
||||
|
||||
|
|
|
|||
31
zshell.org
31
zshell.org
|
|
@ -224,6 +224,12 @@ Using the =colorize= plugin (see [[Plugins][plugins section below]]), we customi
|
|||
export ZSH_COLORIZE_STYLE="coffee"
|
||||
#+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
|
||||
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:
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
alias e="$EDITOR"
|
||||
alias te="$EDITOR"
|
||||
if [[ -n "$INSIDE_EMACS" ]]
|
||||
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 eee="emacsclient --create-frame --no-wait"
|
||||
#+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:
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
#+BEGIN_SRC zsh :tangle no
|
||||
vterm_printf() {
|
||||
if [ -n "$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:
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
#+BEGIN_SRC zsh :tangle no
|
||||
vterm_cmd() {
|
||||
local vterm_elisp
|
||||
vterm_elisp=""
|
||||
|
|
@ -529,7 +542,7 @@ This allows us to execute Emacs commands:
|
|||
|
||||
For instance:
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
#+BEGIN_SRC zsh :tangle no
|
||||
if [[ "$INSIDE_EMACS" = 'vterm' ]]
|
||||
then
|
||||
alias clear='vterm_printf "51;Evterm-clear-scrollback";tput clear'
|
||||
|
|
@ -540,6 +553,14 @@ For instance:
|
|||
fi
|
||||
#+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
|
||||
Assuming we’ve installed [[https://github.com/lsd-rs/lsd][lsd]], let’s make an alias for it:
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue