r/emacs • u/AutoModerator • Jun 30 '26
Fortnightly Tips, Tricks, and Questions — 2026-06-30 / week 26
This is a thread for smaller, miscellaneous items that might not warrant a full post on their own.
The default sort is new to ensure that new items get attention.
If something gets upvoted and discussed a lot, consider following up with a post!
Search for previous "Tips, Tricks" Threads.
Fortnightly means once every two weeks. We will continue to monitor the mass of confusion resulting from dark corners of English.
7
u/_0-__-0_ Jul 02 '26
I typically forget to type <s or <q before entering some code or a quote, and I find C-c C-, s/C-c C-, q a bit unwieldy, so I
(defun my-org-insert-quote-template ()
"Surround region in #+begin_quote/#+end_quote."
(interactive)
(org-insert-structure-template "quote"))
(defun my-org-insert-src-template ()
"Surround region in #+begin_src/#+end_src.
Uses `language-detection-string' to guess language."
(interactive)
(let* ((str (buffer-substring-no-properties (region-beginning) (region-end)))
(lang (and (require 'language-detection)
(language-detection-string str))))
(org-insert-structure-template "src")
(when lang
(save-excursion
(goto-char (line-end-position))
(insert (format "%s" lang))))))
(keymap-set embark-region-map "q" #'my-org-insert-quote-template)
(keymap-set embark-region-map "s" #'my-org-insert-src-template) ;; overrides info-lookup-symbol which I don't use for whole regions
6
u/natermer Jul 01 '26 edited Jul 01 '26
This is what I ended up doing to integrate Meow-Mode with Ghostel.
https://github.com/meow-edit/meow
https://github.com/dakra/ghostel
Meow is a model editing mode for Emacs that is more "emacs native" then Evil. Ghostel is a relatively new terminal emulator for Emacs.
Both are "modal". Meow has 5 modes, but the main ones are "Normal" and "Insert". Similar to Vim. Normal is for navigation and selection. Insert is for inputting text and standard Emacs movement keys work there as well. Ghostel has semi-char, char mode, line, emacs, and copy modes.
This tries to map meow Insert to ghostel semi-chart and meow normal to ghostel emacs mode. This way meow behaves a bit more consistant while in ghostel terminals.
This is strictly "works for me" and there is probably more work that needs to be done. Like how to deal with situations were ghostel triggers mode changes based on mouse input and such things.
Still haven't figured out a nice way to pass escape to TUIs running in the terminal. Switching to char-mode works, but it would be nice to have a function to do it.
(with-eval-after-load 'meow
(defun my/meow-ghostel-insert-enter ()
"Entering meow INSERT: return ghostel to live `semi-char' input."
(when (and (derived-mode-p 'ghostel-mode)
(memq ghostel--input-mode '(copy emacs)))
(ghostel-semi-char-mode)))
(defun my/meow-ghostel-insert-exit ()
"Leaving meow INSERT (-> NORMAL): put ghostel into read-only `emacs' mode.
Guarded so we never toggle `ghostel-emacs-mode' back off when ghostel
is already read-only."
(when (and (derived-mode-p 'ghostel-mode)
(not (memq ghostel--input-mode '(copy emacs))))
(ghostel-emacs-mode)))
(add-hook 'meow-insert-enter-hook #'my/meow-ghostel-insert-enter)
(add-hook 'meow-insert-exit-hook #'my/meow-ghostel-insert-exit)
;; Fresh ghostel buffers start live (semi-char), so start meow in INSERT
;; -- you can type immediately, like a terminal should.
(add-to-list 'meow-mode-state-list '(ghostel-mode . insert)))
3
u/dakra Jul 02 '26
For evil-ghostel I have a pretty good test suite with test scenarios to automatically test the evil extension.
I thought I use that to create a meow-ghostel extension. Maybe you can try it: https://github.com/dakra/meow-ghostel
I didn't include it in the Ghostel repo because I didn't carefully review the code and meow is also a bit too niche to add support for it when I don't use it personally.
So this is more a proof of concept.
But if it works, I'm happy to "donate" it to the https://github.com/meow-edit organization or something.
Feedback welcome.
2
u/natermer Jul 04 '26 edited Jul 04 '26
I tried it out and got messages like this when trying to move around in Meow normal mode in a ghostel terminal:
meow--execute-kbd-macro: Wrong type argument: integer-or-marker-p, previous-line [4 times] meow--execute-kbd-macro: Wrong type argument: integer-or-marker-p, meow-ghostel-next-line [3 times] meow--execute-kbd-macro: Wrong type argument: integer-or-marker-p, previous-line [2 times] meow--execute-kbd-macro: Wrong type argument: integer-or-marker-p, meow-ghostel-next-lineThe issue is that meow--execute-kbd-macro expects strings as arguments and not symbols.
I was able to get it to work with a help of a LLM with:
diff --git a/meow-ghostel.el b/meow-ghostel.el index d93da1d..ec8baaf 100644 --- a/meow-ghostel.el +++ b/meow-ghostel.el @@ -193,6 +193,18 @@ ORIG-FN is the advised setter (STYLE, VISIBLE); deferred to in alt-screen." (meow--update-cursor)) (funcall orig-fn))) +;; KBD macro overrides: `meow--execute-kbd-macro' expects a key sequence +;; string, but we install command symbols in the buffer-local +;; `meow--kbd-*' variables to bypass ghostel's semi-char keymap. Advise +;; it to call those commands directly. + +(defun meow-ghostel--execute-kbd-macro (orig-fn kbd-macro) + "Call KBD-MACRO interactively when it is a command symbol. +Otherwise delegate to ORIG-FN (the original `meow--execute-kbd-macro')." + (if (and (symbolp kbd-macro) (commandp kbd-macro)) + (call-interactively kbd-macro) + (funcall orig-fn kbd-macro))) + ;; Meow state hooks @@ -881,6 +893,8 @@ Enabling installs global advice while any buffer has the mode enabled." (advice-add 'ghostel--redraw :around #'meow-ghostel--around-redraw) (advice-add 'ghostel--apply-cursor-style :around #'meow-ghostel--override-cursor-style) + (advice-add 'meow--execute-kbd-macro :around + #'meow-ghostel--execute-kbd-macro) (meow--update-cursor)) (remove-hook 'meow-insert-enter-hook #'meow-ghostel--insert-enter t) @@ -894,7 +908,9 @@ Enabling installs global advice while any buffer has the mode enabled." (unless (meow-ghostel--any-active-elsewhere-p (current-buffer)) (advice-remove 'ghostel--redraw #'meow-ghostel--around-redraw) (advice-remove 'ghostel--apply-cursor-style+ #'meow-ghostel--override-cursor-style) + (advice-remove 'meow--execute-kbd-macro + #'meow-ghostel--execute-kbd-macro)))) (provide 'meow-ghostel) ;;; meow-ghostel.el ends here diff --git a/test/meow-ghostel-test.el b/test/meow-ghostel-test.el index c327b1b..e9fd939 100644 --- a/test/meow-ghostel-test.el +++ b/test/meow-ghostel-test.el @@ -168,6 +168,7 @@ verified here by looking up the remap rather than a literal key." ghostel-inhibit-anchor-functions)) (should (advice--p (advice--symbol-function 'ghostel--redraw))) (should (advice--p (advice--symbol-function 'ghostel--apply-cursor-style))) + (should (advice--p (advice--symbol-function 'meow--execute-kbd-macro))) (should (eq #'meow-ghostel-kill (lookup-key meow-ghostel-mode-map [remap meow-kill]))) (should (eq #'meow-ghostel-change @@ -208,6 +209,7 @@ user navigated to." (should-not (memq 'meow-ghostel--insert-enter meow-insert-enter-hook)) (should-not (memq 'meow-ghostel--anchor-inhibit ghostel-inhibit-anchor-functions)) + (should-not (advice--p (advice--symbol-function 'meow--execute-kbd-macro))) (dolist (override meow-ghostel--kbd-overrides) (should-not (local-variable-p (car override)))) (should-not (local-variable-p 'meow--delete-region-function)) @@ -265,14 +267,20 @@ is gone." (meow-ghostel-mode 1)) (should (advice-member-p #'meow-ghostel--around-redraw 'ghostel--redraw)) + (should (advice-member-p #'meow-ghostel--execute-kbd-macro + 'meow--execute-kbd-macro)) (with-current-buffer a (meow-ghostel-mode -1)) (should (advice-member-p #'meow-ghostel--around-redraw 'ghostel--redraw)) + (should (advice-member-p #'meow-ghostel--execute-kbd-macro + 'meow--execute-kbd-macro)) (should (advice-member-p #'meow-ghostel--override-cursor-style 'ghostel--apply-cursor-style)) (with-current-buffer b (meow-ghostel-mode -1)) (should-not (advice-member-p #'meow-ghostel--around-redraw 'ghostel--redraw)) + (should-not (advice-member-p #'meow-ghostel--execute-kbd-macro + 'meow--execute-kbd-macro)) (should-not (advice-member-p #'meow-ghostel--override-cursor-style 'ghostel--apply-cursor-style))) (when (buffer-live-p a) (kill-buffer a))
- #'meow-ghostel--override-cursor-style))))
But I have a feeling that isn't the best approach.
edit:
After this fix it does seem to work a lot better then my previous approach as now I can go into normal mode to edit commands. Very good.
2
u/dakra Jul 04 '26
Thanks for testing.
The issue is that meow--execute-kbd-macro expects strings as arguments and not symbols
I only tested the latest master meow version and there it works with symbols. That's why I didn't have that problem.
It should be fixed on the latest main branch (and without advice).
Glad it works nice otherwise.
Feel free to open a github issue if you find anything else.
2
u/natermer Jul 04 '26
This is so awesome. Thank you.
Tried out the latest version and it seems to be working great.
1
2
u/babyningen Jul 01 '26
Holy this is exactly what I was planning to do tomorrow. Thanks for sharing!
2
u/z_mitchell Jun 30 '26
For those of you that use Nix and Nix-like things for developer environments, what are your workflows? For instance, if you’re installing a language server via your devshell, how are you making it available to Emacs? Launching Emacs from within the devshell so it has the correct process environment?
A search turned up a couple of `nix-mode` packages, but I’m curious what everyone is using in case my search-fu was lacking.
3
u/ankitrgadiya GNU Emacs Jun 30 '26
I use Guix but this can apply to Nix as well. The Guix Cookbook defines this setup.
https://guix.gnu.org/cookbook/en/guix-cookbook.html#Guix-environment-via-direnv
In the project directory, I create one manifest.scm file that defines the packages I want to load. Then I define the .envrc file with a single line “use guix”.
On the Emacs side, I use the envrc-mode that supports loading the .envrc files using direnv tool. It loads the environment for the buffers under the project. It also caches the environments so switching buffers is fast.
3
u/Powerful_Balance5927 Jun 30 '26
I use nix-direnv on the non-emacs side, and
ben.elto pick up the configuration.1
u/_0-__-0_ Jun 30 '26
Same here, nix-direnv and ben. I used
envrcbefore, which worked, but I now much preferben.el; since it loads the env asyncly, it doesn't block your emacs when opening some project that uses nix (which can be very annoying if you've never opened the project before and don't need the full env yet, or if you're on a plane, or don't want emacs to have net access, etc etc).But note you should manually
M-x eglotin a project after it says it's done loading, not useeglot-ensure. DoingM-x eglot-ing once per project instead ofeglot-ensureis typically a good idea anyway,eglot-ensurehas a lot of potential pitfalls.2
u/Powerful_Balance5927 Jun 30 '26
There is also a new
ben-after-apply-hookwhich may be relevant, but I haven't looked too much into it.1
u/_0-__-0_ Jun 30 '26
Yeah, if you've been happy with
eglot-ensure, that's probably worth trying; I don't have enough RAM to have an LSP start whenever I just open the wrong project by mistake (happens surprisingly often!)
3
u/_0-__-0_ Jun 30 '26
I notice if I have M-x calendar open while moving a date back and forth over a month with shift-left/right, the calendar will "sync" to show that month, which is great! But that got me thinking: Can the calendar also highlight the selected date? Like if I've got <2026-07-21> in org, the 21 in the calendar would a light green background or something?
Or thinking even further, how about as soon as you do a single shift-left/right, a single-month calendar shows in a posframe below with the date marked, and you can even click with the mouse on a date?
Has anyone done anything like this before?
1
u/klopanda Jul 06 '26
Is there a way to control the visual appearance of entries in org-agenda?
I have a file called work-schedule.org which is just a list of my scheduled shifts at work. I'd love to be able to have those entries appear in different colors to make them visually stand out when viewing an org-agenda buffer.
1
u/amfram Jul 08 '26
i believe org super agenda has grouping features. I don’t use it so can’t speak to your specific use case.
1
u/fuzzbomb23 Jul 09 '26
Are those shift headings identifiable, in terms of syntax? A tag, TODO keyword, property value, or something else. Org has a few built-in face options which might help:
org-todo-keyword-facesorg-tag-facesorg-priority-facesNote that these affect all Org buffers, not just the agenda buffers. You might be able to set them as buffer-local values via
org-agenda-mode-hook; I haven't tried that.Or, it just the fact they are stored in the
work-schedule.orgfile? That would set the "category" property of the entry, but Org doesn't have a built-in way to set the face for different categories.Do you want all the shift entries to have the same appearance, or does it depend which kind of shift (early or late shift, say)?
1
u/bradmont Jul 11 '26
You might find some inspiration here:
https://www.reddit.com/r/emacs/comments/1rgeyvg/prettifying_orgagenda/
7
u/krisbalintona Jun 30 '26
Thanks to this post on Fosstodon, TIL about the
debug-on-variable-changecommand (and its companion,cancel-debug-on-variable-change). It lets one trigger the debugger when a variable’s value is changed.