Emacs APAC: Announcing Emacs Asia-Pacific (APAC) virtual meetup, Saturday, September 28, 2024
-1:-- Announcing Emacs Asia-Pacific (APAC) virtual meetup, Saturday, September 28, 2024 (Post)--L0--C0--September 14, 2024 12:01 AM
-1:-- Announcing Emacs Asia-Pacific (APAC) virtual meetup, Saturday, September 28, 2024 (Post)--L0--C0--September 14, 2024 12:01 AM
Cursory provides a thin wrapper around built-in variables that affect the style of the Emacs cursor on graphical terminals. The intent is to allow the user to define preset configurations such as “block with slow blinking” or “bar with fast blinking” and set them on demand. The use-case for such presets is to adapt to evolving interface requirements and concomitant levels of expected comfort, such as in the difference between writing and reading.
cursory
Below are the release notes.
Cursory is in a stable state. This version includes quality-of-life refinements.
cursory-mode
simplifies how the state is storedCursory has functions to store and restore its state. In previous
versions, we would document how to use those by adding them to the
relevant hooks. This approach still works, though we now provide an
easier way to achieve the same result: just enable the cursory-mode
.
Technically, all this does is to set the hooks if enabled, and unsets them if disabled.
The “restore” phase is the same as before. For example:
;; Set last preset, if available, or fall back to the `bar' preset
;; from the `cursory-presets'.
(cursory-set-preset (or (cursory-restore-latest-preset) 'bar))
cursory-set-preset-hook
The cursory-set-preset-hook
is a normal hook (where functions are
invoked without any arguments), which is called after the command
cursory-set-preset
. Here are some ideas on how to use it:
;; Imagine you have a preset where you want minimal cursor styles.
;; You call this `focus' and want when you switch to it to change the
;; cursor color.
(defun my-cursory-change-color ()
"Change to a subtle color when the `focus' Cursory preset is selected."
(if (eq cursory-last-selected-preset 'focus)
(set-face-background 'cursor "#999999")
(face-spec-recalc 'cursor nil)))
;; Here we just show how to disable a given mode. Of course, we can
;; have something more sophisticated, which stores the last value and
;; restores it if the condition we are testing for here is not met.
;; Keeping it simple for now.
(defun my-cursory-change-color-disable-line-numbers ()
"Disable line numbers if the Cursory preset is `presentation' or `focus'."
(when (memq cursory-last-selected-preset '(presentation focus))
(display-line-numbers-mode -1)))
I am happy to include more examples here, if users have any questions.
Fixed a dependency for older Emacs versions. The subr-x
, which is
built into Emacs, needs to be explicitly loaded at compile time.
This makes some parts of the code work as expected. Thanks to Mehdi
Khawari for reporting the problem and Nicholas Vollmer for
suggesting this change. The exchange took place in issue 1:
https://github.com/protesilaos/cursory/issues/1. Users should
already have this change, as I published a minor release for it
(version 1.0.1
).
Added some missing metadata to the manual. This is useful for the indices and COPYING section.
Updated the relevant links to the package sources. The main repository is now on GitHub.
-1:-- Emacs: cursory version 1.1.0 (Post)--L0--C0--September 14, 2024 12:00 AM
2024-09-14
I’ve been reflecting on life for the past couple of months, and my world view has changed a lot. I feel like I have grown as a person, and I wanted to share the lessons I’ve learned during this time and throughout my life. Here are 5 life lessons from a 20-year-old.
A lot of people my age tend to question if calling an ambulance is the right thing to when faced with health and emergency situations. I can understand the reasoning, as these kinds of situations are almost always in gray areas.
Here is a simple trick if you want to decide if you should call an ambulance; call 911.
If the situation escalates into you thinking you might need an ambulance, that's all the reason you need. Even if you think the situation might be minor and you think you might waste a first responders time, you should call. Because this is what first responders are for and you won't waste anyone's time.
911 operators are trained professionals and will know what to do.
In the worst-case scenario, where you call 911 and an ambulance isn’t necessary, they will connect you to a medical professional who can guide you on what to do next and also will advise you to call again if the situation worsens.
And, worst case scenario, if you don't call 911, is the situation escalating and someone dying.
We humans tend to think the worst of situations. We feel like we are not good enough, feel like we don't have what it takes, and so on.
And we act accordingly to this. Whether in a work or a school setting, we find ourselves in situations where we don't want to speak up or step on anyone's toes.
We also feel like we are not good enough to achieve our dreams. Hell, sometimes we don't even dare to dream.
The best way to shake of this mindset is to fake your ideal mindset into existence.
In my opinion, while hard and sometimes cringe, it is the best way to deal with low self-confidence and self-worth.
Think of yourself as your ideal self, work hard, speak your mind on things, and dream big. Even if you are faking it and are well aware of the fact, with time, it will turn into reality.
Let's say that you want to learn about investing;
Introduction to investing books or textbooks are 10 times slower than watching a YouTube video.
But… they are 100 times more effective.
Let me explain, if you are not watching an actual university lecture. What you are watching is a fast-paced tutorial that tries to cram as much as possible into the shortest possible amount of time.
In these kinds of videos…
And don't get me started on how distracting it is to learn something in YouTube where entertainment is one click away and everything else is one tab away.
Yes, reading about something can be really slow. But because you are the one deciding the pace, your brain has an easier time absorbing the information.
If buying books are becoming too expensive or cumbersome, investing in a nice e-book reader might be a great idea.
Family and friends are one of the most important things in the world. You should love, cherish, and trust them. But you can't lean on them for all situations.
There will be times where you need or have to go through something on your own. These challenges tend to be hardest and being prepared is important.
Always work and invest in yourself. People can die, material things can perish. The only person you can depend on is you. Because if you are no more, then all is done.
I also think that life has a lot more meaning when you work on yourself regularly. When you eat healthy, read, exercise, or do anything that helps you become a better person. You feel like you are more in control and the things that cannot be changed becomes more bearable.
Until this year, I thought that success would come in the form of money or fame. But it turns out I was extremely wrong.
Money doesn't mean anything if you are not happy. Fame doesn't mean anything if you are not happy. Career advancement doesn't mean anything if you are not happy.
Of course, you don't have to be happy constantly. But if you have all the things above and you don't feel any happiness, what is the point?
Everyone would choose being a happy person in a cheap car than be a sad person in a Porsche.
If material things bring you happiness go for it. If traveling brings you happiness travel. If being alone and doing your own thing brings you happiness do that. Also, you don't have to do these things right now. Even dreaming about these is a lot of fun.
In my opinion, having the people you love nearby, working on your goals and self, and having the insight to recognize what truly matters in life is the key to happiness and living a content life.
-1:-- 5 Life Lessons (Post İsmail Efe Top (ismailefetop@gmail.com))--L0--C0--September 13, 2024 09:00 PM
Here’s a bit of Friday Red Meat for all you Emacs partisans in the eternal editor holy war.
Before you flame me, please keep in mind that I was a long time Vim user and often write approvingly of it. As I’ve often said, these days the editor wars are more about comic relief than a serious dispute. The real point of contention is not the editors themselves but the workflow that they engender.
Some people want a Lisp Machine, others want a small, fast, editor that’s good at editing and nothing more. The nice thing is that the Emacs/Vim duopoly lets you choose the environment most comfortable to you.
Anyway, enjoy the short diversion and get back to work. After all, we all have serious matters to deal with.
-1:-- Red Meat Friday: A Poetic Incursion Into The Editor Wars (Post jcs)--L0--C0--September 13, 2024 05:20 PM
I like checking out the #emacs hashtag when I put together Emacs News. In the past, I usually browsed the hashtag timeline on emacs.ch, which also picked up updates from other people that emacs.ch was following. Now that I've moved to @sacha@social.sachachua.com and emacs.ch is winding down, I wanted to see if there was a way for me to see a combined view using mastodon.social's API feed (paging by
max_id
as needed). I haven't enabled public
timeline feeds on my server, so I also need to reuse the OAuth mechanics from mastodon.el.
First, let's start by making a unified timeline. By digging around in mastodon-tl.el
, I found that I could easily create a timeline view by passing it a vector of toot JSONs.
(defun my-mastodon-fetch-posts-after (base-url after-date) "Page backwards through BASE-URL using max_id for all the posts after AFTER-DATE." (require 'plz) (require 'mastodon-http) (let ((results []) (url base-url) (use-mastodon-el (not (string-match "^http" base-url))) page filtered) (while url (setq page (if use-mastodon-el (mastodon-http--get-json (mastodon-http--api url) nil :silent) (seq-map (lambda (o) (cons (cons 'external t) o)) (plz 'get url :as #'json-read))) filtered (seq-filter (lambda (o) (string< after-date (assoc-default 'created_at o))) page)) (if filtered (progn (setq results (seq-concatenate 'vector filtered results) url (concat base-url (if (string-match "\\?" base-url) "&" "?") "max_id=" (number-to-string (1- (string-to-number (assoc-default 'id (elt (last page) 0))))))) (message "%s %s" (assoc-default 'created_at (elt (last page) 0)) url)) (setq url nil))) results)) (defun my-mastodon-combined-tag-timeline (later-than tag servers) "Display items after LATER-THAN about TAG from SERVERS and the current mastodon.el account." (interactive (list (org-read-date nil nil nil nil nil "-Mon") "#emacs" '("mastodon.social" "emacs.ch"))) (require 'mastodon) (require 'mastodon-tl) (require 'mastodon-toot) (let* ((limit 40) (sources (cons (format "timelines/tag/emacs?count=%d" limit) (mapcar (lambda (s) (format "https://%s/api/v1/timelines/tag/emacs?count=%d" s limit)) servers))) (combined (sort (seq-reduce (lambda (prev val) (seq-union prev (my-mastodon-fetch-posts-after val later-than) (lambda (a b) (string= (assoc-default 'uri a) (assoc-default 'uri b))))) sources []) (lambda (a b) (string< (assoc-default 'created_at b) (assoc-default 'created_at a)))))) (with-current-buffer (get-buffer-create "*Combined*") (let ((inhibit-read-only t)) (erase-buffer) (mastodon-tl--timeline combined) (mastodon-mode)) (setq mastodon-tl--buffer-spec `(account ,(cons mastodon-active-user mastodon-instance-url) buffer-name ,(buffer-name))) (display-buffer (current-buffer)))))
The tricky thing is that boosting and replying in
mastodon.el both use the toot IDs instead of the
toot URLs, so they only work for toots that came
in via my current mastodon.el account. Toots from
other timelines might not have been fetched by my
server yet. Adding an external
property lets me
find that in the item_json
text property in the
timeline buffer. For those toots, I can use
(mastodon-url-lookup (mastodon-toot--toot-url))
to open the toot in a new buffer that does allow
boosting or replying, which is probably enough for
my purposes.
(defun my-mastodon-lookup-toot () (interactive) (mastodon-url-lookup (mastodon-toot--toot-url)))
When I go through Emacs News, I have a shortcut
ethat boosts a post and saves it to as an Org Mode
capture with a link to the toot. I sometimes want
to reply, too. So I just need to intervene before
boosting and replying. Boosting and favoriting
both use mastodon-toot--action
, which looks up
the base-item-id
text property. Replying looks
up the item-json
property and gets the id
from
it.
(defun my-text-property-update-at-point (pos prop value) (let ((start (previous-single-property-change (or pos (point)) prop)) (end (next-single-property-change (or pos (point)) prop))) (put-text-property (or start (point-min)) (or end (point-max)) prop value))) (defun my-mastodon-update-external-item-id (&rest _) (when (mastodon-tl--field 'external (mastodon-tl--property 'item-json)) ;; ask the server to resolve it (let* ((response (mastodon-http--get-json (format "%s/api/v2/search" mastodon-instance-url) `(("q" . ,(mastodon-toot--toot-url)) ("resolve" . "t")))) (id (alist-get 'id (seq-first (assoc-default 'statuses response)))) (inhibit-read-only t) (json (get-text-property (point) 'item-json))) (when (and id json) (my-text-property-update-at-point (point) 'base-item-id id) (my-text-property-update-at-point (point) 'item-json (progn (setf (alist-get 'id json) id) (setf (alist-get 'external json) nil) json))))))
So now all I need to do is make sure that this is called before the relevant mastodon.el functions if I'm looking at an external toot.
(with-eval-after-load 'mastodon-tl (advice-add #'mastodon-toot--action :before #'my-mastodon-update-external-item-id) (advice-add #'mastodon-toot--reply :before #'my-mastodon-update-external-item-id) (advice-add #'mastodon-tl--thread :before #'my-mastodon-update-external-item-id))
The only thing is that I need to press RET after loading a thread with T (mastodon-tl--thread
) for some reason, but that's okay. Now I can boost and save posts with my usual Emacs News shortcut, and I can reply easily too.
I'm curious: how many toots would I be missing if I looked at only one instance's hashtag? Let's look at the #emacs hashtag toots on 2024-09-12:
(defun my-three-way-comparison (seq1 seq2 seq3 &optional test-fn) `(("1" ,@(seq-difference seq1 (seq-union seq2 seq3 test-fn) test-fn)) ("2" ,@(seq-difference seq2 (seq-union seq1 seq3 test-fn) test-fn)) ("3" ,@(seq-difference seq3 (seq-union seq1 seq2 test-fn) test-fn)) ("1&2" ,@(seq-difference (seq-intersection seq1 seq2 test-fn) seq3 test-fn)) ("1&3" ,@(seq-difference (seq-intersection seq1 seq3 test-fn) seq2 test-fn)) ("2&3" ,@(seq-difference (seq-intersection seq2 seq3 test-fn) seq1 test-fn)) ("1&2&3" ,@(seq-intersection (seq-intersection seq2 seq3 test-fn) seq1 test-fn)))) (defun my-three-way-comparison-report (label1 seq1 label2 seq2 label3 seq3 &optional test-fn) (let ((list (my-three-way-comparison seq1 seq2 seq3))) `((,(format "%s only" label1) ,@(assoc-default "1" list #'string=)) (,(format "%s only" label2) ,@(assoc-default "2" list #'string=)) (,(format "%s only" label3) ,@(assoc-default "3" list #'string=)) (,(format "%s & %s" label1 label2) ,@(assoc-default "1&2" list #'string=)) (,(format "%s & %s" label1 label3) ,@(assoc-default "1&3" list #'string=)) (,(format "%s & %s" label2 label3) ,@(assoc-default "2&3" list #'string=)) ("all" ,@(assoc-default "1&2&3" list #'string=))))) (assert (equal (my-three-way-comparison '("A" "A&B" "A&C" "A&B&C" "A1") '("B" "A&B" "A&B&C" "B&C") '("C" "A&C" "A&B&C" "B&C")) '(("1" "A" "A1") ("2" "B") ("3" "C") ("1&2" "A&B") ("1&3" "A&C") ("2&3" "B&C") ("1&2&3" "A&B&C")))) (let* ((later-than "2024-09-12") (earlier-than "2024-09-13") (results (mapcar (lambda (o) (cons (car o) (seq-map (lambda (o) (assoc-default 'uri o)) (seq-filter (lambda (toot) (string< (assoc-default 'created_at toot) earlier-than)) (my-mastodon-fetch-posts-after (format "%stimelines/tag/emacs?count=40" (cdr o)) later-than))))) `((mastodon-social . "https://mastodon.social/api/v1/") (emacs-ch . "https://emacs.ch/api/v1/") (my-instance . "")))) (intersections (let-alist results (my-three-way-comparison-report "mastodon.social" .mastodon-social "emacs.ch" .emacs-ch "my instance" .my-instance #'string=)))) (mapcar (lambda (row) (list (elt row 0) (length (cdr row)) (string-join (seq-map-indexed (lambda (o i) (org-link-make-string o (number-to-string (1+ i)))) (cdr row)) " "))) intersections))
mastodon.social only | 3 | 1 2 3 |
emacs.ch only | 1 | 1 |
my instance only | 0 | |
mastodon.social & emacs.ch | 9 | 1 2 3 4 5 6 7 8 9 |
mastodon.social & my instance | 0 | |
emacs.ch & my instance | 1 | 1 |
all | 11 | 1 2 3 4 5 6 7 8 9 10 11 |
Here's an Euler diagram visualizing it.
I love that I can tinker with mastodon.el to get it to combine the timelines. (I'm crossing the streams!) Yay Emacs!
-1:-- Combining Mastodon timelines using mastodon.el (Post Sacha Chua)--L0--C0--September 13, 2024 04:55 PM
-1:-- When is something executed? (mental model) (Post Kisaragi Hiu)--L0--C0--September 12, 2024 09:39 PM
Andrea Corallo has just announced that the first Emacs 30 pretest (30.0.91) is available for download and testing. You can check the NEWS file to see what’s new in the release.
As always, thanks to Eli, Andrea, and all the other devs who worked so hard to bring us this release and who keep Emacs a vital and thriving enterprise. The release of this pretest means that the release cycle for Emacs 30 is underway and we can expect the first release candidate sometime soon depending on how many errors are discovered in 30.0.91.
The developers depend on the Emacs community to help find those errors so if you can, please download and test the new version. It will help us all and move Emacs 30 closer to the official release.
-1:-- Emacs Pretest 30.0.91 (Post jcs)--L0--C0--September 12, 2024 04:02 PM
-1:-- evil-mode in terminal without Alt/Meta (Post)--L0--C0--September 11, 2024 10:00 PM
Well-ingrained into every Emacs user is the echo area, a one-stop shop to receive any kind of message from the editor, located at the bottom of the frame. Posting messages to this area from elisp couldn't be simpler:
(message "Hello world")
If we want to get a little fancier, we can propertize the text to add some styling.
(message (propertize "hello " 'face '(:foreground "#C3E88D")) (propertize "world" 'face '(:foreground "#FF5370")))
With this in mind, I set out to add a tiny command to ready-player.
I wanted the ability to ask what's on without switching to another buffer. The echo area is perfect for that. It should display track title, artist, and album.
(message (concat "Ahead " ;; title (propertize "Wire " 'face '(:foreground "#C3E88D")) ;; artist (propertize "The Ideal Copy" 'face '(:foreground "#FF5370")))) ;; album
This kinda work, but I wasn't convinced with the styling. Maybe I need multi-line?
(message (concat "Ahead\n" ;; title (propertize "Wire\n" 'face '(:foreground "#C3E88D")) ;; artist (propertize "The Ideal Copy" 'face '(:foreground "#FF5370")))) ;; album
I felt something was missing. If I could just add the album artwork as a thumbnail… The ideal layout would maybe look something like:
+-------+ | | Ahead | image | Wire | | The Ideal Copy +-------+
While the text-everywhere nature of Emacs buffers has many advantages, building more involved layouts can have its challenges. But hey, for that simple read-only message we're aiming at, we can certainly get creative without too much trouble. You see, Emacs has native svg support, so we can craft our fancy layout in elisp and tell Emacs to render it for us.
While I'm a noob at doing anything in svg from Emacs, adding an image and three labels, really isn't that difficult.
(message (let* ((image-width 90) (image-height 90) (text-height 25) (svg (svg-create (frame-pixel-width) image-height))) (svg-embed svg "path/to/thumbnail.png" "image/png" nil :x 0 :y 0 :width image-width :height image-height) (svg-text svg "Ahead" :x (+ image-width 10) :y text-height :fill (face-attribute 'default :foreground)) (svg-text svg "Wire" :x (+ image-width 10) :y (* 2 text-height) :fill "#C3E88D") (svg-text svg "The Ideal Copy" :x (+ image-width 10) :y (* 3 text-height) :fill "#FF5370") (with-temp-buffer (svg-insert-image svg) (buffer-string))))
The code is fairly self-explanatory. While there may be an even simpler way (please lemme know), I used a temporary buffer to embed the svg in the propertized text prior to feeding to the handy message
function.
…and with that, we get a richer display of the current track.
While I haven't experimented with other ways of creating multi-column layouts in Emacs (including images), I'd love to know if there's anything else available besides svg.
Help make them sustainable. Consider supporting this work.
-1:-- Spiffing up those echo messages (Post)--L0--C0--September 11, 2024 08:14 PM
A couple of months ago, I wrote about Álvaro Ramírez’s gluing together of Symbol Overlay and Multiple Cursors. I was really taken with Symbol Overlay and its ability to select a given symbol for further actions. There are many possible operations and symbol-overlay
lets you define your own commands for them. Of course, those commands are going to be hard to remember so it’s a perfect candidate for one of Charles Choi’s Casual apps.
Choi has, of course, stepped up to that challenge with Casual Symbol Overlay. As usual, it provides a Transient menu for those commands that you can invoke at will. You don’t, of course, have to use the menu. If you use a given command enough to remember it, you just use it but if you can’t remember the command, you can just invoke the menu and execute the command from there. It’s the best of both worlds.
At this point, I’ve just about decided to install Casual Suite so that I get all the Casual apps. You still have to configure them so they won’t be loaded unless you want them but Choi is making additions so often that it makes sense to reduce the friction of adding them. I don’t want them all but I do want a lot of them so it makes sense to add them all to my ELPA repository and configure the ones I actually want to be available.
-1:-- Casual Symbol Overlay (Post jcs)--L0--C0--September 11, 2024 04:08 PM
This is about the first version of show-font.el
. I just pushed the
changes to show-font.git and elpa.git, so expect the new package to be available in the coming hours. Below are some screen shots and the release notes for version 0.1.0
.
show-font
Always click to enlarge the image for best results.
With show-font
the user has the means to preview fonts inside of
Emacs. This can be done in the following ways:
The command show-font-select-preview
uses the minibuffer to
prompt with completion for a font on the system. The selected
font is then displayed in a bespoke buffer.
The command show-font-list
produces a list with all the fonts
available on the system. Each font on display is styled with its
given character set.
The show-font-mode
is a major mode that gets activated when the
user visits a .ttf
or .otf
file. It will preview with the font,
if it is installed on the system, else it will provide a helpful
message and an option to install the font (NOTE 2024-09-10: this
only works on Linux).
The previews include a pangram, which is controlled by the user option
show-font-pangram
. The default value is a playful take on the more
familiar “the quick brown fox jumps over the lazy dog” phrase. Users
can select among a few presets, or define their own custom string.
The function show-font-pangram-p
is available for those who wish to
experiment with writing their own pangrams (it is not actually limited
to the Latin alphabet).
The user option show-font-character-sample
provides a more complete
character set that is intended for use in full buffer previews (i.e.
not in the list of fonts). It can be set to any string. The default
value is a set of alphanumeric characters that are commonly used in
programming: a good monospaced font should render all of them
unambiguously.
Finally, the following faces control the appearance of various elements.
show-font-small
show-font-regular
show-font-medium
show-font-large
show-font-title
show-font-title-small
show-font-misc
show-font-button
-1:-- Emacs: show-font version 0.1.0 (Post)--L0--C0--September 10, 2024 12:00 AM
I got the following question on my post on how I handle secrets in my work notes:
Sounds like a nice approach for other secrets but how about
:dbconnection
for Orgmode andsql-connection-alist
?
I have to admit I'd never come across the variable sql-connection-alist
before. I've never really used sql-mode
for more than editing SQL queries and
setting up code blocks for running them was one of the first things I used
yasnippet for.
I did a little reading and unfortunately it looks like sql-connection-alist
can only handle string values. However, there is a variable
sql-password-search-wallet-function
, with the default value of
sql-auth-source-search-wallet
, so using auth-source is already supported for
the password itself.
There seems to be a lack of good tutorials for setting up sql-mode
in a secure
way – all articles I found place the password in clear-text in the config –
filling that gap would be a nice way to contribute to the Emacs community. I'm
sure it'd prompt me to re-evaluate incorporating sql-mode
in my workflow.
-1:-- Followup on secrets in my work notes (Post)--L0--C0--September 09, 2024 08:36 PM
This is a sort of Public Service Announcement. One of the great things about Org mode is the code block where you can run code in an Org buffer and have the results inserted into the Org document. I use this all the time. It’s a particularly elegant way of practicing literate programming and writing “live” documents that automatically rewrite themselves when the data the changes.
It’s usually a seamless process but there are gotchas for some languages. Sadly, Python, a widely used language, is one of those where you have to be careful. If you don’t follow the rules correctly, you can end up with erroneous results.
Recently, on the Org Mode mailing list there was a nice discussion of the problems that Python can present. As of right now, there are only three posts in the thread so you should read them all to get a full idea of what’s going on. The TL;DR is that you (usually) have to provide an explicit return
in your Python code to get the correct results into your Org buffer.
Python is the only language that I use—even occasionally—that has these problems: usually things just work. It is, therefore, worth spending a few minutes familiarizing yourself with the problems that Python and a few other languages have in the Babel environment.
-1:-- Babel and Python (Post jcs)--L0--C0--September 09, 2024 04:13 PM
The excellent Symbol Overlay package for Emacs lets one highlight a programming language symbol (such as a variable or function/method) and perform operations on it. Common operations on a highlighted symbol include bulk renaming and navigating between different instances of said symbol. Out of the box, Symbol Overlay defines a keymap (symbol-overlay-map
) where the user is intended to specify their preferred bindings to different symbol-overlay
commands. This setup adds more friction than I’d like though, as a user is forced to define and remember these bindings to get at the nice features of Symbol Overlay.
For folks who like working with highlighted symbols but are less enamored with remembering more bindings, I’m happy to announce a new Transient user interface for Symbol Overlay: Casual Symbol Overlay, now available on MELPA.
A screenshot of this menu is shown below:
Note that keymap symbol-overlay-map
will only be active over a highlighted symbol. To actually highlight a symbol, you'll need to define a binding for the command symbol-overlay-put
. I leave it to the reader to determine which binding to use here but personally, I have that assigned to a pre-released Casual Transient menu which I intend to release soon. For readers who prefer a menu-driven workflow, consider the binding for symbol-overlay-put
to be an interim solution until then.
If symbol-based operations are new to you, I encourage you to give them a try, especially if you code. They can be genuinely useful.
-1:-- Announcing Casual Symbol Overlay (Post Charles Choi)--L0--C0--September 09, 2024 04:00 PM
Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Mastodon #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, communick.news, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!
-1:-- 2024-09-09 Emacs news (Post Sacha Chua)--L0--C0--September 09, 2024 01:18 PM
-1:-- What is the best pointer tagging method? (Post)--L0--C0--September 09, 2024 12:00 AM
As most of you know, I’m a big fan of using literate programming techniques in the context of what might be described as “devops”. The technique boils down to writing an Org file with code blocks that document how you are solving a particular problem. The key is that the code blocks are executable and are what you actually use to solve the problem. Howard Abrams has a really good introduction to the idea in a post and subsequent video.
Magnus Therning has a nice nice post that expands on the same theme. His wrinkle is that the applications he’s interacting with require login credentials. For a long time, he simply kept those credentials as plain text in his Org file but, of course, he realized that was a bad thing.
He solved the problem by putting his credentials in his .authinfo
file and accessing them with the auth-source library. He wrote a couple of functions that used the auth-source
library to retrieve the necessary credentials. He populated these in a properties block. This is perfect because the source code doesn’t show any secrets but those secrets are made available to the executing code.
I do something similar to retrieve secrets that I don’t want exposed in plain text. The .authinfo
file and associated library is a really useful set of tools to enable access to secure applications without exposing the required credentials. Take a look at his post to see how easy it is.
-1:-- Using .authinfo With Org Code Blocks (Post jcs)--L0--C0--September 08, 2024 03:45 PM
A couple of months ago, I introduced Ready Player Mode, an Emacs major mode used to peek at media files from my beloved text editor. The goal was simple. Treat opening media files like any other file, that is, open and go.
The initial implementation served me well while reviewing lots of tiny audio files I used to practice learning a new language. At this point, I started thinking, could I use ready-player for regular music consumption? The thing is, long ago I had stopped buying music and relied on streamed music from online services. Could I go back to offline?
Dusting off my old media collection brought lots of memories as I rediscovered tunes. Having said that, the ready-player experience wasn't quite cutting it for an extended listening experience. I no longer wanted to occasionally peek at media to learn a language. I wanted to load a full music collection. I wanted random access to everything. I wanted Emacs to remember what I was listening to across sessions… While I did add some pluggable flows, I still needed additional changes to make the experience more pleasant.
While plugging away at my own ready-player's pet peeves, I also collected a handful of feature requests. Let's go over the latest features.
While not a feature I initially thought ranked highly in priority, I now find myself seeking audio files from time to time. Ready Player delegates all playback to the likes of mpv, vlc, mplayer, and so on… Up until now, interacting with these utilities merely consisted of feeding a media file path on to the respective process.
Command line utilities like mpv
offer socket communication via --input-ipc-server
to enable further requests like seeking forward and back. Ready player now supports seeking via mpv. Maybe support for other utilities can be added in the future.
If you're on a recent version of ready-player, seeking is automatically enabled if you've got mpv installed and aren't explicitly customizing ready-player-open-playback-commands
. The default value takes care of things:
(defcustom ready-player-open-playback-commands '(("mpv" "--audio-display=no" "--input-ipc-server=") ("vlc") ("ffplay") ("mplayer")) "..." :type '(repeat (list string)) :group 'ready-player)
Until now, ready-player could only play and stop, so you always had to start playing tracks from the beginning. With mpv
ipc support now in place, adding pause/resume was a breeze. Like seek, it should just work for ya if mpv
is on your system and no explicit customization of ready-player-open-playback-commands
.
While repeating current playlist (or directory) was already supported, there was a feature request to enable repeating files. Toggling repeat now cycles through available modes.
With ready-player delegating to a single utility for either audio or video playback, folks may have a need to specify different utilities for either of these two. While I'm happy for mpv
to handle both audio and video now have a couple of prepending options.
Prepend each utility with either the built-in ready-player-is-audio-p
or ready-player-is-video-p
functions, or maybe create your own predicate helper.
(setq ready-player-open-playback-commands '((ready-player-is-audio-p "ffplay") (ready-player-is-video-p "mpv")))
In this example, we delegate mp3 and ogg playback to ffplay and everything else to mpv.
(setq ready-player-open-playback-commands '((("mp3" "ogg") "ffplay") ("mpv")))
Automatically start playing once file opens. No need for user to explicitly request playback.
Open a dired buffer and mark the currently played file.
While I talked about how the dired abstraction made basic m3u playlist support possible, it wasn't until recently that I included this experiment in the package itself. In addition, .m3u are now recognized by Emacs and automatically open like any other file: find-file, dired, projectile…
With the dired abstraction at its core, ready player can load any dired buffer. You could do something like:
M-x find-dired RET
."-iname \*.mp3 -o -iname \*.ogg -o -iname \*.m4a"
RET.M-x ready-player-load-dired-buffer
RET.
While uber flexible, there's no need to regularly do that, so you can now invoke M-x ready-player-load-directory
and it will recursively find all media files in it.
While we can always get back to the player buffer via our favourite buffer-switching mechanism (I like ivy's ivy-switch-buffer), we now have M-x ready-player-view-player
available for quicker toggle.
Playback is now remembered across Emacs sessions. Toggling player view (C-c m m binding) or playback (C-c m SPC binding) starts the last song you were playing on your previous Emacs session.
We now have automatic indexing, which enables richer searching across your collection, not to mention that random access I was craving.
Last but not least, you may have noticed a handful of key bindings throughout the post. Single-character bindings all work within a ready-player buffer. Bindings prefixed C-c m
are now globally available when ready-player-mode
is turned on. This can be customized via ready-player-set-global-bindings
.
If you find this package useful or got the features you wanted, please consider sponsoring the work. I've left my tech job (maybe a post for another time) and looking to make projects like ready-player self-sustainable.
If you're an iOS/macOS user, you can also buy my apps. Here's another freebie ( macosrec) I've put out there, which I regularly use to capture Emacs demos for this blog.
You may also enjoy this blog and all the tips I share. Blog posts take time. Consider sponsoring my blog.
I've built other Emacs packages you may already use or would like to. Maybe I already built a feature request? Consider sponsoring:
I'm also building lmno.lol, a new blogging platform, with drag and drop to the web. Maybe you want to try that too? Get in touch.
Thank you!
Álvaro
-1:-- Seek and you shall find (Post)--L0--C0--September 07, 2024 01:27 PM
As an avid ArtRage user for almost 10 years I have in the past delved into the subtle art of editing arscript files:
-1:-- New Package arscript-mode (Post)--L0--C0--September 07, 2024 07:55 AM
Raw link: https://www.youtube.com/watch?v=yHHlYB3zE3U
Gavin does videos about Emacs, Vim, and related technology issues. Follow the channel:
In this ~1-hour video I talk with Gavin about all sorts of interesting topics:
Thanks to Gavin for this interview! I had a good time and learnt new things in the process. I hope you will enjoy it as well.
-1:-- I talked with Gavin Freeborn about Emacs, philosophy, life, and politics (Post)--L0--C0--September 07, 2024 12:00 AM
-1:-- How to setup python-lsp-server with lsp-mode using pipx (Post)--L0--C0--September 07, 2024 12:00 AM
It is a while I don't post about code-compass. I recently jumped back in the consulting world and it is a hectic life! In a couple of months I moved from a project to another. Furthermore, I cannot say I got somebody introducing me to the software architecture of these projects (or even their status).
Lucky me these years (from Ph.D. to industry times) have given me some experience, so my boat is well equipped for this wavy sea. Also I have a great tool: in both projects I just had to rely on my Emacs for a reliable code-compass.
So armed of hotspots, knowledge and communication graphs with a bit of churn, fragmentation and complexity on the side, I could get up and running faster than ever! Yay!!
One thing I have been missing is to explore graphically who dedicated themselves to the lovely art of refactoring. Indeed, the project on which I rely, the fantastic code-maat, offers a refactoring analysis. This finds who has deleted most lines in a file using Git commits information.
Naturally deletions are an approximation for refactoring, but good enough as less code is always an improvement (at least for our eyes).
Well there I go: I added it just now. It was pretty easy because is super-similar to the knowledge graph implementation. So a tweak here and there and it is now available.
Below a video that gives you a sense of what it is about.
If you want to try that yourself it is easy: just try out code-compass ;)
Happy refactoring!
-1:-- Emacs as your code-compass: who is the person who refactored most in this project? (Post)--L0--C0--September 07, 2024 12:00 AM
Over at the Emacs subreddit, harmanola, an Emacs user of 16 years, says that he’s recently switched from Emacs to Cursor, the AI code editor. It’s his opinion that Emacs has become unstable, that he’s tired of its “non-standard defaults”, that AI can increase his productivity by 5 times, that Emacs doesn’t scale, and that its developers aren’t on Discord. He also thinks that Emacs might be history soon.
One hardly knows where to begin. Well, I may not but the commenters certainly do. If there was ever a legitimate point to harmanola’s post, it got demolished by one or more of the commenters. To me, the silliest of his arguments is that one needs an “AI editor” to be productive. It seems to me that the AI suggestions are usually just slightly better than the code generated by previous editors that offered to write code for you: great for folks who are mostly generating boilerplate but used by virtually no one else.
The silliness about the Emacs developers not being on Discord strikes me as revealing a sense of entitlement: “I would like your help but I don’t want to go where you give it; please come over here instead.” If you spend 10 minutes on the Emacs mailing list you can’t help but be impressed by how much time guys like Eli Zaretskii spend—for free—on Emacs. As one of the commenters noted, all the things that comprise a healthy development environment—bug fixes, responding to pull requests, and regular updates—are, in fact, happening.
I’m sorry to see harmanola abandon Emacs and I hope he finds happiness elsewhere but his arguments for why we should leave Emacs for an AI editor just don’t withstand scrutiny.
-1:-- 🥩 Red Meat Friday: Should You Replace Emacs With An “AI Editor”? (Post jcs)--L0--C0--September 06, 2024 04:06 PM
Last month, I wrote about Charles Choi’s post on the the on package-install-upgrade-built-in variable and how it controls the upgrading of builtin packages. The TL;DR is that when it’s set to t
, package.el
treats builtin packages as if they had been installed like any other 3rd party package for upgrading purposes.
My first inclination was to wonder why anyone would not want to have it set to t
. I could imagine some outlying cases where it didn’t make sense but mostly I’d have expected that upgrading builtin packages was what most users wanted.
Apparently not. Over at the Emacs subreddit, jonas37 asks if people are setting package-install-upgrade-built-in
and the comments are revealing. It’s hard to imagine the answer would be controversial but lots of people have strong feelings on the matter.
Take a look at the comments to see what I mean. The answer, as it usually is, is that “it depends”. In short, it’s hard to automate the decision. Sometimes you want to upgrade the builtins and sometimes you don’t.
It’s easy to take the position that your editor, whatever it is, should take care of things for you, but people who do take that position are the first to complain when the algorithmic decision is not to their liking. Sadly, sometimes we just need to engage with Emacs and tell it what we want it to do about upgrading our packages. For many cases. setting apackage-install-upgrade-built-in
to t
is probably the right decision but sometimes not. It, as they say, depends.
-1:-- More On Upgrading Builtins (Post jcs)--L0--C0--September 05, 2024 03:28 PM
-1:-- Redirecting from under a load balancing NGINX (Post Kisaragi Hiu)--L0--C0--September 04, 2024 05:54 PM
Charles Choi is announcing another member of his casual suite: Casual Agenda. Like the other members of his suite, Casual Agenda provides a Transient driven menu that helps you navigate the arcane functionality of Org Agenda View.
I say “arcane” because although it’s easy to use Agenda View to simply list the content of the target files, there’s a lot more functionality hidden in obscure commands that even if you know they exist are hard to remember. Remembering the commands is even harder because Org makes them context sensitive.
Take a look at Choi’s post to see the menus and how they work with each other. It’s a nice system and probably worth installing even if you don’t use the commands often. Especially if you don’t use them often.
I know these command exist but I can never figure out how to access them so I’m really glad to see this latest addition to Choi’s suite. If you’re in the same situation, you should consider installing Casual Agenda.
You can, alternatively, simply install Casual Suite to get all the apps in the collection. This has the advantage that you automatically get additions to the suite when Choi adds them. All the apps have to be invoked explicitly so they never get in the way. If, like me, you follow Choi’s recommendation to bind them all to Ctrl+o, you need only remember a single command to bring up the appropriate menu when you need it.
As I’ve said before, I really like this set of applications and recommend you install the ones you need or possibly just install the entire suite.
-1:-- Casual Agenda (Post jcs)--L0--C0--September 04, 2024 04:09 PM
-1:-- Anki bookmarks (Post)--L0--C0--September 04, 2024 01:27 PM
Denote aims to be a simple-to-use, focused-in-scope, and effective note-taking and file-naming tool for Emacs.
Denote is based on the idea that files should follow a predictable and descriptive file-naming scheme. The file name must offer a clear indication of what the contents are about, without reference to any other metadata. Denote basically streamlines the creation of such files or file names while providing facilities to link between them (where those files are editable).
Denote’s file-naming scheme is not limited to “notes”. It can be used for all types of file, including those that are not editable in Emacs, such as videos. Naming files in a constistent way makes their filtering and retrieval considerably easier. Denote provides relevant facilities to rename files, regardless of file type.
denote
Below are the release notes.
Denote is stable and reliable though we keep adding minor refinements to it. Remember that many—if not all—of these are intended for experienced users who have developed their own workflow and want to adapt Denote to its particularities. We may call them “power users”.
New users do not need to know about every single feature. A basic
configuration is enough and is why the original video I did about
Denote (from even before I published version 0.1.0
) is still relevant.
For example:
;; Start with something like this.
(use-package denote
:ensure t
:bind
(("C-c n n" . denote)
("C-c n r" . denote-rename-file)
("C-c n i" . denote-link) ; "insert" mnemonic
("C-c n b" . denote-backlinks))
:config
(setq denote-directory (expand-file-name "~/Documents/notes/")))
And here is the same idea with a little bit more convenience:
;; Another basic setup with a little more to it.
(use-package denote
:ensure t
:hook (dired-mode . denote-dired-mode)
:bind
(("C-c n n" . denote)
("C-c n r" . denote-rename-file)
("C-c n l" . denote-link)
("C-c n b" . denote-backlinks))
:config
(setq denote-directory (expand-file-name "~/Documents/notes/"))
;; Automatically rename Denote buffers when opening them so that
;; instead of their long file name they have a literal "[D]"
;; followed by the file's title. Read the doc string of
;; `denote-rename-buffer-format' for how to modify this.
(denote-rename-buffer-mode 1))
denote-sort-dired
command is more configurableThe denote-sort-dired
command asks for a literal string or regular
expression and then produces a fully fledged Dired listing of matching
files in the denote-directory
. Combined with the efficient Denote
file-naming scheme, this is a killer feature to collect your relevant
files in a consolidated view and have the full power of Dired available.
By default denote-sort-dired
prompts for the file name component to
sort by and then asks whether to reverse the sorting or not. Users who
want a more streamlined experience can configure the user option
denote-sort-dired-extra-prompts
.
It is possible to skip the prompts altogether and use the default values for (i) which component to sort by and (ii) whether to reverse the sort. To this end, users can have something like this in their configuration:
;; Do not issue any extra prompts. Always sort by the `title' file
;; name component and never do a reverse sort.
(setq denote-sort-dired-extra-prompts nil)
(setq denote-sort-dired-default-sort-component 'title)
(setq denote-sort-dired-default-reverse-sort nil)
For me, Dired is one of the best things about Emacs and I like how it combines so nicely with Denote file names (this is the cornerstone of Denote, after all).
denote-sort-dired
sorting functions are customisablePower users may want to control how the sorting works and what it is matching on a per file-name-component basis. The user options are these:
denote-sort-title-comparison-function
.denote-sort-keywords-comparison-function
.denote-sort-signature-comparison-function
.One use-case is to match specific patterns inside of file names, such as Luhmann-style signatures. I wrote about this in the manual as well as on my blog (with screenshots): https://protesilaos.com/codelog/2024-08-01-emacs-denote-luhmann-signature-sort/.
Thanks to Riccardo Giannitrapani for discussing this with me and helping me understand the use-case better. This was done via a private channel and I am sharing it with permission.
All our Org dynamic blocks that produce links to files now read the
parameter :include-date
. When it is set to t
, the listed files
will include their corresponding date inside of parentheses after the
file’s title.
Thanks to Sergio Rey for describing this idea to me. This was done via a private channel and the information is shared with permission.
The optional Org dynamic blocks we define let users collect links to other files (and more) in a quick and effective way. Each block accepts parameters which control its output, such as how to sort files.
All our dynamic blocks now accept the :excluded-dirs-regexp
. This is
a regular expression which is matched against directory file system
paths. Matching directories and their files are not included in the
data handled by the dynamic block.
Note that we have the user option denote-excluded-punctuation-regexp
which defines a global preference along the same lines.
I did a video about this feature: https://protesilaos.com/codelog/2024-07-30-emacs-denote-exclude-dirs-org-blocks/.
Thanks to Claudio Migliorelli for discussing this idea with me. It was done via a private channel and this information is shared with permission.
We already had an Org dynamic block that would insert file contents.
Though that one inserts files as they are, optionally without their
front matter. However, users may have a workflow where they want to
eventually copy some of the block’s output into the main file they are
editing, at which point it is easier for the entire inserted file to
appear as a series of headings. The #+title
of the inserted file
becomes a top-level heading and every other heading is pushed deeper
one level.
To this end, we provide the Org dynamic block known as denote-files-as-headings
.
Insert it with the command denote-org-extras-dblock-insert-files-as-headings
or select it with the minibuffer after calling Org’s own command
org-dynamic-block-insert-dblock
.
The top-level headings (those that were the #+title
) can optionally
link back to the original file. Though please read the manual for all
the parameters this dynamic block takes.
The Org dynamic block for backlinks can now read the optional
:this-heading-only
parameter. When it is set to t
, the block will
only include links that point to the specific heading inside of the
current file. Otherwise, backlinks are about the whole file.
To insert such a dynamic block, use the command
denote-org-extras-dblock-insert-backlinks
.
By default, the buffer produced by the command denote-backlinks
has
a compact view of showing the file names linking to the current file.
With the user option denote-backlinks-show-context
set to a non-nil
value, the backlinks buffer produces a detailed listing of matching
results, where the links are shown in their original context.
Users can now choose to have this on-demand by calling the command
denote-backlinks-toggle-context
which switches between the detailed
and compact views.
This blog post I wrote about it include screenshots: https://protesilaos.com/codelog/2024-07-25-emacs-denote-backlinks-context-toggle/.
The denote-templates
variable allows the user to specify one or more
named templates which can then be inserted during the creation of a
new note. One way to be prompted for a template among those specified
is to modify the denote-prompts
user option and then use the regular
denote
command. Another way is to use the command denote-template
(alias denote-create-note-with-template
), which will prompt for the
template to use.
Templates ordinarily have a string as their value, though now their value can also be the symbol of a function. This function takes no arguments and is expected to return a string. Denote takes care to insert that below the front matter of the new note.
So it can look like this:
(setq denote-templates
`((report . "* Some heading\n\n* Another heading") ; A string with newline characters
(blog . my-denote-template-function-for-blog) ; the symbol of a function that will return a string
(memo . ,(concat "* Some heading" ; expand this `concat' into a string
"\n\n"
"* Another heading"
"\n\n"))))
Thanks to skissue (Ad) for the contribution in pull request 398: https://github.com/protesilaos/denote/pull/398. The change is small, meaning that its author does not need to assign copyright to the Free Software Foundation.
Also thanks to Jean-Philippe Gagné Guay for extending this to
denote-org-capture
. Done in pull request 399:
https://github.com/protesilaos/denote/pull/399. Jean-Philippe is a
long-time contributor who has assigned copyright to the Free Software
Foundation.
denote-rename-buffer-mode
can now show if a file has backlinksThis global minor mode takes care to rename the buffers of Denote files to a pattern that is easier for users to read. As with everything, it is highly configurable. The default value now includes an indicator that shows if the current file has backlinks (other files linking to it).
The exact characters used in this indicator are specified in the new
user option denote-rename-buffer-backlinks-indicator
. The default
value is "<-->"
, which hopefully communicates the idea of a link
(but, yeah, symbolism is hard). Users may want to modify this to add
some fancier Unicode character.
Thanks to Ashton Wiersdorf for the original contribution in pull request 392: https://github.com/protesilaos/denote/pull/392. Ashton has assigned copyright to the Free Software Foundation.
denote-rename-buffer-format
has changedIn the same theme as above, the user option denote-rename-buffer-format
has a new default value. Before, it would only show the title of the
file. Now it shows the aforementioned denote-rename-buffer-backlinks-indicator
,
if there are backlinks, plus the title, plus a literal "[D]"
prefix.
The prefix should make it easier to spot Denote files in a buffer
listing.
Read the documentation of denote-rename-buffer-format
for how to
tweak this to your liking.
denote-kill-buffers
This controls whether and when Denote should automatically kill any buffer it generates while creating a new note or renaming an existing file. The manual describes the details.
By default, Denote does not kill any buffers to give users the chance to review what is on display and confirm any changes or revert them accordingly.
Thanks to Jean-Philippe Gagné Guay for the contribution in pull request 426: https://github.com/protesilaos/denote/pull/426. This is related to issues 273 and 413, so also thanks to Vineet C. Kulkarni and mentalisttraceur for their participation and/or questions.
denote-journal-extras-new-or-existing-entry
handles any filename component orderVersion 3.0.0
of Denote introduced a new option to rearrange the
file name components. All Denote commands should respect it. We did,
however, have a problem with the command denote-journal-extras-new-or-existing-entry
which was not recognising the date properly.
Thanks to Jakub Szczerbowski for the contribution in pull request 395: https://github.com/protesilaos/denote/pull/395. The change is small, meaning that Jakub does not need to assign copyright to the Free Software Foundation.
While I am documenting this here, users should already have the fix as
I published a minor release for it in July (in fact, there were 8
minor releases in the aftermath of the 3.0.0
release, which
addressed several small issues).
denote-rename-file-using-front-matter
recognises the file-at-point in DiredThis makes it consistent with how denote-rename-file
works. I am
implemented this in response to issue 401 where Alp Eren Kose assumed
it was the default behaviour: https://github.com/protesilaos/denote/issues/401.
I think it makes sense to have it this way to avoid such confusion.
Still, it seems easier to edit the file and call denote-rename-file-using-front-matter
directly, rather do an intermediate step through Dired.
denote-rename-file-using-front-matter
does not ask to rewrite front matterThe workflow for this command is that the user modifies the front matter, invokes the command, and Denote takes care to rename the file accordingly. We had a regression were this would happen as expected, but Denote would still prompt if it was okay to update the front matter. That made no sense.
As with the change mentioned above, this was also fixed in a minor release so that users would not have to wait all this time.
denote-add-links
and denote-find-link
commands always works inside a siloThis was always the intended behaviour, though there was an issue with the implementation that prevented the directory-local value from being read.
Thanks to yetanotherfossman for reporting the problem with
denote-add-links
in issue 386 and to Kolmas for doing the same for
denote-find-link
:
Also thanks to Jean-Philippe Gagné Guay for following up with a change to the code that should address the underlying problem with temporary buffers. This was done in pull request 419: https://github.com/protesilaos/denote/pull/419.
A case we already handled was org-capture
buffers. Another one is
the buffer produced by the command org-tree-to-indirect-buffer
.
Thanks to coherentstate for bringing this matter to my attention in issue 418: https://github.com/protesilaos/denote/issues/418.
Also thanks to skissue for noting another edge case that prevented
denote-rename-buffer-mode
from doing the right thing. This was
reported in issue 393: https://github.com/protesilaos/denote/issues/393.
CUSTOM_ID
via org-capture
if not necessaryIf the org-capture
template does not include one of the specifiers
which produce a link, then we take care to not include a CUSTOM_ID
in the properties of the current heading. We do this to make it
possible to link directly to a heading inside of a file (a feature
that is documented in the manual).
Before, we were creating the CUSTOM_ID
unconditionally, which was
not the desired behaviour. Thanks to Jonas Großekathöfer for bringing
this matter to my attention in issue 404:
https://github.com/protesilaos/denote/issues/404.
All the Denote minibuffer prompts have the appropriate completion
metadata to integrate with core Emacs functionalities and with
third-party packages that leverage them. One such case pertains to the
completion category our prompts report. This is used by a package such
as embark
to infer the set of relevant actions to perform or by the
marginalia
package to produce the appropriate annotations.
Users will now notice a difference while using commands such as
denote-silo-extras-create-note
if they have marginalia-mode
enabled: all completion candidates will have file-related annotations.
This is a small change which goes to show how the little things contribute to a more refined experience.
The user option is now called denote-backlinks-display-buffer-action
.
The old name denote-link-backlinks-display-buffer-action
is an alias
for it and will thus work the same way. Though you are encouraged to
rename it in your configuration as I will eventually remove those
obsolete symbols from the Denote code base.
revert-buffer
should do the right thing in backlinks buffersI made several tweaks to the underlying code to ensure that reverting
a backlinks buffer will always reuse the original parameters that
generated it. Backlinks buffers are produced by the denote-backlinks
command, among others.
The manual of Denote is a rich resource of knowledge for how to use this package and how to extend it with custom code. I have written the following entries to further help you improve your productivity:
denote-region
that references the sourceThe following functions are now public, meaning that they are safe to be used in the code of other packages or incorporated in user configurations:
denote-identifier-p
.
denote-get-identifier-at-point
. I am implementing this in response
to a question by Alan Schmitt in issue 400: https://github.com/protesilaos/denote/issues/400.
denote-org-extras-outline-prompt
.
denote-silo-extras-directory-prompt
.
Consult their respective doc strings for the technicalities.
Note that the Elisp convention is that private functions (intended for
use only inside the package) have a double dash (--
) in their name.
In principle, these are undocumented and can change at any moment
without any notice. I do try to avoid such cases and even add warnings
when I make changes to them. Still, you should not use private
functions without understanding the risks involved.
I have many ideas for how to further refine Denote. Maybe you do too. Though we must all wait a couple of weeks in case someone reports a bug. This way, it is easy to fix it and publish a new minor version. Otherwise, we may have to bundle the fix with some in-development feature that we have not fully tested yet.
This is just an overview of the Git commits, though remember that there is more that goes into a project, such as the reporting of inconsistencies, discussion of new ideas, etc.. Thanks to everybody involved!
~/Git/Projects/denote $ git shortlog 3.0.0..3.1.0 --summary --numbered
104 Protesilaos Stavrou
7 Jean-Philippe Gagné Guay
3 Ashton Wiersdorf
1 Ad
1 Jakub Szczerbowski
1 bryanrinders
-1:-- Emacs: Denote version 3.1.0 (Post)--L0--C0--September 04, 2024 12:00 AM
Use Org mode long enough and invariably you'll get around to using Agenda views to manage your defined tasks. Agenda views have become core to my Emacs experience and I'm certain that I'm not alone in saying this. As with other packages, there's a steep learning curve to using Agenda views, largely because Org adopts the Emacs convention of using keybindings and the mini-buffer prompt as its primary user interface with an added twist of frequently making this behavior conditional on where the point is.
To help ease using Agenda views, I'm happy to announce Casual Agenda, a Transient user interface for Org Agenda available on MELPA today.
Casual Agenda organizes the Agenda view commands into the following sections:
Note that all the menus in Casual Agenda are contextual so as one navigates the Agenda view, the menu items will be enabled as appropriate.
Use the Operations menu to alter attributes about it such as TODO state, scheduling, tags, and priority. To use it, move the point to the line of a heading you wish to change and from the main menu select “(o) Operations”. The following menu will be displayed.
User the Mark menu to mark different headlines and perform a bulk action on them. From the main menu, select “(m) Mark” to display the following menu:
Agenda views have different display modes and behavior that can be modified from the Settings menu. From the main menu, select “(,) Settings” to display the following menu:
Get sunrise/sunset times, lunar cycle dates, and holidays with respect to a date via the Almanac menu. From the main menu, select “(l) Almanac” to display the following menu.
By enabling “(u) Use Unicode Symbols” from the Settings menu, Casual Agenda will use Unicode symbols as appropriate in its menus.
Casual Agenda requires that you have a relatively recent version of Org (≥ 9.7.1) and Transient, both built-in packages to Emacs 29.1+. To update those packages you will need to take into consideration Emacs' default policy of not upgrading built-in packages unless configuring it to explicitly do so. My last blog post provides more detail on this.
As with the other Casual Suite packages, Casual Agenda is intended to lower the cognitive load of using Agenda views. Even as I’ve already committed to memory many of these commands, it’s often that I mess up by issuing the wrong binding at the wrong place or just plain failing to recall a command. Since building and using Casual Agenda, this has happened less so. You might perhaps share the same experience.
-1:-- Announcing Casual Agenda (Post Charles Choi)--L0--C0--September 03, 2024 06:00 PM
The ever industrious Protesilaos Stavrou (Prot) just uploaded another nice package to MELPA. It’s a simple little app that displays a font in an Emacs buffer but for those who are on an eternal quest for the perfect font it’s perfect.
The app displays a (configurable) bit of text—think “The quick brown fox…”—and an (again configurable) set of characters underneath. Currently, the app works only with locally installed fonts but Prot is planning to upgrade it to be able to display and install any font.
Prot describes it as a work in progress but it’s already useful and will probably become more so as Prot refines it. It’s not a big thing but it’s another nice example of how Emacs is—or can be made to be—a complete editing environment.
-1:-- Show Font (Post jcs)--L0--C0--September 03, 2024 04:32 PM
This package provides a simple approach to setting up a “focus mode”.
It uses the page-delimiter
(typically ^L
) or the outline together
with some commands to move between pages whether narrowing is in effect
or not. It also provides some optional aesthetic tweaks which come into
effect when the buffer-local logos-focus-mode
is enabled. The manual
shows how to extend the code to achieve the desired result.
(all my videos since early 2022 where I show parts of code use logos
).
logos
^L
Only Generates Ostensible Slides; Logos Optionally Goes through Outline Sections.Below are the release notes.
This version introduces minor refinements to an already stable package.
logos-update-fringe-in-buffers
works with enable-theme-functions
It is possible to hide the fringes when logos-focus-mode
is enabled
by setting the user option logos-hide-fringe
to a non-nil value. To
make sure that the proper colours are applied when the theme changes,
users must also set up the logos-update-fringe-in-buffers
to run
after the theme is loaded.
In versions of Emacs before 29 there was no standard way to do this
(my themes (Modus, Ef, Standard) have always had the relevant “post
load” hook). With Emacs 29, users can now use the enable-theme-functions
to make this work with all themes:
(add-hook 'enable-theme-functions #'logos-update-fringe-in-buffers)
logos-hide-header-line
user option for logos-focus-mode
Users can now optionally hide the header-line when logos-focus-mode
is enabled in the current buffer. This is done by setting logos-hide-header-line
to a non-nil value and then enabling the mode.
[ Remember to read the manual for all such options. ]
org-indent-mode
The logos-focus-mode
operates in the current buffer to make the
changes that are needed for a more “focused” editing experience. Here
we extend it to work with Org’s virtual indentation.
It disables org-indent-mode
when logos-focus-mode
is enabled and
restores it when logos-focus-mode
is disabled. The
logos-set-mode-arg
function takes care of the technicalities.
(defun my-logos-org-indent ()
(when logos-focus-mode
(logos-set-mode-arg 'org-indent-mode -1)))
(add-hook 'logos-focus-mode-hook #'my-logos-org-indent)
Continuing from above, the following code block below shows how to
disable the menu-bar-mode
, tool-bar-mode
, tab-bar-mode
, and
tab-line-mode
when logos-focus-mode
is enabled. If the given mode
is already disabled, the corresponding function does nothing.
Otherwise, it toggles the mode off/on when logos-focus-mode
is
enabled/disabled.
(defun my-logos-hide-menu-bar ()
(when logos-focus-mode
(logos-set-mode-arg 'menu-bar-mode -1)))
(add-hook 'logos-focus-mode-hook #'my-logos-hide-menu-bar)
;; Assuming the `tool-bar-mode' is enabled by default...
(defun my-logos-hide-tool-bar ()
(when logos-focus-mode
(logos-set-mode-arg 'tool-bar-mode -1)))
(add-hook 'logos-focus-mode-hook #'my-logos-hide-tool-bar)
;; Assuming the `tab-bar-mode' is enabled by default...
(defun my-logos-hide-tab-bar ()
(when logos-focus-mode
(logos-set-mode-arg 'tab-bar-mode -1)))
(add-hook 'logos-focus-mode-hook #'my-logos-hide-tab-bar)
;; Assuming the `tab-line-mode' is enabled by default...
(defun my-logos-hide-tab-line ()
(when logos-focus-mode
(logos-set-mode-arg 'tab-line-mode -1)))
(add-hook 'logos-focus-mode-hook #'my-logos-hide-tab-line)
cond
This was affecting the logos-narrow-dwim
function in some cases.
Thanks to Edgar Vincent for the contribution, which happened in the
now-defunct mailing list.
-1:-- Emacs: logos version 1.2.0 (Post)--L0--C0--September 03, 2024 12:00 AM
-1:-- Rounding all timestamps in an srt file (Post)--L0--C0--September 02, 2024 07:02 PM
Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Mastodon #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, communick.news, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!
-1:-- 2024-09-02 Emacs news (Post Sacha Chua)--L0--C0--September 02, 2024 06:33 PM
Fontaine allows the user to define detailed font configurations and set
them on demand. For example, one can have a regular-editing
preset
and another for presentation-mode
(these are arbitrary, user-defined
symbols): the former uses small fonts which are optimised for writing,
while the latter applies typefaces that are pleasant to read at
comfortable point sizes.
fontaine
Below are the release notes.
Fontaine is in a stable state and I find it very useful every day. This release includes some small quality-of-life improvements.
fontaine-toggle-preset
commandIt will switch between the last preset and the one you are currently using. If it cannot find an older preset, it will prompt for one using minibuffer completion.
Presets are set with the fontaine-set-preset
command, either
interactively or from Lisp (e.g. in the init.el
file).
Internally, fontaine-toggle-preset
takes care to only switch between
existing presets, so old preset names (such as from the time of some
experiment) will be skipped if they are not part of the current value
of fontaine-presets
.
fontaine-presets
accept and optional width attributeThis is for users who need to set an explicit width value to the underlying face they are targeting. This, of course, depends on the capabilities of the font family that is used. Those that do not support varying widths will have no effect.
The width attribute for all existing entries is composed by the name
of the face plus the -width
suffix, such as :fixed-pitch-width
.
Check the Fontaine manual for a complete example.
Thanks to Adam Porter for making the suggestion to cover the width attribute in issue 6: https://github.com/protesilaos/fontaine/issues/6.
The fontaine-presets
can look very long if all values are set, as we
cover all typography-related faces and all their attributes. But do
not let this intimidate you. Your configuration can be short and still
highly usable. For example:
(setq fontaine-presets
'((coding ; get the fallback values and override the `:default-height'
:default-height 120)
(reading ; change more stuff from the fallback values
:default-height 140
:default-family "Fira Sans"
:fixed-pitch-family "Fira Mono"
:variable-pitch-family "Merriweather")
(presentation
:inherit reading ; copy the attributes of `reading', then override the `:default-height'
:default-height 220)
(t ; everything falls back to this
:default-family "Iosevka Comfy"
:default-height 100
:fixed-pitch-family "Iosevka Comfy Motion"
:variable-pitch-family "Iosevka Comfy Duo")))
With these, you can switch between coding
, reading
, and
presentation
to match your evolving workflow requirements.
These allow you to switch between not only different font families, but also font combinations to match a certain style, with higher or lower heights, and so on.
fontaine-set-preset
prompt only uses relevant default presetsWhen you invoke the command fontaine-set-preset
it tries to find a
previous preset to set it as the default minibuffer value. This means
that if you press RET
without selecting anything, the default will
be used (check with your minibuffer package in case this does not
happen, or contact me if you need help).
Before, the default value was the last selected preset. This could be
out-of-date though if the fontaine-presets
were rewritten in the
meantime. Now we take care to only produce a default value that is
among those specified in the fontaine-presets
.
-1:-- Emacs: fontaine version 2.1.0 (Post)--L0--C0--September 02, 2024 12:00 AM
My small #emacs #orgmode #gtd customization of the day:
org-edna is a plugin that can be used to setup auto triggers (and blockers) when completing a task. org-gtd uses it to auto-forward the next TODO item in a project to NEXT when a task in the project is marked as DONE. The #orgedna trigger it uses is: relatives(forward-no-wrap todo-only 1 no-sort) todo!(NEXT)
.
This works okay for me, but also results in tickler tasks configured as repeated tasks to go to NEXT state instead of TODO state when they are completed. This results in them showing up in the org agenda even before they are due.
To fix this, I had to add this property to the top-level headings of the tickler file:
:PROPERTIES:
:TRIGGER: self todo!(TODO)
:END:
This overrides the global triggers configured by org-gtd for these org subtrees.
Syndicated to:
-1:-- 2024-09-01-002 (Post Srijan Choudhary)--L0--C0--September 01, 2024 09:45 PM
I’ve written about Peter Prevos and his Emacs Writing Studio several times [1, 2, 3, 4 ]. It’s a series of articles on using Emacs for long form writing. Now, happily, Prevos has announced that the project—or at least the first version of it—is finished and available as a book from several e-bookstores. The source files are also available from his GitHub respository.
This is, as I’ve written, a great resource with lots of useful information. But don’t take my word for it. Protesilaos Stavrou also has a few words to say about it. He has, in fact, contributed those words as a forward to the book.
Those of you who have been around for a while know that I’m very interested in stories about people who use Emacs for non-technical purposes such as prose writing. Those who share that interest will find Prevos’ book a handy resource for using Emacs in their own projects.
I’ve read a lot of Prevos’ articles but never read them through as a book. I’m looking forward to reading the complete work.
-1:-- The Emacs Writing Studio Is Finished and Available (Post jcs)--L0--C0--September 01, 2024 03:10 PM
At work I use org-mode to keep notes about useful ways to query our systems, mostly that involves using the built-in SQL support to access DBs and ob-http to send HTTP requests. In both cases I often need to provide credentials for the systems. I'm embarrassed to admit it, but for a long time I've taken the easy path and kept all credentials in clear text. Every time I've used one of those code blocks I've thought I really ought to find a better way of handling these secrets one of these days. Yesterday was that day.
I ended up with two functions that uses auth-source and its ~/.authinfo.gpg
file.
(defun mes/auth-get-pwd (host) "Get the password for a host (authinfo.gpg)" (-> (auth-source-search :host host) car (plist-get :secret) funcall)) (defun mes/auth-get-key (host key) "Get a key's value for a host (authinfo.gpg) Not usable for getting the password (:secret), use 'mes/auth-get-pwd' for that." (-> (auth-source-search :host host) car (plist-get key)))
It turns out that the library can handle more keys than the documentation
suggests so for DB entries I'm using a machine
(:host
) that's a bit shorter
and easier to remember than the full AWS hostname. Then I keep the DB host and
name in dbhost
(:dbhost
) and dbname
(:dbname
) respectively. That makes
an entry look like this:
machine db.svc login user port port password pwd dbname dbname dbhost dbhost
If I use it in a property drawer it looks like this
:PROPERTIES: :header-args:sql: :engine postgresql :header-args:sql+: :dbhost (mes/auth-get-key "db.svc" :dbhost) :header-args:sql+: :dbport (string-to-number (mes/auth-get-key "db.svc" :port)) :header-args:sql+: :dbuser (mes/auth-get-key "db.svc" :user) :header-args:sql+: :dbpassword (mes/auth-get-pwd "db.svc") :header-args:sql+: :database (mes/auth-get-key "db.svc" :dbname) :END:
-1:-- Improving how I handle secrets in my work notes (Post)--L0--C0--September 01, 2024 01:03 PM
There are some people who prefer to run Emacs in terminal mode. I have no problem with that but I do think that GUI Emacs has so much more to offer that it’s usually the best choice. Sometimes there’s no choice.
The need to use terminal mode often comes up when developers have to work on remote systems rather than their local machine. The usual advice is to use Tramp, which often works well and solves the problem but sometimes—especially with remote servers that are not on the local network—tramp can be too slow.
Wai Hon Law is in that situation. His employer does not allow source code on individual machines so he has do all his development on a remote server. Tramp didn’t work for him so he had to find another solution.
That solution involves a good terminal emulator and tmux. The two main problems are getting good colors for syntax highlighting and enabling the clipboard. These mostly depend on choosing the right terminal emulator but Law’s solution may not help too much because he’s using Chrome OS but there are doubtless terminal emulators suitable for your system.
The TL;DR is that you may have to experiment a bit to find the right emulator for your OS but once you do, you can look at Law’s post to get an idea of the other things you need.
I’m lucky that I’ve never been in this situation and could always just use Emacs in GUI mode but if you aren’t so lucky, take a look at Law’s post to see some possible ways forward.
-1:-- Remote Emacs in Terminal Mode (Post jcs)--L0--C0--August 31, 2024 04:15 PM
[ I am not affiliated with this work. I just enjoy what Peter is doing and I am sharing it as a fellow Emacs user. ]
Peter Prevos has just published the book Emacs Writing Studio. It is a high quality resource for those who want to use Emacs to write at length (books, scientific papers, personal notes, …). EWS comes with an accompanying Emacs configuration to help users get started. Peter used this configuration to produce EWS!
Buy the book from one of the many available bookstores listed here: https://books2read.com/u/4NpgQ9. And check the source code on GitHub: https://github.com/pprevos/emacs-writing-studio.
Below is the foreword to EWS that I wrote.
With Emacs Writing Studio you have what you need to get started with writing. The book and the concomitant configuration for Emacs provide a solid foundation for you to organise your ideas, capture information, and elucidate your thoughts.
This book provides an overview of Emacs’ capabilities for writers. It does it in a way that is approachable. You get the essentials and are then guided through the various facets of the workflow.
Consider Emacs Writing Studio a companion on a long journey. It helps you get started with Emacs and will be there for you as a valuable reference when you need to do something a little bit more advanced but forgot how to proceed.
What you get at the outset is a curated experience. This is exactly what you need to get on with the task of writing: it minimises distractions. Though do not think of it as a constraint: you are still using Emacs — a powerful tool that can be reprogrammed or extended to do more with text and related patterns of interaction. The Emacs Writing Studio setup consists of sensible defaults. You will not be locked in to a bespoke system. This is the standard Emacs experience and you are free to modify it to your liking.
You can always find more resources to address whatever issue you may have. Beside the official manual of Emacs, you will discover a rich corpus of knowledge produced by the community. There are blog posts, drawings, and video demonstrations. They will all apply to what you have here.
No configuration can be a replacement for the work you put in. This is true for your time using Emacs but also for writing in general. Do not come with the expectation that Emacs Writing Studio will do miracles for you: it will not make you an Emacs expert overnight and it will not boost your creativity without you doing anything.
This is a tool that has been tested and proven to work well. Like every tool, it must be used properly by someone who has the requisite skills or is willing to acquire them through continuous practice. As a beginner, you will not know much: the book is here to ensure that you find the information you need to keep going.
The expectation you can have is that Emacs Writing Studio will deliver on its promise of giving you a set of tools for authoring your next works. It will do it in a reliable way. The rest is up to you: conduct the research and start creating.
Beside the technicalities, this book will make you think about matters of method. It does it indirectly through the functions it describes. You then have to consider how each of those will fit in to your workflow.
Piecing together a set of tools or procedures is part of the process of discovery that authors must go through. Through trial and error, you figure out what works for you. You may then stick with it and strongly prefer it over alternative approaches. Whether your methods are appropriate for others does not really matter: you know that one size does not fit all.
Emacs is the perfect tool for those who want to be particular with their writing. It is highly configurable and will grow with you as a user to always match your current level. If you do ever get the chance to learn some Emacs Lisp, you will realise that there is so much you can do to tweak every little thing exactly how you want it to be.
The key to learning your way around Emacs is to be patient and methodical. Try one thing at a time, learn how to use it, and then move on to the next one. This is why Emacs Writing Studio is helpful: it lets you experiment at your own pace while giving you something that works well out-of-the-box.
Remember that you are just getting started and you will be here long-term. Good luck!
-1:-- The Emacs Writing Studio is available—I wrote the foreword (Post)--L0--C0--August 31, 2024 12:00 AM
ChatGPT and its LLM brethren have been a potent source of FOMO: the AI revolution is happening, and I feel like I'm forever late to the party. After getting comfortable with OpenAI's web interface and coding my own command line tool, I figured it was time to complete the trilogy by integrating an LLM AI into Emacs.
As with many topics, there were a number of available Emacs packages, and it wasn't immediately obvious which was 'the best.' And then I watched this (to me) blandly named YouTube video: Every LLM in Emacs, with gptel and was hooked.
This 17 minute video blew my mind. If you're remotely interested in emacs and LLMs, stop reading this post and go watch this video. Heck, watch it a couple of times. In it, the gptel package developer goes through the why and how of gptel, and demonstrates some next-level uses of this package.
So gptel is my answer for adding them magic of ChatGPT to Emacs. gptel can be used both interactively and programmatically. I've found the former capability let's me have a running conversation with an 'assistant.' I can get answers to coding, writing or any other question on my mind without having to leave Emacs. Score.
But interactive use is just the beginning. By leveraging gptel-request, it's possible to automate common patterns. For example, I can set the region to include a word and run bs-gptel-define-word. In a few moments, ChatGPT will come back with a definition, examples, synonyms and antonyms. Here's the definition this function reports for FOMO:
In some respects, this is hardly exciting. There are a number of dictionary services are already integrated into Emacs, so why bother hand coding another? Yet, using gptel has two advantages. First, by changing the prompt, I can easily adjust the output. For example, here's the FOMO definition with a prompt that asks for active and passive voice examples:
The other benefit of using gptel for definitions is that the universe of what's considered a definable term is far larger. For example, I can ask for the 'definition' of a CSS property box-sizing: border-box.
Heck, it even handles slang. Here's the definition of slang: what the sigma
This would have been handy when we were traveling with our nieces and nephew, and this phrase came up repeatedly.
Another example of automating a task by leveraging gptel is gptel-proof. This is an early attempt at coding a proofreading tool within Emacs. The package works by taking an arbitrary region of text and asking ChatGPT to fix the spelling and grammar. The result is embedded back in the original document, surrounded by the familiar version control conflict markers. For example, here's what I see when I proofread this paragraph.
By using the conflict markers, I can use M-x vc-resolve-conflicts, to interactively compare and adopt the improved text.
What I like about this approach is that I don't need to blindly accept the LLM's changes. By using ediff, I'm combining both the magic of AI with the magic of emacs, to make, well, more magic. It's magical. A
This all feels like a very awkward start to using such a game-changing capability. But, at least I've started!
Here's some additional inspiration on the topic: Integrate Emacs with ChatGPT or any LLM, Powerful AI Prompts I have Known and Loved - that you can use, and Emacs pinky Saver: a voice driving GPT4 co-worker for emacs. together.ai is a platform for letting me interact with more LLMs than just ChatGPT.
-1:-- gptel: Mindblowing integration between Emacs and ChatGPT (Post Ben Simon (noreply@blogger.com))--L0--C0--August 30, 2024 09:03 PM
Please note that planet.emacslife.com aggregates blogs, and blog authors might mention or link to nonfree things. To add a feed to this page, please e-mail the RSS or ATOM feed URL to sacha@sachachua.com . Thank you!