Skip to content

coxley/rtprompt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Realtime Prompt (rtprompt)

GoDoc

A command-line prompt that looks normal, but can show results as users type.

Basic Example

Why?

I wanted a way to have auto-updated results in the terminal as a user typed -- without the experience that curses brings. I'm not a fan of how terminal UIs feel like opening a new window.

Turns out this didn't exist, and wasn't nearly as straight forward as I had hoped. We have to put the terminal into raw mode to get unbuffered input, but because it's a text prompt we need to recreate the keybindings that Linux's terminal discipline uses. Fortunately when we're done prompting, we can put everything back the way it was!

Example (Basic)

Here's the code for the example above. It's a silly thing that counts the words that have been typed. But it demonstrates that we can have output update in real-time without doing a full-screen terminal UI.

Navigation shortcuts are demonstrated too.

package main

import (
  "fmt"

  "github.com/coxley/rtprompt"
)

func callback(inp string, tab bool, enter bool) string {
  return fmt.Sprintf("Words typed: %d", len(strings.Fields(inp)))
}

func main() {
  prompt := rtprompt.New("Input: ", callback)
  prompt.Wait()
  fmt.Println("Glad we're done with that")
}

Example (Closest Match)

Closest Match Example

This one is more involved. It's also why I wrote this lib. I wanted users, when reporting a bug, have a list of open tasks shown that get updated as they type.

We use https://github.com/schollz/closestmatch for ranking, support tab to select items, colors for selected items, and a function to invoke when the user presses enter.

package main

import (
  "fmt"

  "github.com/coxley/rtprompt"
)

func main() {
  issues := map[string]string{
    "[#1011] LSPs too optimized":                               "",
    "[#1112] Dry runs too dry":                                 "",
    "[#1213] All hands on deck":                                "",
    "[#1314] Leak in the Enterprise":                           "",
    "[#1415] Exception thrown during cardio":                   "",
    "[#1516] Panic when frying eggs":                           "",
    "[#1617] Frying eggs when panicking":                       "",
    "[#1618] Nothing to report, just lonely":                   "",
    "[#1619] Bloody onions when expecting uncontaminated ones": "",
  }

  var selected string
  cm := rtprompt.ClosestMatch{
    Data:     issues,
    OnSelect: func(s string) { selected = s },
    MaxShown: 7,
  }
  prompt := rtprompt.New("Summary: ", cm.CB())
  prompt.Wait()
  fmt.Printf("Woohoo! You selected: %s\n", selected)
}

Supported Keybinds

These should cover most use-cases but happy to expand them.

  • ALT+B: Go back a word
  • ALT+F: Go forward a word
  • CTRL+A: Beginning of line
  • CTRL+B: Move left
  • CTRL+D: Delete forward
  • CTRL+E: End of line
  • CTRL+F: Move right
  • CTRL+K: Remove all text after cursor
  • CTRL+U: Remove all text before cursor
  • CTRL+W: Remove the previous word
  • CTRL-C: SIGINT
  • END: End of line
  • Enter: Finish input
  • HOME: Beginning of line
  • Left arrow: Move left
  • Right arrow: Move right