2019-12-18 18:38:21 +08:00
|
|
|
package edit
|
2019-05-14 17:59:41 +08:00
|
|
|
|
|
|
|
import (
|
2020-05-04 03:39:24 +08:00
|
|
|
"fmt"
|
2019-11-04 22:03:48 +08:00
|
|
|
"strings"
|
2019-05-14 17:59:41 +08:00
|
|
|
"testing"
|
2021-10-05 08:02:54 +08:00
|
|
|
"time"
|
2019-05-14 17:59:41 +08:00
|
|
|
|
2021-01-27 09:28:38 +08:00
|
|
|
"src.elv.sh/pkg/cli/clitest"
|
|
|
|
"src.elv.sh/pkg/cli/term"
|
|
|
|
"src.elv.sh/pkg/testutil"
|
|
|
|
"src.elv.sh/pkg/ui"
|
2019-05-14 17:59:41 +08:00
|
|
|
)
|
|
|
|
|
2019-11-07 04:38:05 +08:00
|
|
|
func TestPrompt_ValueOutput(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(`edit:prompt = { put '#'; num 13; styled '> ' red }`))
|
2019-05-14 17:59:41 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t,
|
2020-11-27 11:53:03 +08:00
|
|
|
"#13> ", Styles,
|
2019-12-08 05:24:00 +08:00
|
|
|
" !!", term.DotHere)
|
2019-11-07 04:38:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPrompt_ByteOutput(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(`edit:prompt = { print 'bytes> ' }`))
|
2019-11-07 04:38:05 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t, "bytes> ", term.DotHere)
|
2019-11-07 04:38:05 +08:00
|
|
|
}
|
|
|
|
|
2020-08-26 06:04:14 +08:00
|
|
|
func TestPrompt_ParsesSGRInByteOutput(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(`edit:prompt = { print "\033[31mred\033[m> " }`))
|
2020-08-26 06:04:14 +08:00
|
|
|
|
|
|
|
f.TestTTY(t,
|
|
|
|
"red> ", Styles,
|
|
|
|
"!!! ", term.DotHere)
|
|
|
|
}
|
|
|
|
|
2019-11-07 04:38:05 +08:00
|
|
|
func TestPrompt_NotifiesInvalidValueOutput(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(`edit:prompt = { put good [bad] good2 }`))
|
2019-11-07 04:38:05 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t, "goodgood2", term.DotHere)
|
|
|
|
f.TestTTYNotes(t, "invalid output type from prompt: list")
|
2019-11-07 04:38:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPrompt_NotifiesException(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(`edit:prompt = { fail ERROR }`))
|
2019-11-07 04:38:05 +08:00
|
|
|
|
2020-05-03 06:11:50 +08:00
|
|
|
f.TestTTYNotes(t,
|
2020-05-04 06:06:08 +08:00
|
|
|
"[prompt error] ERROR\n",
|
2020-10-23 19:36:24 +08:00
|
|
|
`see stack trace with "show $edit:exceptions[0]"`)
|
2020-05-03 06:11:50 +08:00
|
|
|
evals(f.Evaler, `excs = (count $edit:exceptions)`)
|
2021-04-04 20:37:38 +08:00
|
|
|
testGlobal(t, f.Evaler, "excs", 1)
|
2019-11-04 22:03:48 +08:00
|
|
|
}
|
2019-05-14 17:59:41 +08:00
|
|
|
|
2019-11-04 22:03:48 +08:00
|
|
|
func TestRPrompt(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(`edit:rprompt = { put 'RRR' }`))
|
2019-11-04 22:03:48 +08:00
|
|
|
|
2019-12-18 18:26:49 +08:00
|
|
|
f.TestTTY(t, "~> ", term.DotHere,
|
2020-09-03 11:44:55 +08:00
|
|
|
strings.Repeat(" ", clitest.FakeTTYWidth-6)+"RRR")
|
2019-05-14 17:59:41 +08:00
|
|
|
}
|
|
|
|
|
2019-11-07 03:27:22 +08:00
|
|
|
func TestPromptEagerness(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(
|
2019-11-07 07:14:06 +08:00
|
|
|
`i = 0`,
|
|
|
|
`edit:prompt = { i = (+ $i 1); put $i'> ' }`,
|
2019-12-02 09:19:33 +08:00
|
|
|
`edit:-prompt-eagerness = 10`))
|
2019-11-07 03:27:22 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t, "1> ", term.DotHere)
|
2019-11-07 03:27:22 +08:00
|
|
|
// With eagerness = 10, any key press will cause the prompt to be
|
|
|
|
// recomputed.
|
2019-11-08 23:49:43 +08:00
|
|
|
f.TTYCtrl.Inject(term.K(ui.Backspace))
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t, "2> ", term.DotHere)
|
2019-11-07 03:27:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPromptStaleThreshold(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(
|
2021-10-03 23:40:48 +08:00
|
|
|
`pipe = (file:pipe)`,
|
2019-11-07 07:27:17 +08:00
|
|
|
`edit:prompt = { nop (slurp < $pipe); put '> ' }`,
|
2020-05-04 03:39:24 +08:00
|
|
|
`edit:prompt-stale-threshold = `+scaledMsAsSec(50)))
|
2019-11-07 03:27:22 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t,
|
|
|
|
"???> ", Styles,
|
|
|
|
"+++++", term.DotHere)
|
2019-11-07 03:27:22 +08:00
|
|
|
|
2021-07-14 11:44:37 +08:00
|
|
|
evals(f.Evaler, `file:close $pipe[w]`)
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t, "> ", term.DotHere)
|
2021-07-14 11:44:37 +08:00
|
|
|
evals(f.Evaler, `file:close $pipe[r]`)
|
2019-11-07 03:27:22 +08:00
|
|
|
}
|
|
|
|
|
2019-11-07 04:38:05 +08:00
|
|
|
func TestPromptStaleTransform(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(
|
2021-10-03 23:40:48 +08:00
|
|
|
`pipe = (file:pipe)`,
|
2019-11-07 07:27:17 +08:00
|
|
|
`edit:prompt = { nop (slurp < $pipe); put '> ' }`,
|
2020-05-04 03:39:24 +08:00
|
|
|
`edit:prompt-stale-threshold = `+scaledMsAsSec(50),
|
2021-11-29 05:32:41 +08:00
|
|
|
`edit:prompt-stale-transform = {|a| put S; put $a; put S }`))
|
2019-05-14 17:59:41 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t, "S???> S", term.DotHere)
|
2021-07-14 11:44:37 +08:00
|
|
|
evals(f.Evaler, `file:close $pipe[w]`)
|
|
|
|
evals(f.Evaler, `file:close $pipe[r]`)
|
2019-05-14 17:59:41 +08:00
|
|
|
}
|
|
|
|
|
2020-05-04 06:06:08 +08:00
|
|
|
func TestPromptStaleTransform_Exception(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(
|
2021-10-03 23:40:48 +08:00
|
|
|
`pipe = (file:pipe)`,
|
2020-05-04 06:06:08 +08:00
|
|
|
`edit:prompt = { nop (slurp < $pipe); put '> ' }`,
|
|
|
|
`edit:prompt-stale-threshold = `+scaledMsAsSec(50),
|
2021-11-29 05:32:41 +08:00
|
|
|
`edit:prompt-stale-transform = {|_| fail ERROR }`))
|
2020-05-04 06:06:08 +08:00
|
|
|
|
|
|
|
f.TestTTYNotes(t,
|
|
|
|
"[prompt stale transform error] ERROR\n",
|
2020-10-23 19:36:24 +08:00
|
|
|
`see stack trace with "show $edit:exceptions[0]"`)
|
2020-05-04 06:06:08 +08:00
|
|
|
evals(f.Evaler, `excs = (count $edit:exceptions)`)
|
2021-04-04 20:37:38 +08:00
|
|
|
testGlobal(t, f.Evaler, "excs", 1)
|
2020-05-04 06:06:08 +08:00
|
|
|
}
|
|
|
|
|
2019-11-08 18:30:55 +08:00
|
|
|
func TestRPromptPersistent_True(t *testing.T) {
|
2019-12-08 05:24:00 +08:00
|
|
|
testRPromptPersistent(t, `edit:rprompt-persistent = $true`,
|
2020-09-03 11:44:55 +08:00
|
|
|
"~> "+strings.Repeat(" ", clitest.FakeTTYWidth-6)+"RRR",
|
2019-12-08 05:24:00 +08:00
|
|
|
"\n", term.DotHere,
|
|
|
|
)
|
2019-11-08 18:30:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestRPromptPersistent_False(t *testing.T) {
|
2019-12-08 05:24:00 +08:00
|
|
|
testRPromptPersistent(t, `edit:rprompt-persistent = $false`,
|
|
|
|
"~> ", // no rprompt
|
|
|
|
"\n", term.DotHere,
|
|
|
|
)
|
2019-11-08 18:30:55 +08:00
|
|
|
}
|
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
func testRPromptPersistent(t *testing.T, code string, finalBuf ...interface{}) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, rc(`edit:rprompt = { put RRR }`, code))
|
2019-11-08 18:30:55 +08:00
|
|
|
|
2020-10-06 02:35:52 +08:00
|
|
|
// Make sure that the UI has stabilized before hitting Enter.
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t,
|
|
|
|
"~> ", term.DotHere,
|
2020-09-03 11:44:55 +08:00
|
|
|
strings.Repeat(" ", clitest.FakeTTYWidth-6), "RRR",
|
2019-12-08 05:24:00 +08:00
|
|
|
)
|
2019-11-08 18:30:55 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TTYCtrl.Inject(term.K('\n'))
|
|
|
|
f.TestTTY(t, finalBuf...)
|
2019-11-08 18:30:55 +08:00
|
|
|
}
|
|
|
|
|
2019-11-07 04:38:05 +08:00
|
|
|
func TestDefaultPromptForNonRoot(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, assign("edit:prompt", getDefaultPrompt(false)))
|
2019-05-14 17:59:41 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t, "~> ", term.DotHere)
|
2019-05-14 17:59:41 +08:00
|
|
|
}
|
|
|
|
|
2019-11-07 04:38:05 +08:00
|
|
|
func TestDefaultPromptForRoot(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, assign("edit:prompt", getDefaultPrompt(true)))
|
2019-05-14 17:59:41 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t,
|
|
|
|
"~# ", Styles,
|
|
|
|
" !!", term.DotHere)
|
2019-05-14 17:59:41 +08:00
|
|
|
}
|
|
|
|
|
2019-11-07 04:38:05 +08:00
|
|
|
func TestDefaultRPrompt(t *testing.T) {
|
2021-08-07 05:18:09 +08:00
|
|
|
f := setup(t, assign("edit:rprompt", getDefaultRPrompt("elf", "host")))
|
2019-11-07 04:38:05 +08:00
|
|
|
|
2019-12-08 05:24:00 +08:00
|
|
|
f.TestTTY(t,
|
|
|
|
"~> ", term.DotHere, strings.Repeat(" ", 39),
|
|
|
|
"elf@host", Styles,
|
|
|
|
"++++++++")
|
2019-05-14 17:59:41 +08:00
|
|
|
}
|
2020-05-04 03:39:24 +08:00
|
|
|
|
|
|
|
func scaledMsAsSec(ms int) string {
|
2021-10-05 08:02:54 +08:00
|
|
|
return fmt.Sprint(testutil.Scaled(time.Duration(ms) * time.Millisecond).Seconds())
|
2020-05-04 03:39:24 +08:00
|
|
|
}
|