I’ve been reading through os, io and bufio core packages trying to reverse engineer the chain of procedures used for the various methods of acquiring user input from the terminal. So far I am unable to find the right combination of things needed to create my own tab completion functionality. I’m only interested in stdin (at least I think so), but the existing procedures contain logic to handle any type of file stream, making it difficult to pinpoint only the things I need.
More specifically, I’m trying to find a way to capture the tab character (or tab key press), and do one of 2 things. Either cycle completion options and replace the contents of the buffer on each tab press like MS terminal, or print completion options and re-print the prompt with the buffer still intact like many unix terminals.
Does anyone have an example or ideas that I might be able to learn from?
On Unix systems you need to put stdin in canonical mode, which basically means you don’t wait for enter for read() to complete. If you want to manually place things on screen you also want to disable echoing (it won’t print back what you just typed).
This is done with tcsetattr() and then you can read stdin however you want 1 byte at a time. Note the defer to reset the terminal back to it’s original state. And of course you should check if STDIN_FILENO is actially a tty with isatty(), but I left it out…
For moving the cursor around and repainting the completions you’d need to use ANSI escape codes, unfortunately cursor movements are not part of core:terminal/ansi but there’s plenty examples how to use them.
Thanks for the info. I was hoping for a cross-platform solution that did not involve rewriting basic terminal prompt functionality, though I’m not surprised this is what it would take. The ANSI sequences themselves are relatively trivial, though the nuances of terminal behavior gets weird especially when the cursor is on the last line, which is the sort of thing I wanted to avoid having to deal with.
I’ll work with the above code and see how far I can take it before the effort becomes overkill for what I had planned.