chipsenkbeil/choose

Make choose non-blocking

Opened this issue · 3 comments

choose is a great app! However, unlike (for example) fzf, it is blocking. What this means is that if you pipe to choose, it will not open until stdin closes. If, for example, you run ls -R ~ | choose - which for many people is a long operation - no results are shown until ls is complete. It would be great if choose could dynamically update like fzf does.

Thanks for your work on this great program.

@andrewferrier did you have thoughts on how the program would behave when a user interacts and begins filtering while new input is being received? Do you expect it like running fzf where new input not matching the filter is discarded?

Would you be willing to contribute an enhancement to achieve what you're thinking? I'm more than happy to accept contributions. :)

@chipsenkbeil yes, basically that was my thinking; the results are dynamically updated as new input becomes available (which is, I think, how fzf works).

I'm sure that's not trivial to implement ;) I'll take a look at an enhancement if I get time, although my MacOS native dev experience is limited, I have to admit, so others who could contribute this would be great :)

This might be easier than I thought to implement, gated with some flag to indicate async input.

We already have a method to read data from stdin (getInputItems), although I'm not sure if we'd need to cache the current items or if stdin on Mac will retain the existing input. Given we're advancing our pointer to the end of stdin, I'm going to assume that we'd need to combine our current list with new items.

Presently, we only assign the list of choices once upon the app finishing launching: https://github.com/chipsenkbeil/choose/blob/master/SDAppDelegate.m#L204

What we'd want to do for async instead is to either poll or enact some interrupt to know when new content is available on stdin. If we build in some event loop logic that checks stdin on some regular schedule (configure via CLI option?), we could trigger a rerun of the query with the new choices whenever there's a change. Concurrent programming doc

Potentially use the readabilityHandler to data that arrives on stdin's file handle to trigger a query update.

stdinHandle.readabilityHandler = ^( NSFileHandle *handle ) {
     NSData* data = [handle availableData];
    if ([data length] == 0) {
        // End of stream reached, so should expect no more data
        return;
    }

    NSString* newInputStrings = [[[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];

    if ([inputStrings length] == 0)
        return;

    // Assign these to an existing array by appending to end
     [inputStrings componentsSeparatedByString:@"\n"];
}

If re-assigning the choices parameter, probably need to reference self, which involves using a weak reference: https://bytes.vokal.io/objc-block-capture-weakself/