Last edit
Summary: remove obsolete info about Polish words (they've been translated to English a long time ago anyway).
Deleted:
< (Note to English-speaking readers: the links entitled //Komentarze na tej stronie// lead to comment pages.)
Deleted:
< (//Więcej// means //More// in Polish; click it to see older entries.)
A bit over a decade ago (!) I wrote about Iedit. It’s a very cool package, a bit similar to multiple cursors, very convenient for changing variable names (especially that it has a great feature where the change is restricted to the current function).
I am also a Lispy user. Lispy requires Iedit (and has a binding for it different from the default one – M-i – while Iedit’s default I’m used to is C-;). The problem is, when I added Lispy to my Emacs, it disabled the default C-; (and only installed M-i in Elisp buffers).
Now, I admit that M-i may be a better (or at least not worse) keybinding for Iedit than C-;. It’s default binding is tab-to-tab-stop, which is one of those useless commands Emacs has had probably for decades. Personally, I’m accustomed to C-;, so I wanted Lispy not to interfere with Iedit setting that keybinding.
It turns out that all I had to do was to make sure that Iedit is loaded before Lispy. I think the reason is that Lispy says
(setq iedit-toggle-key-default nil)
and Iedit says
(defcustom iedit-toggle-key-default (kbd "C-;") ; ... )
and defcustom only sets the value when not already set. So, if you want both Iedit in non-ELisp buffers and Lispy, just use your favorite package manager to make sure that Lispy is loaded after Iedit and you’re done! And if you want M-i to be the Iedit entry point instead of C-; in all buffers, just make sure that
(keymap-global-unset "M-i") (setq iedit-toggle-key-default (kbd "M-i"))
is evaluated before loading Iedit. (The unsetting is needed because Iedit won’t let you use a keybinding which is already taken by another command.)
That’s it for today, and if you don’t use Iedit (or Lispy), definitely check those packages out – they are both really great!
When I write blog posts containing several links (usually to Emacs documentation, sometimes to my other posts and sometimes to other websites), one of the things I do is to check if all the links are correct. Usually I just middle-click on every one of them in the browser and see if they lead to the right place. I thought, however, that it would be useful to be able to see where an Org link points to without actually going there.
The most natural thing that occurred to me was to show the link target in the echo area when the point is on the link. I asked how to do it and learned that I’m far from the only one wanting such a feature. It turned out that this is almost supported out of the box.
First of all, Org mode puts the link target in the help-echo text property. This means that hovering the mouse over a link shows a tooltip with the link target. Also, I learned that C-h . (display-local-help) shows that property in the echo area when the point is on the link.
I started to search for methods of doing this without coding it myself, and I was not disappointed. It turns out that Emacs can display “local help” automatically when it is available at point.
One way to do this is to enable the option help-at-pt-display-when-idle. It works very much like Eldoc and in fact it can conflict with it. If you use Eldoc (and as far as I know, (global) Eldoc mode is turned on by default in every buffer that supports it), there is another setting you can use – eldoc-help-at-pt. It’s less configurable than help-at-pt-display-when-idle (see its docstring to know how to fine-tune its behavior), but I don’t need the fine-tuning, so I enabled it in my config. (As is often the case with things I write about here, as of the time of writing this, eldoc-help-at-pt is only available for the brave people who compile Emacs from master.)
One more thing I’d like to be able to do would be to see the target of a link the point is not on. I think I’ve mentioned on my blog that I use Avy. It’s an excellent package from Oleh Krehel, famous for Swiper, Hydra, Lispy and several other Emacs packages. Avy lets the user perform actions at places other than point without moving to them, in a very fast and convenient way. (There is a great article about using and configuring Avy by Karthinks, too – I learned a lot from it!) It turns out, however, that making Avy select Org links is trickier than I thought.
Finding links in Org mode is easy – you just search for the org-link-any-re regex. However, (avy-jump org-link-any-re) doesn’t work because avy-jump only selects visible text, and Org mode only shows the links’ descriptions by default. (This can be changed by calling org-toggle-link-display, but I really don’t like the result, since it makes text with links very hard to read.)
Now what I did was a bit of poking in Avy sources, and for a moment I thought I was able to come up with a solution. I was not particularly happy with it because I don’t fully understand what is going on there
. It seems that Avy uses the avy--visible-p function (the two dashes mean that it’s an internal function, theoretically subject to change anytime) to determine whether a character is visible or not. This function looks like this:
(defun avy--visible-p (s)
(let ((invisible (get-char-property s 'invisible)))
(or (null invisible)
(eq t buffer-invisibility-spec)
(null (assoc invisible buffer-invisibility-spec)))))
so if buffer-invisibility-spec is set to t, it will always treat everything as visible (and frankly, I have no idea why it would do that):
(defun avy-goto-org-link ()
(interactive)
(let ((buffer-invisibility-spec t))
(avy-jump org-link-any-re)))
This, however, has an obvious drawback – now legitimately invisible links (for example, ones under folded headlines) are selected as Avy candidates. A natural solution would be to modify buffer-invisibility-spec so that only the link should become visible:
(defun avy-goto-org-link ()
(interactive)
(let ((buffer-invisibility-spec
(remove '(org-link) buffer-invisibility-spec)))
(avy-jump org-link-any-re)))
This seems to work, but has the same issue as using the org-toggle-link-display function – it makes the whole links (target plus description) visible for the duration of candidate selection.
I decided that the only way I can see is changing buffer-invisibility-spec only during the evaluation of avy--regex-candidates. The standard way of achieving things like that is advice. It is probably not optimal here since I want it to only be active temporarily, and I tried using cl-letf, but failed (and decided that debugging such a convoluted construct is not worth the time). So, advice it is.
(defun avy--regex-candidates-links-visible-advice (orig-fun &rest args)
"Call `avy--regex-candidates' but with Org links visible."
(let ((buffer-invisibility-spec
(if (listp buffer-invisibility-spec)
(remove '(org-link)
buffer-invisibility-spec)
buffer-invisibility-spec)))
(apply orig-fun args)))
(defun avy-goto-org-link ()
(interactive)
(advice-add 'avy--regex-candidates
:around
#'avy--regex-candidates-org-links-visible-advice)
(avy-jump org-link-any-re)
(advice-remove 'avy--regex-candidates
#'avy--regex-candidates-org-links-visible-advice))
And now it works really well! The last missing thing is a good keybinding for this. Since I bound avy-goto-char to M-j, I decided that M-J (that is, meta-shift-j) is a good enough keychord.
(define-key global-map (kbd "M-J") 'avy-goto-org-link)
Let’s now come back to the idea of displaying a links’ target using Avy.
(defun avy-action-display-local-help (pt)
"Call `display-local-help' at PT."
(save-excursion
(goto-char pt)
(display-local-help)))
(add-to-list 'avy-dispatch-alist
'(?. . avy-action-display-local-help)
t)
And now I can press M-J . and then the character Avy associates with a particular link visible on screen to see its target in the echo area, without moving the point.
A bonus I get here is that display-local-help is useful outside Org mode, too. For example, I use ESLint to find issues in my JavaScript code, and it uses the help-echo property to show ESLint messages when the mouse hovers over the problematic place. And now I can use my newly defined Avy action for that, too! Assuming that the first character in that place is an “h”, I can press M-j h . and the suitable character to see the ESLint message without moving the point nor touching my mouse. Neat!
CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode
A few weeks ago I wrote about my toy train timetable clock. I used it with my son a few times since then, and it worked great. However, some things that I imagined would be a good idea turned out to be a bit worse UI-wise.
For example, I noticed that it would be quite useful to be able to pause and resume the time. This is a bit difficult to achieve in my initial design, where instead of keeping track of the “current toy time”, I store the start times (both real and toy) and compute the toy time on every update. I thought that was clever and allowed me to avoid problems with timers being late, but after I read the docs again, I realized that I could just increment the “toy time” on every call to ttt-refresh and the result will be (almost) the same. (Theoretically, if Emacs is really busy, say performs some computations taking a minute, then the previous approach would update the toy time to the current value immediately, and the “new” one would update it four times in 15-second increments in quick succession – but (1) I don’t expect that to ever happen, and (2) even if it sometimes does, it’s not a big problem.)
After spending some time thinking about the new design, I considerably simplified the UI. From now on, the ttt-start command (the main entry point) no longer asks the user for the “real start time” – the user just enters the “start toy time” and the clock starts running. The main innovation (from the user’s perspective) are two buttons below the clock: pause (which is self-explanatory) and restart. The latter works like this: the “start toy time” is stored in the new variable ttt-start-toy-time, and restart just sets the toy time to that value (and refreshes the screen so that the update is visible at once).
As usual, Emacs turns out to be a perfect platform for coding little “apps” like this. Much like the web, you get the whole UI “for free”. In the case of the web, you have HTML, CSS if you want it to look fancier, and JavaScript for handling various “events” (like clicks and key presses). In the case of Emacs, you get the machinery of major and minor modes, the concept of keybindings and things like completion or ASCII art drawings. Both platforms support even pretty sophisticated cases like date/time input. In the case of the web, there is the (infamously bad) <input type="date"> and its relatives <input type="datetime-local"> and <input type="time">. In the case of Emacs, there is the (famously great) org-read-date. Of course, the big upside of the web is that basically everyone who has a computer these days (including phones) has the runtime; the big upside of Emacs is that, well, it’s Emacs, so us Emacsers get the integration with one of the best tools in existence.
That’s it for today, happy hacking!