laravel / prompts

Beautiful and user-friendly forms for your command-line PHP applications.

Home Page:https://laravel.com/docs/prompts

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Debounce with search()

noplanman opened this issue · comments

I'm using search() to request data from an external API and it would be really cool to have some kind of debounce to not make a request on every keystroke.

Is there some smart way of doing this?

Hey @noplanman,

This is a bit tricky due to the synchronous nature of this prompt. We could make it async, but that would reduce the environments that it can run in. We could make a hybrid (like the spinner), but that's a lot of extra work and more things that can break.

However, due to the synchronous nature of this prompt, it won't make two requests simultaneously. If you continue typing while a search is running, the keystrokes are buffered and received in one go once the first search is complete when it will then search again for the new current query, without having queued up multiple searches for each keystroke that occurred in between.

You also have the option of not performing the search until the search value meets a required length.

I'm open to other ideas, but at the core of it would be the need to delay a search until a certain amount of time has passed so it could be assumed the typing has "finished". Anything like that in standard PHP would be a blocking operation that would prevent re-rendering.

Thanks @jessarcher, I understand. Yes, I've noticed the input buffering when typing quickly (but typos and requiring to correct it make it even worse 😅)

I was also wondering if there was some way of "misusing" the validation to do the data requesting, after "selecting" my initial search, but couldn't get it to work.

Alternatively, is there a way to clear a previous promt from the terminal screen? That way, I could use a normal text() input, use the response in a suggest() field and just hide the initial text input.

Or maybe I'm overcooking this and just leave it as is. I cache every single request, which works well enough I guess.

I'll close off here, and if anybody feels inspired to explore this again when PHP is natively asynchronous, they can do that. 😉

Alternatively, is there a way to clear a previous promt from the terminal screen? That way, I could use a normal text() input, use the response in a suggest() field and just hide the initial text input.

There's nothing built-in to Prompts to do this, but it should be pretty straightforward to do in your app, especially with the text input, as it is a consistent height. You'd need to familiarise yourself with ANSI escape sequences, specifically the ones for moving the cursor and erasing.

This worked for me:

$search = text('Search');

echo "\e[4A"; // Move the cursor up 4 lines.
echo "\e[J"; // Clear from the cursor to the end of the screen.

$selection = select('Select', ['your', 'results', 'here']);

This does depend on the Prompts theme not changing the number of lines used to render a text prompt, but I can't see that changing any time soon.

Also, directly echoing could be problematic if your command isn't always run in interactive mode so you may need to make it conditional.