Skip to content

Commit

Permalink
prompt: build your own CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
jedib0t committed Aug 26, 2023
1 parent 13d3a1d commit 15d9552
Show file tree
Hide file tree
Showing 23 changed files with 2,836 additions and 11 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
/demo*
/profile/
.coverprofile
*.swp
*.log
*.swp
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,21 @@ bench:
go test -bench=. -benchmem

cyclo:
gocyclo -over 13 ./*/*.go
gocyclo -over 13 ./list/*.go
gocyclo -over 13 ./table/*.go
gocyclo -over 13 ./progress/*.go
#gocyclo -over 13 ./prompt/*.go
gocyclo -over 13 ./text/*.go

demo-list:
go run cmd/demo-list/demo.go

demo-progress:
go run cmd/demo-progress/demo.go

demo-prompt:
go run cmd/demo-prompt/demo.go

demo-table:
go run cmd/demo-table/demo.go

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# go-pretty

[![Go Reference](https://pkg.go.dev/badge/github.com/jedib0t/go-pretty/v6.svg)](https://pkg.go.dev/github.com/jedib0t/go-pretty/v6)
![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)
[![Build Status](https://github.com/jedib0t/go-pretty/workflows/CI/badge.svg?branch=main)](https://github.com/jedib0t/go-pretty/actions?query=workflow%3ACI+event%3Apush+branch%3Amain)
[![Coverage Status](https://coveralls.io/repos/github/jedib0t/go-pretty/badge.svg?branch=main)](https://coveralls.io/github/jedib0t/go-pretty?branch=main)
[![Go Report Card](https://goreportcard.com/badge/github.com/jedib0t/go-pretty/v6)](https://goreportcard.com/report/github.com/jedib0t/go-pretty/v6)
Expand Down
107 changes: 107 additions & 0 deletions cmd/demo-prompt/demo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package main

import (
"errors"
"flag"
"fmt"
"os"
"time"

"github.com/jedib0t/go-pretty/v6/prompt"
"github.com/jedib0t/go-pretty/v6/text"
"github.com/nsf/termbox-go"
)

var (
flagDebug = flag.Bool("debug", false, "Write debug logs to prompt.log?")
flagNoTermBox = flag.Bool("no-termbox", false, "Do not use TermBox?")
flagTestTermBox = flag.Bool("test-termbox", false, "Test TermBox?")
)

func demoPrompt() {
colorFaint := text.FgHiBlack
colorTitle := text.Colors{text.FgHiCyan, text.Bold}
count := 0
errStop := errors.New("demo.stop")
inputHandler := prompt.Callback(func(userInput string, err error) error {
// handle errors and user exit attempts
if err != nil {
if err == prompt.ErrAbort {
return errStop
}
return err
} else if userInput == "/quit" {
return errStop
}

// deal with user input: to keep it a simple demo, just print it out
count++
fmt.Println(colorFaint.Sprintf("userInput: %#v", userInput))
return nil
})
timeStart := time.Now()
title := "" +
colorTitle.Sprint("********************************************************************") + "\n" +
colorTitle.Sprint("*** SQL prompt powered by github.com/jedib0t/go-pretty/v6/prompt ***") + "\n" +
colorTitle.Sprint("********************************************************************") + "\n" +
colorFaint.Sprint("(press Ctrl+D or type '/quit' and press Enter to terminate)")

p := prompt.NewWriter()
if *flagDebug {
p.Debug()
}
if *flagNoTermBox {
p.DoNotUseTermbox()
}
p.SetAutoCompleter(prompt.AutoCompleteSQLKeywords())
p.SetHistory([]string{
"SELECT * FROM employees WHERE id = 1;",
"SELECT * FROM employees WHERE\n\tid BETWEEN (1, 101) AND\n\temployees.salary > 13000;",
})
p.SetStyle(prompt.StyleColored)
p.SetTerminationChecker(prompt.TerminationCheckerSQL)
p.SetTitle(title)
p.Style().SyntaxHighlighter = prompt.SyntaxHighlighterOptionsSQL
defer func() {
fmt.Printf(colorFaint.Sprintf(
"Bye! (evaluated %d command(s) in %s)\n", count, time.Since(timeStart).Round(time.Second),
))
}()

if err := p.Render(inputHandler); err != nil {
if err != errStop {
fmt.Printf("ERROR: %v\n", err)
os.Exit(-1)
}
}
}

func testTermBoxPolling() {
err := termbox.Init()
if err != nil {
panic(err)
}
count := 0
fmt.Printf("Polling for events... (press Ctrl+D to exit)\n")
for {
event := termbox.PollEvent()
count++
fmt.Printf(">> %#v [ch: %c]\n", event, event.Ch)
if event.Key == termbox.KeyCtrlD {
break
}
}
termbox.Close()

fmt.Printf("Polling for events... done! [found %d events]\n", count)
}

func main() {
flag.Parse()

if *flagTestTermBox {
testTermBoxPolling()
} else {
demoPrompt()
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ module github.com/jedib0t/go-pretty/v6
go 1.16

require (
github.com/alecthomas/chroma v0.10.0
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203
github.com/mattn/go-runewidth v0.0.13
github.com/nsf/termbox-go v1.1.1
github.com/pkg/profile v1.6.0
github.com/stretchr/testify v1.7.4
golang.org/x/sys v0.1.0
Expand Down
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg=
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=
github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -11,9 +20,11 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
4 changes: 4 additions & 0 deletions prompt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Prompt
[![Go Reference](https://pkg.go.dev/badge/github.com/jedib0t/go-pretty/v6/prompt.svg)](https://pkg.go.dev/github.com/jedib0t/go-pretty/v6/prompt)

A customizable prompt for building your own CLIs.
45 changes: 45 additions & 0 deletions prompt/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package prompt

// Action defines an activity that is done based on a key sequence.
type Action string

// Supported Actions.
const (
None Action = "" // no action
Abort Action = "Abort" // abort the prompt completely and return to caller

// insert-mode actions
DeleteCharCurrent Action = "DeleteCharCurrent" // delete the character at the cursor
DeleteCharPrevious Action = "DeleteCharPrevious" // delete the character before the cursor
DeleteWordNext Action = "DeleteWordNext" // delete the next work
DeleteWordPrevious Action = "DeleteWordPrevious" // delete the previous word
EraseEverything Action = "EraseEverything" // erase the entire prompt
EraseToBeginningOfLine Action = "EraseToBeginningOfLine" // erase from cursor to the the beginning of current line
EraseToEndOfLine Action = "EraseToEndOfLine" // erase from cursor to the the end of current line
HistoryDown Action = "HistoryDown" // show command executed after current command if any
HistoryUp Action = "HistoryUp" // show previously executed command if any
MakeWordCapitalCase Action = "MakeWordCapitalCase" // make the word at the cursor capitalized
MakeWordLowerCase Action = "MakeWordLowerCase" // make the word at the cursor lower case
MakeWordUpperCase Action = "MakeWordUpperCase" // make the word at the cursor upper case
MoveDownOneLine Action = "MoveDownOneLine" // move the cursor down one line
MoveLeftOneCharacter Action = "MoveLeftOneCharacter" // move the cursor left one character
MoveRightOneCharacter Action = "MoveRightOneCharacter" // move the cursor right one character
MoveUpOneLine Action = "MoveUpOneLine" // move the cursor up one line
MoveToBeginning Action = "MoveToBeginning" // move to the beginning of the entire prompt text
MoveToBeginningOfLine Action = "MoveToBeginningOfLine" // move to the beginning of the current line
MoveToEnd Action = "MoveToEnd" // move to the end of the entire prompt text
MoveToEndOfLine Action = "MoveToEndOfLine" // move to the end of the current line
MoveToWordNext Action = "MoveToWordNext" // move to the beginning of the next word
MoveToWordPrevious Action = "MoveToWordPrevious" // move to the beginning of the previous word
SwapCharacterNext Action = "SwapCharacterNext" // swap the character at the cursor with the next
SwapCharacterPrevious Action = "SwapCharacterPrevious" // swap the character at the cursor with the previous
SwapWordNext Action = "SwapWordNext" // swap the word at the cursor with the next
SwapWordPrevious Action = "SwapWordPrevious" // swap the word at the cursor with the previous
Terminate Action = "Terminate" // trigger the termination checker if any, or call the callback function

// auto-complete specific actions
AutoCompleteChooseNext Action = "AutoCompleteChooseNext" // choose the next suggestion
AutoCompleteChoosePrevious Action = "AutoCompleteChoosePrevious" // choose the previous suggestion
AutoCompleteHide Action = "AutoCompleteHide" // hide the auto-complete suggestions pop-up
AutoCompleteSelect Action = "AutoCompleteSelect" // select the current suggestion
)

0 comments on commit 15d9552

Please sign in to comment.