vjgoh · 2022-05-21 01:10
I'm switching to Transient from Hydra for my build commands. Hydra was great, but being able to toggle switches on and off quickly was something I always wanted to be able to do, and Transient makes it a lot easier--indeed, that seems to be its raison d'etre.
I'm going through both the very dry and obtuse manual, but also the excellent writeups posted here and on github. However, I still have two questions that don't seem to have answers.
1. Is there any way to display information without providing a way to act on it? One of the things about hydra was it was possible to display the state of variables (and arbitrary text) as part of the formatting. I used this to give me information on the context I was operating in, like what the root directory was, or what the peforce root was. I don't actually want to change those values, I just need to know them. What I've done in the interim is define an empty interactive function. I still get the key as a weird little prefix, but my data is displayed.
2. I'm making extensive use of transient-define-suffix that takes an argument and completes from a list. The description is a lambda that reads and propertizes the saved variable (shamelessly stolen and repurposed from /u/psionikus' examples posted here). However, when I set them, the display doesn't update. I found the undocumented function (so many undocumented things!) `(transient--redisplay)` but it feels like I'm doing something wrong if I have to put it at the end of every one of my suffixes.
I appreciate that the documentation is getting better over time, but I still find it frustrating that I can't, say, find a list of all the keyword-value pairs. They're scattered throughout the docs, so if you don't know or don't remember what you're looking for, it's nearly impossible to find.
That said, I'm making progress. The best way to do it seems just to do it, and hack around until you find a solution.
alexluigit · 2022-05-21 10:47
> Is there any way to display information without providing a way to act on it?
Is this what you wanted?
```
(transient-define-prefix my-transient-prefix ()
[:description
(lambda () (format "Current directory is: %s" default-directory))
[("a" "toggle flag-a" "--flag-a")]])
```
> I'm making extensive use of transient-define-suffix ... However, when I set them, the display doesn't update.
After you invoke a transient-suffix, transient is exited, what do you mean by "display doesn't update"?
vjgoh · 2022-05-21 19:38
Ah, that does work, though it's not 100% what I want. That's forcing me to give information as the titles of sections. Moreover, if I create one of those groupings, I HAVE to put a command in it; it's not allowed to just stand alone with information.
That is:
(transient-define-prefix proj-transient-build ()
"A transient to construct build strings and execute them."
["Current Project Override"
("P" proj-set-project-override)
("foo" foo :description (lambda () (format ""%s"" (getvar helm-locate-instance))) :transient t)]
[:description (lambda () (format ""%s"" (getvar helm-locate-instance)))] ;; this doesn't show up
["Header String"] ;; Neither does this
["Build args"
("-p" "Show Progress" "-progress")
("-N" "No Hot Reload" "-NoHotreloadfromide")]
["Targets"
("e" proj-set-executable)
("t" proj-set-target)
("p" proj-set-platform)])
Those groupings that only have a description string of some kind don't show up, presumably because they're empty.
Still, this is another tool for me to use, so thanks for that. :)
For your second question, consider this setup:
(transient-define-suffix proj-set-platform (platform)
"Choose build target"
:transient t
:description '(lambda () (concat "Current Platform: "
(propertize (format "%s" proj-platform-string) 'face 'transient-argument)))
(interactive (list (completing-read "Build Platform: " +proj-platform-list+)))
(setf proj-platform-string platform)
(transient--redisplay))
If I use this without `(transient--redisplay)`, then when the proj-platform-string is set, the old value is still there after setting it.
I'm not inherently against using that function, but is there a way it can be called automatically after I set ANY variable?
Oh, it's also worth noting that if I try to do
:class 'transient-lisp-variable
:variable 'proj-platform-string
:choices +proj-platform-list+
Transient won't read options from the choices list (it only wants to set the variable through a freeform string), which is why I'm building the suffix so verbosely.
(Edit: excuse the formatting. I hate the Reddit editor for code now.)
alexluigit · 2022-05-22 06:15
For the documentation issue, I guess this is a design choice of the builtin transient classes, it tries to display the value of the item, which is dynamic, only inside the parentheses at the tail of the action. I usually put these "not-belong-to-any-group" descriptions below the main heading, separate with different lines.
In terms of the second issue, I believe what you need to do is to specify a reader for `transient-lisp-variable`.
```
(defvar proj-platform-string "a")
(defvar +proj-platform-list+ '("a" "b" "c"))
(defun proj-platform-reader (_prompt _initial-input _history)
"Helper function to read the value of `proj-platform-string'."
(completing-read "Platform: " +proj-platform-list+))
(transient-define-infix proj-set-platform ()
"Set project platform."
:description "Current Platform:"
:class 'transient-lisp-variable
:shortarg "p"
:variable 'proj-platform-string
:reader 'proj-platform-reader)
(transient-define-prefix demo ()
"Demo."
["Flags" ("p" proj-set-platform)])
```
vjgoh · 2022-05-23 14:47
Ah, that `:reader` thing is very helpful, AND it seems to solve the problem of the transient display not refreshing with the current value.
I searched both the original manual, the GNU manual AND the developer quick start and neither of them mention that at all. I know I'm beating a dead horse at this point, but it seems absurd that that's not in any official documentation ANYWHERE.
Edit: I found custom readers in the developer quickstart; my mistake was searching for `:reader.`