Open justbur opened 8 years ago
It's a nice idea. I've had the same in mind, e.g. ivy-widen
going from counsel-M-x
to counsel-describe-function
to a union of describe-function
and describe-var
. And in the other direction with ivy-narrow
.
It only remains to implement it in a sane and extensible way. If only to find the time:). I've already spent today's allotment on a couple of bug fixes and the new swiper-all
(which is totally awesome now, btw).
Help functions are a good example, all the way up to apropos
You could have a tree, where walking down the tree is more specific and walking up is more general. Then ivy-widen
would preserve input and execute the prior command in the list. Then people could define their own trees like
(setq counsel-command-tree
'(nil
(apropos
(describe-function counsel-M-x)
describe-variable)
(counsel-find-file ivy-switch-buffer)))
@abo-abo Just have tried swiper-all --- and it doens't work at the moment.
Error in post-command-hook (ivy--exhibit): (wrong-type-argument characterp ("s" . t))
@habamax Please open a new issue, with more details.
well, if there was exposed in documentation swiper-all function, I would definetely opened new issue.
But I have just found out from this thread that threre is awesome function implemented, tried it, it didn't work -- I let you know.
If you want to fix it -- okay, if not -- okay too.
There are no more details, the error is the same as in ivy-switch-buffer. But the workaround for buffers doesn't work for swiper-all.
Just passing by to say this would be an awesome add to Ivy.
I implemented some sort of swapping similar to the example that @justbur mentioned by doing:
(define-key counsel-find-file-map (kbd "C-b")
(lambda ()
(interactive)
(ivy-quit-and-run (ivy-switch-buffer)))))
(define-key ivy-switch-buffer-map (kbd "C-f")
(lambda ()
(interactive)
(ivy-quit-and-run (counsel-find-file))))
I like switching to locate. I've just been using this for a while (requires lexical binding):
(defun my-ivy-switch-to-locate ()
"Switch to using locate, preserving current input."
(interactive)
(let ((input (ivy--input)))
(ivy-quit-and-run (counsel-locate input))))
@noctuid Can you make a PR adding ivy-set-actions
using your function?
Isn't the idea of hot-swapping commands the same as Ivy actions? The only difference is that actions act on the current candidate, whereas command hot-swapping would act on the current input.
Unless I'm mistaken, this would allow piggy-backing the action machinery. Perhaps a prefix argument before M-o could be interpreted as a hot-swap dispatch instead of action dispatch. This would also preserve valuable key binding real-estate.
This implementation idea is slightly less elegant than the widen/narrow idiom (mostly because of more keybindings, though), and the current action machinery might need a mighty face-lift before piggy-backing becomes as easy as I'm suggesting, but the 3D action machinery already exists and has the potential to be much more flexible and customisable than 2D widen/narrow.
Edit: When I say 2D/3D I actually mean linear/exponential, the idea being that widen/narrow can only traverse commands along a single axis, whereas actions can connect any one command with any other command, potentially forming a complete graph in the graph theory sense.
@noctuid
requires lexical binding
Just to be clear, your function does not in and of itself require lexical-binding
. It is probably the ivy
/counsel
functions you are calling which depend on lexical-binding
.
Just to be clear, your function does not in and of itself require lexical-binding. It is probably the ivy/counsel functions you are calling which depend on lexical-binding.
I don't quite understand your meaning, but that function itself does require lexical binding. I only mentioned this because the function will not work if normally evaluated (e.g. in the scratch buffer). The issue is not that ivy-quit-and-run
is used; the issue is that there is a let
around it. The body for ivy-quit-and-run
ends up in a lambda, so lexical binding is required for input
to be bound correctly.
Warning: The following is 100% off-topic and may contain traces of pedantry.
@noctuid
I don't quite understand your meaning [...]
What I am saying is that none of the Elisp language features (defun
, let
, etc.) used in my-ivy-switch-to-locate
depend on lexical-binding
. Whether the local variable input
is bound dynamically or lexically would normally make no difference.
[...] but that function itself does require lexical binding. I only mentioned this because the function will not work if normally evaluated [...]
The reason the type of scoping of input
does make a difference here is the fact that the macro ivy-quit-and-run
depends on lexical-binding
. The macro could well have been written to support both types of scoping (that run-at-time
doesn't look dubious at all!), and then your function could be correctly evaluated even in Emacs 23 (which lacks lexical scoping) without changing a single word in it. This is what I mean when I say your function does not, in and of itself, depend on lexical features; rather it is calling macros/functions which are written in lexical Elisp (which is a different programming language altogether, despite appearances).
[...] (e.g. in the scratch buffer).
As a side note, you can enable lexical-binding
in the *scratch*
buffer like any other buffer. I always do this in my configuration, and there was recently some discussion on emacs-devel
about enabling this by default in a future release.
The issue is not that
ivy-quit-and-run
is used; the issue is that there is alet
around it.
The issue is not that there is a let
around it, or that ivy-quit-and-run
is used, but rather that ivy-quit-and-run
depends on lexical scoping by placing the given body in a lambda
. This is a leaky implementation detail which could be avoided by ivy
if there was reason to.
The body for
ivy-quit-and-run
ends up in a lambda so lexical binding is required forinput
to be bound correctly.
Indeed, but that is a requirement/limitation of ivy
, not your function, as I describe above.
P.S. Sorry for bringing this up; there really is little anyone could gain, even in the case of consensus on the definition of separation of concerns which I present above.
Isn't the idea of hot-swapping commands the same as Ivy actions? The only difference is that actions act on the current candidate, whereas command hot-swapping would act on the current input.
This is worthwhile to investigate as well. But I think the value of the narrow/widen pattern is the options are tightly coupled to the command at hand, grouping related information together.
The issue is not that there is a let around it, or that ivy-quit-and-run is used, but rather that ivy-quit-and-run depends on lexical scoping by placing the given body in a lambda.
Indeed, but that is a requirement/limitation of ivy, not your function, as I describe above.
The issue is exactly that there is a let
around the lambda
. Lexical scoping is required for this to be a closure. It is as simple as that.
Lexical scoping would not be necessary if there were no bindings around the lambda. ivy-quit-and-run
can work fine in cases without lexical scoping. This is not an issue of ivy-quit-and-run
inherently requiring lexical scoping. The only reason my function doesn't work without lexical scoping is because it uses let
to make bindings around a lambda
.
@noctuid
The issue is exactly that there is a
let
around thelambda
. Lexical scoping is required for this to be a closure. It is as simple as that. Lexical scoping would not be necessary if there were no bindings around the lambda.ivy-quit-and-run
can work fine in cases without lexical scoping. This is not an issue ofivy-quit-and-run
inherently requiring lexical scoping. The only reason my function doesn't work without lexical scoping is because it useslet
to make bindings around alambda
.
Yes, this is what I said in my last reply. My (pointless) point is that, the fact that ivy-quit-and-run
puts its arguments into a lambda
, thus requiring lexical scope, is an implementation detail of ivy-quit-and-run
. For example, a patch for ivy.el
could theoretically land tomorrow which removed the lambda
(this is actually something I want to look into, because that run-at-time
looks like a bit of a kludge). In this case, you wouldn't have had to change a single word and yet my-ivy-switch-to-locate
would suddenly work irrespective of the scoping used to evaluate it.
I understand if you don't agree with this way of looking at things from a separation of concerns standpoint; but my (pointless) point still stands from a technical standpoint. Anyway, sorry again for inciting this off-topic discussion.
@abo-abo
Isn't the idea of hot-swapping commands the same as Ivy actions? The only difference is that actions act on the current candidate, whereas command hot-swapping would act on the current input.
This is worthwhile to investigate as well. But I think the value of the narrow/widen pattern is the options are tightly coupled to the command at hand, grouping related information together.
Indeed, this is why I think it's slightly more elegant. But my guess is that the number of such groups of related functionality might turn out to be a bit limited. Perhaps the ideal implementation could combine the best of both worlds.
because that run-at-time looks like a bit of a kludge
While I agree, the Emacs command loop and recursive minibuffer quitting is a mystery/maze to me. I'm just happy ivy-quit-and-run
works at all, and with a small amount to code to boot. Improvements welcome, of course.
See also this related post: https://oremacs.com/2015/07/16/callback-quit/.
Here is a reddit discussion about a related feature request: the poster suggests interactive scope change via a simple query language like any search engine provides:
Problem: There are too many helm- or counsel/ivy- functions.
Firstly, I don't want to manage, create, and remember many bindings. Secondly, its an effort on a brain(I need to do X, oh I need to call func counsel-X, what's the binding? Ah heck I'll just execute-extended-command it).
Ideally, I want one function and one simple button that does the following: By default, show me open buffers and files in default-directory. If I type src/ switch to find-file like functionality. If I type b:feature/make-it-work switch to a branch. If I type m: start a Maildir search with counsel-mu4e. Maybe if I type code: it does counsel-ag.
So essentially a simple query-like language to search stuff inside emacs that I get to define.
I do find this idea very interesting and maybe it contributes something to this issue here.
Maybe something like this could be useful, but those examples seem to be worse than the current method for doing things. Running the hypothetical counsel-X
followed b:
or m:
requires just as much memorization as would be required for a keybinding but requires extra keypresses. Typing code:
doesn't seem much better than just using counsel-M-x
(and maybe aliases, but counsel-ag
is a lot more descriptive than just code
and easily matched). I don't really feel like a middleground between execute-extended-command
/counsel-M-x
and keybindings is needed. Maybe a counsel-counsel
for only ivy/counsel commands.
@noctuid I can follow your arguments. In the end, it's a trade-off between "using a separate keybinding for each command" which takes a few to many keybindings I have to memorize and "using one keybinding plus a mnemonic query language".
In my opinion, there are good arguments for both. The one should not replace the other. With this query language, commands could be solved via tab-completion and mnemonic enhanced commands are easier to remember IMO.
In my world, I tend to use keybindings for things I use on a daily basis and stick to M-x foo
for the other things.
And "search" is quite often enhanced via those query keywords separated by colons. This is a common pattern which would be a dramatic improvement for people who are not using all those counsel-foo
commands with separate keybindings.
YMMV of course.
I really like this idea, and I've got this.
I think this is quite a good solution to the basics. I wanted the implementation to satisfy all the ideas in the original issue thread, so:
ivy-become-any
, which takes a key sequence like describe-key
does, and switches to the corresponding command (it assumes that the command is appropriate, taking a single string argument).I don't think its ready to make a PR yet. The last thing to implement is narrow/widen commands. I've held off from this yet though because I'm not sure I personally would use it, so I don't know how others would want it to work.
Mostly I'm wondering about whether widening/narrowing should be linear. A linear pathway seems to be @abo-abo 's original sentiment and would certainly be easier to implement. But I'm not sure how many commands really fit into linear hierarchies.
The other thing is less often used commands. If we stick to only commonly used commands (with keybindings) and logically wider/narrower commands, then structurally similar commands that people might want to switch to are left out of the feature. For example, I might be using counsel-describe-variable
to look for something that is actually a face. Realising, I decide to switch to counsel-describe-face
. This doesn't have a keybinding because it's so rarely used, but it does have something in common with counsel-describe-variable
(they're both describe-* commands), so I feel it should be possible to switch to it. On the other hand, the more common switches should still be as quick and easy as possible.
One solution to this is to implement switching to any command the user chooses from a list, like in counsel-M-x
. But by the time you've run the swith command, searched and selected, I think you've probably switched context enough that it isn't worth it.
A better solution this might be a default/alternate pattern, like ivy actions. I'm not sure how the data could be stored or accessed, but for every command there could be:
There could then be three keybindings in the ivy minibuffer, for:
This would work, but there would be a lot going on, so maybe just what I've got for now might be a start?
This is possibly crazy/stupid, but here are two situations that I'm thinking of
ivy-switch-buffer
-> search for file buffer -> "damn the file's not open" ->C-g
->ivy-find-file
-> Doneswiper
-> search for symbol in project -> "damn wrong file" ->C-g
->counsel-ag
(or whatever) -> DoneI think it would be cool if you could somehow broaden the context (or narrow it) without leaving ivy. Helm sort of has this, because it has multiple sources and you can jump between sources, but I was thinking that instead of implementing that, which I think has drawbacks, you could implement a simple way of swapping commands while preserving some state (like the minibuffer input). So maybe there's a meta command for files that has keys like,
C-1
for buffersC-2
for local filesC-3
for remote files. I don't know.Another thought, but probably more complicated would be if you could dynamically add candidates from more places. So search for buffer, buffer is not there, dump file names in there too dynamically.