tj / go-tea

Tea provides an Elm inspired functional framework for interactive command-line programs.
MIT License
376 stars 11 forks source link

Support copy/pasting #7

Open tj opened 4 years ago

tj commented 4 years ago

Not sure how this is typically done

danneu commented 4 years ago

I don't know either. I'm new to Go but here's some obvious sleuth-work that's certainly no mystery to you.

One place that obviously varies on single keypress vs. pasting is how many bytes you are going to read from term.Read():

https://github.com/tj/go-terminput/blob/691367d1d60da90c822e81c172dd22ddb4280065/terminput.go#L18

Currently, terminput.Read() grabs the first rune c off the paste and returns it, ignoring the rest, so go-tea can never perceive the rest of the characters without changes to go-terminput:

https://github.com/tj/go-tea/blob/791bd3b3188665129215c1daae273ea5e65dced0/tea.go#L134

It's also worth mentioning that, of course, entering character "k" is going to look the same as pasting a single character "k" to n, err := term.Read(). And that if runelen(buf[:n]) > 1, maybe it's not too naive to assume that it's going to be a sequence of KeyRunes rather than control characters like KeySOH (ctrl-a). Like, can you actually copy control characters like KeySOH to be pasted into a cli app? If the answer is no, then I think the solution following solution might be nice.

So one naive idea is for msg, err := terminput.Read() to return a sum type of ((KeyboardInput | []KeyRune), error) which seems ergonomic to work with from go-tea at the expense of possibly being too naive. Or since sum types don't really work in Go, maybe KeyboardInput just takes on a new field { ..., Runes []KeyRune } (well, []rune or string would prob be more accurate there) that will be have a length on pastes if runelen(buf[:n])>1.

Another less ergonomic idea is to always return a sequence ([]KeyboardInput, error) since n, err := term.Read(); runelen(buf[:n]) may be greater than 1. But this becomes inaccurate if, in practice, only the first element could ever be a non-KeyRune. Or in that case maybe it's not so bad since the user can pop the first key off to check it for ctrl chars and then assume the rest are just printable RuneKey runes. But that may have the user writing logic to handle states that can never actually exist.

Anyways, great lib. I've built a CLI app with go-tea that I can leave open and use to quickly translate/lookup words between languages for personal use and to learn Go. Being able to paste words/sentences into it would be a next layer of polish one day.

Some coming weekend, I'll vendor go-terminput and go-tea into my project and play with it myself to see if any of these assumptions are reliable in practice.

tj commented 4 years ago

Awesome! Yeah definitely let me know if your technique works out, sounds fine to me! KeyboardInput's name is pretty generic so we could probably even just stuff the entire string in there, but it might be nice to return an interface and a second type like you mention, just to switch on.