armindarvish / consult-omni

A Powerful Versatile Omni Search inside Emacs
https://github.com/armindarvish/consult-omni/tree/main
165 stars 4 forks source link

Is there a way to set different minimum input length for different sources? #34

Open WeissP opened 3 weeks ago

WeissP commented 3 weeks ago

I know it is controlled by consult-async-min-input for all asynchronous sources. I am wondering whether it is possible to set this variable differently for each source? Or, at least, can synchronous sources display results immediately even there is no input?

armindarvish commented 3 weeks ago

@WeissP No, currently there is not. Right now there is only one single limit in consult-omni-default-count and it is hard-coded in most collection functions to use that value. It is very much possible to make a separate variable for the limit per source but at some point we are going to run into too much fine-grain customization.

For now, you can let bind consult-omni-default-count and wrap your functions with that, or you can pass -- --count N in the minibuffer input to dynamically change the limit. Both of those will change the limit on all the sources in your multi-source search.

I thought between setting a global limit with consult-omni-default-count and being able to dynamically change the limit on individual searches, we should be good enough, but may be there is an argument for defining the limit per source?

WeissP commented 3 weeks ago

Maybe I didn't explain it well, but what I meant is the minimum number of input characters needed to enable a source. You can check the documentation of consult-async-min-input to understand what I meant.

WeissP commented 3 weeks ago

Regarding the motivation, I now use consult-omni-multi as the most frequent way to switch buffers and open files. (It of course also does some other fancy things via asynchronous sources.) However, I don't want to type any characters if I just want to switch to a buffer I recently used. That's why I want all synchronous sources to display results immediately, while asynchronous sources can be enabled based on the minimum input length.

armindarvish commented 3 weeks ago

@WeissP Sorry, I read that wrong. I thought you were talking about counts.

We don't really use the consult-async-min-input in case of synchronous sources. However, this is hard coded, so if you want to change it you have to override some functions in consult-omni. Depending on what synchronous sources you are using, there are different ways to go about what you want to achieve:

  1. If you are interested in built-in synchronous sources from consult (like consult-buffer), you can change the macro that converts the consult source to a consult-omni source. You can either add a line to let-bind consult-async-min-input to 0 before the line (`(,query . ,opts) (consult-omni--split-command input args) here:

https://github.com/armindarvish/consult-omni/blob/5bc8fe0fb7f229ea374459d3ab7a9f98dae64ea0/consult-omni.org?plain=1#L2470
So it would become:

         (pcase-let* ((consult-async-min-input 0)
                      (`(,query . ,opts) (consult-omni--split-command input args))
                      (opts (car-safe opts))
                      ...))

or alternatively you can change the line here https://github.com/armindarvish/consult-omni/blob/5bc8fe0fb7f229ea374459d3ab7a9f98dae64ea0/consult-omni.org?plain=1#L2480
and get rid of that (when (string-match (concat ".*" query ".*") item) condition.

  1. For other synchronous sources like elfeed, projects, apps etc. you need to modify *-fetch-results function. You can either let-bind consult-async-min-input to 0 before calling consult-omni--split-command like I showed above in those functions as well, or get rid of consult-omni--split-command altogether and use the entire input directly. My suggestion would be the former if you still want to be able to use other syntax like adding extra arguments (e.g. -- --count 10)

That said, note that in such scenario you are likely going to get a lot of candidates from synchronous sources, and because they are usually available right away, they end up showing on top of the list. That would mean you have to actively go down the list to see other items from other sources (e.g. by using vertico-next-group. Also, this would mean that you are only getting results from sync sources before you reach consult-async-min-input.

In general, bear in mind that fundamentally, what you are trying to achieve is challenging because you are trying to fit possibly opposing work flows into one and there is a cost to that both in terms of performance and also practical convenience. Currently consult-omni is designed around a 2-step workflow. First, search for input, then narrow down by filtering (e.g. adding # to further filter the results like consult-grep). If you remove the first step from the synchronous sources and not async sources, I won't be surprised if you run into scenarios where overall you lose efficiency rather than gaining efficiency by combining everything (because for example you may have to adjust your minibuffer input to get the result you want from different sources and that can be less efficient depending on your use-case).

WeissP commented 3 weeks ago

If I understood correctly, it is only controlled by the function passed to ":request"? But even a source like this requires at least 3 input characters to be enabled.

(consult-omni-define-source
 "Demo"
 :type 'sync
 :request (lambda () '("___aaa" "___bbb" "___ccc""___ddd")))