armindarvish / consult-web

Powerful Web and Omni Search inside Emacs
https://github.com/armindarvish/consult-web
84 stars 6 forks source link

Using the prompt as the fallback input when there's no match for dynamic sources #31

Closed agzam closed 2 months ago

agzam commented 2 months ago

Let me try describing it using consult-web-google (async branch) command as a concrete example.

When you run the command, it prompts you for an input. I thought it would be nice to have it run "dwim style", where it tries to pick up the thing-at-point or the region, and I did just that with an advise. But I digress, this isn't the thing I want to talk about

So then, user types something; consult-web fetches a few results. But, what if, none of them are satisfying?Wouldn't it be nice to select none of them and press RET. Naturally, I'm inclined to think that the best action for that would be to simply delegate the prompt string to the browser (trimming it to take everything before " -- ") and open the Google Search Page with the prompt.

Currently, this fails with NPE. I could probably solve this with another advising function in my config (I'm looking into that atm), I just thought that something like this should be a default behavior for all the sources. I mean, of course, that default action would change for each different source.

armindarvish commented 2 months ago

@agzam For using the "thing-at-point" or the region, ... you can just use future history, by default bound to M-n for any of the consult-web command.

The other thing you are mentioning, it is in consult-web-google-autsuggest or consult-web-brave-autosuggest. If you don't set consult-web-default-autosuggest-command to nil, then you will get a simple read-string command.

(setq consult-web-default-autosuggest-command nil)

If you want the autosuggest, then you have to wait 0.5s for the candidates to populate and the first item should be what you typed in the minibuffer anyway.

All that said, I am in the process of moving to a new repo consult-omni because the async branch in this repo is a fundamental redesign, and at this point with all the new things added, I think a new package would make more sense. This behavior will be improved there as well.

I'll close this for now since I won't be addressing it here.

agzam commented 2 months ago

I think either I'm confused, or I haven't explained it properly, or I confused you with my thing-at-point digression.

Check this line:

https://github.com/armindarvish/consult-web/blob/async/consult-web.el#L1830

If I type something in the prompt, e.g. "foo", and then decide to not to select any of the results (move my cursor back to the prompt, since in Vertico it automatically selects the first item), and then I press "RET", it currently fails at the exact point above. What I think should happen (that would work for me anyways) is that it navigates to google.com?query=foo in the browser.

agzam commented 2 months ago

I think a new package would make more sense.

Hmm. So, you're planning a complete redesign in a different package that eventually will replace consult-web?

armindarvish commented 2 months ago

I think a new package would make more sense.

Hmm. So, you're planning a complete redesign in a different package that eventually will replace consult-web?

Yes. It is the async branch of this repo plus some new improvements.

armindarvish commented 2 months ago

I think either I'm confused, or I haven't explained it properly, or I confused you with my thing-at-point digression.

Check this line:

https://github.com/armindarvish/consult-web/blob/async/consult-web.el#L1830

If I type something in the prompt, e.g. "foo", and then decide to not to select any of the results (move my cursor back to the prompt, since in Vertico it automatically selects the first item), and then I press "RET", it currently fails at the exact point above. What I think should happen (that would work for me anyways) is that it navigates to google.com?query=foo in the browser.

I guess I misunderstood your point. If you are in async branch and you run consult-web-google, then you are getting dynamic results (and not autosuggest) from google search engine and if there are no candidates, that means google is not returning any results for your search. So if there are no results, there are no results, what do you exactly expect to happen when you hit RET and why?

agzam commented 2 months ago

You still don't get it. There are results. It's just in some cases I don't like any of them and I have to throw away the entire search, because selecting and pressing RET would take me to the page of the selected search result. What I'm saying is that if you press early (before any results come through) or if you choose none of the results in the list, and press RET - the function fails exactly at the place where I pointed out before.

I think you're confused because before async branch, there were distinct commands, now there's only dynamic search. But perhaps, it still could be used as static, the function I pointed out simply needs to be fixed. I guess this is now an impractical argumentation, since you're going to pivot to making a separate package.

I was able to figure out some temporary hacky workaround for myself:

(defadvice! consult-web--multi-dynamic-no-selection-a (ret-val)
    "Temporary hack until Issue armindarvish/consult-web#31 gets sorted out."
    :filter-return #'consult-web--multi-dynamic
    (let ((s (car ret-val)))
      (if (null (get-text-property 0 :url s))
          (progn
            (add-text-properties
             0 (length s)
             `(:url ,(format
                      "https://google.com?query=%s"
                      (replace-regexp-in-string "#" "" s))
               :source "Google"
               :title s)
             s)
            (setf (car ret-val) s))
        ret-val)))

What it basically does is it checks the return value of consult-web--multi-dynamic. If it doesn't have a :url property (and that's what happens if you run consult-web-google, type something and then press "C-p" and then "RET"), it simply adds a Google URL. The default callback then allows me to skip all the suggestions and go straight to the Google search page.

This is a pretty dumb hack, because for every kind of source it always opens google search page. Not very ideal, but let's me use the search, combining the old, a bit sucky way - when you needed to type something, press RET and then see it on the search page in the browser and the new awesome way - found URLs are displayed in Emacs.

armindarvish commented 2 months ago

I understand what you are saying, but I don't get the end result you want. If you don't like any of the suggestions, you can change the search term or cancel the command (e.g. C-g). Why would you hit RET? and what do you expect to happen? open Google homepage?

What it basically does is it checks the return value of consult-web--multi-dynamic. If it doesn't have a :url property (and that's what happens if you run consult-web-google, type something and then press "C-p" and then "RET"), it simply adds a Google URL. The default callback then allows me to skip all the suggestions and go straight to the Google search page.

I have a hard time understanding the logic for what you are asking for. It sounds like you want to be able to go back to the minibuffer prompt and hit enter. In other words, in consult world, that is equivalent to :require-match nil meaning you can select the minibuffer prompt and none of the candidates. However, I am not sure what would be the default action in this case?

I guess this is now an impractical argumentation, since you're going to pivot to making a separate package.

It is not because I would have a similar behavior in the new package, and if I understand your suggestion, I may change the behavior, but I need to understand what is the action you expect when you select the minibuffer prompt as opposed to one of the candidates?

agzam commented 2 months ago

I need to understand what is the action you expect when you select the minibuffer prompt as opposed to one of the candidates

In the case of google source, yes, for me personally, the most practical action in this particular case would be browse-url to google search page. For other sources, I'm not sure, I guess, it could be similar for Youtube, for Brave, DuckDuckGo and Wikipedia, for internal sources their respective commands, maybe?

I think this could be the very nice UX - user executes a search command, types anything, and if they are impatient, they can press RET and it would open the home page for the respective search engine. If they however willing to wait for a short delay, results will appear in Emacs. If for any reason they are not satisfied with the results, they still can RET without a match and again, it navigates to the search page. For consult-web-multi however, this shit probably makes no sense at all, so maybe no default command? Or maybe a customizable command, I dunno.

armindarvish commented 2 months ago

@agzam Ok, with the new package you will have a way to implement what you want, although I may not directly implement that as default behavior, manly for the following reason:

1- As you said, in a multi-source setting, the action you said won't make a lot of sense.

2- There is already an embark action implemented for opening the search page, instead of the result page consult-web-embark-external-browse-search-link, which also works in a multi-source setting and tries its best to open the search page with other parameters (e.g. count, page, ...). It may not be as convenient as hitting RET on the prompt but the user can easily solve that by binding it to another key if they want.

3- I don't understand the case with so-called "impatient" people. If the user is using a 1-source search like Google and is impatient and wants to go directly to Google, then they should be using browse-url or google-this or any other package that simply does that, why start with consult-web, and then be impatient? In other words, I don't understand what would happen between the time the user decides to launch consult-web (instead of those other packages) and before they see results from consult-web that makes them change their mind and would want to be so-called impatient and go directly to the search homepage! That scenario sounds more like "Oops I launched the wrong command" and the solution should be cancel the command and launch the command you want browse-url or google-this, rather than us trying to guess what such hypothetical indecisive user 😃 wanted to do to begin with!

agzam commented 2 months ago

Oh, right, I totally forgot about embark actions. Great suggestion.

and the solution should be cancel the command and launch the command you want browse-url or google-this

For me personally, that is exactly why I want it - so I don't have to use other packages and consult-web becomes one stop shop for all the searches I need. Basically, dwim for the RET key. I can now bind a single search command to a key and then start typing the search query - if for any reason I still want to see the search landing page, I would just get back to minibuffer prompt without selecting any candidates and press RET. The "impatient" thing I talked about is just a nice side-effect, now consult-web works as google-this.el or search-engine.el, I just can type my query and quickly press RET without waiting for any search results to be fetched. Not that I'd be using this a lot, but it gives me a nice way to adapt to the new way of performing web searches while still respecting the old muscle memory.

armindarvish commented 2 months ago

@agzam Ok, so what you are asking for is a bit different than just opening "Google Homepage". I am planing to make something similar to what you want in the new package. Here is what I have in mind:

The user calls a consult-web command like consult-web-google. Naturally they will immediately start typing (or use M-p, M-n to get history or thing-at-point, respectively). If they don't like the candidates, they can still force a new selected candidate by vertico-exit-input (I believe by default this is bound to M-RET), in this scenario, they should be taken to the search page with the search query (and parameters) from their input. Of course in this case if the minibuffer input is an empty string then they will see the search homepage with no query. In a multi-source search this would not be allowed because in that scenario we will force the :require-match t in the consult--read command and therefore the user cannot select the prompt as the selected candidate. They can still open the search page of any source (or a logical equivalent to that for non web search sources) using embark actions.

Note that I see this is subtly different than the scenario I mentioned before where the user goes "Oh I called consult-web-google, but all I wanted was to open google homepage in the browser". That would simply be a user error and the solution as I said before would be to cancel and call the right command that you intended. In this scenario the user intends to call consult-web-google but after seeing the results (or seeing no results) they actively decide that they would like to force the minibuffer prompt as the selected candidate. The actions that happens on this forced candidate is pre-defined and customizable just like a consult-multi source with the :new keyword for actions on new non-existing candidates.

This way with multi-source searches, where :new candidates won't make sense, we can force :require-match t in consult--read and the user simply cannot force the minibuffer input as selected candidate because that would be an ambiguous as to what should be the action done on this new candidate.

armindarvish commented 2 months ago

alright consult-omni is now public, so I am closing this and will open an issue there for it:

https://github.com/armindarvish/consult-omni/issues/2

agzam commented 2 months ago

Sorry, it took me a while; I just migrated to consult-omni. It works great. Even this discussed feature works beautifully. Although, I don't know why you've made all the sources require a match by default. I'm having to do this to use this feature:

(defadvice! consult-omni--multi-dynamic-no-match-a (orig-fn &rest args)
    "Require no match for omni searches."
    :around #'consult-omni--multi-dynamic
    (apply orig-fn (plist-put args :require-match nil)))

I'm loving the new package. Although I suppose not match has changed, when compared with "async" branch here, it feels nicer. I'm hoping to experiment with adding different sources next. Thank Armin, this is awesome. Are you going to announce it anywhere?

armindarvish commented 2 months ago

@agzam I believe I fixed the :require-match already. Check the latest in develop branch.

In general, I have been adding all sorts of small things here and there and I am working on. Video to explain features and will also talk about adding new sources too. Once the video is ready, I will announce the package somewhere (probably reddit, ...)

agzam commented 2 months ago

Oh good call, I pulled from the main branch, I'll switch now to 'develop'. Yeah, videos would be awesome. I'll try to spread the word on your cue. I love this little beast. More people should know about it.

armindarvish commented 1 month ago

@agzam I just announced consult-omni here: https://www.reddit.com/r/emacs/comments/1e6qhpf/announcing_consultomni_a_powerful_omnisearch_and/

and also uploaded a video (a long 3-hour one) with details on sources including making new ones. You can watch it here:

https://www.youtube.com/watch?v=wNH2E7iT__c

agzam commented 1 month ago

Holy mother of Turing! Bro, three and a half hours? :open_mouth: I'm gonna need :popcorn: You are a mad lad. This is awesome :smile: