mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
POC for odo interactive testing (#5466)
* POC for odo interactive testing
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* add interactive tests to make target test-integration
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* [WIP] use func to pass test instructions
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* cleanup comments/test
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* cleanup minor changes
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* fix unit test failure
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* skip for windows
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* skip for windows by not compiling, cleanup
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* cleanup, and add the make target to test files
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* incorporate review, adding comments, cleanup
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* fix failing make validate
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* update test dependency, and possible fix for windows
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
* Revert "update test dependency, and possible fix for windows"
This reverts commit 55580b7dc5.
* Final cleanup
Signed-off-by: anandrkskd <anandrkskd@gmail.com>
This commit is contained in:
committed by
GitHub
parent
fbdacb2dde
commit
3eb92b6a47
@@ -14,6 +14,7 @@ cleanup_namespaces
|
|||||||
set -e
|
set -e
|
||||||
make install
|
make install
|
||||||
make test-integration-devfile
|
make test-integration-devfile
|
||||||
|
make test-integration-interactive
|
||||||
make test-e2e-devfile
|
make test-e2e-devfile
|
||||||
make test-cmd-project
|
make test-cmd-project
|
||||||
) |& tee "/tmp/${LOGFILE}"
|
) |& tee "/tmp/${LOGFILE}"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ cleanup_namespaces
|
|||||||
set -e
|
set -e
|
||||||
make install
|
make install
|
||||||
make test-integration
|
make test-integration
|
||||||
|
make test-integration-interactive
|
||||||
make test-integration-devfile
|
make test-integration-devfile
|
||||||
make test-cmd-login-logout
|
make test-cmd-login-logout
|
||||||
make test-cmd-project
|
make test-cmd-project
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -266,6 +266,11 @@ test-cmd-debug: ## Run odo debug command tests
|
|||||||
test-integration: ## Run command's integration tests irrespective of service catalog status in the cluster.
|
test-integration: ## Run command's integration tests irrespective of service catalog status in the cluster.
|
||||||
$(RUN_GINKGO) $(GINKGO_FLAGS) tests/integration/
|
$(RUN_GINKGO) $(GINKGO_FLAGS) tests/integration/
|
||||||
|
|
||||||
|
## Run integration interactive tests
|
||||||
|
.PHONY: test-interactive test
|
||||||
|
test-integration-interactive:
|
||||||
|
$(RUN_GINKGO) $(GINKGO_FLAGS) tests/integration/interactive/
|
||||||
|
|
||||||
.PHONY: test-integration-devfile
|
.PHONY: test-integration-devfile
|
||||||
test-integration-devfile: ## Run devfile integration tests
|
test-integration-devfile: ## Run devfile integration tests
|
||||||
$(RUN_GINKGO) $(GINKGO_FLAGS) tests/integration/devfile/
|
$(RUN_GINKGO) $(GINKGO_FLAGS) tests/integration/devfile/
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -18,7 +18,8 @@ require (
|
|||||||
github.com/go-git/go-git/v5 v5.3.0
|
github.com/go-git/go-git/v5 v5.3.0
|
||||||
github.com/go-openapi/spec v0.19.5
|
github.com/go-openapi/spec v0.19.5
|
||||||
github.com/golang/mock v1.5.0
|
github.com/golang/mock v1.5.0
|
||||||
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c
|
github.com/hinshun/vt10x v0.0.0-20220127042424-3ca73d0126d7
|
||||||
|
github.com/kr/pty v1.1.5
|
||||||
github.com/kubernetes-sigs/service-catalog v0.3.1
|
github.com/kubernetes-sigs/service-catalog v0.3.1
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/mattn/go-colorable v0.1.8
|
github.com/mattn/go-colorable v0.1.8
|
||||||
@@ -42,7 +43,6 @@ require (
|
|||||||
github.com/spf13/afero v1.2.2
|
github.com/spf13/afero v1.2.2
|
||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.1.3
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.7.0
|
|
||||||
github.com/tidwall/gjson v1.9.3
|
github.com/tidwall/gjson v1.9.3
|
||||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
||||||
github.com/zalando/go-keyring v0.1.1
|
github.com/zalando/go-keyring v0.1.1
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -642,8 +642,8 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
|
|||||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||||
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c h1:kp3AxgXgDOmIJFR7bIwqFhwJ2qWar8tEQSE5XXhCfVk=
|
github.com/hinshun/vt10x v0.0.0-20220127042424-3ca73d0126d7 h1:PoerlCqzob3t6b5/8mjCPkX4QSTYR4/+kB8IzqZE3ug=
|
||||||
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
github.com/hinshun/vt10x v0.0.0-20220127042424-3ca73d0126d7/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||||
github.com/hokaccha/go-prettyjson v0.0.0-20190818114111-108c894c2c0e/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI=
|
github.com/hokaccha/go-prettyjson v0.0.0-20190818114111-108c894c2c0e/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
package testingutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/Netflix/go-expect"
|
|
||||||
"github.com/hinshun/vt10x"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"gopkg.in/AlecAivazis/survey.v1"
|
|
||||||
"gopkg.in/AlecAivazis/survey.v1/terminal"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This whole file copies the testing infrastructure from survey lib since it cannot be imported. This mixes elements from:
|
|
||||||
// vendor/gopkg.in/AlecAivazis/survey.v1/survey_posix_test.go
|
|
||||||
// vendor/gopkg.in/AlecAivazis/survey.v1/survey_test.go
|
|
||||||
// vendor/gopkg.in/AlecAivazis/survey.v1/survey.go
|
|
||||||
|
|
||||||
type wantsStdio interface {
|
|
||||||
WithStdio(terminal.Stdio)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stdio converts an expect.Console into a survey terminal.Stdio
|
|
||||||
func Stdio(c *expect.Console) terminal.Stdio {
|
|
||||||
return terminal.Stdio{In: c.Tty(), Out: c.Tty(), Err: c.Tty()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PromptTest encapsulates a survey prompt test
|
|
||||||
type PromptTest struct {
|
|
||||||
// Name of the test
|
|
||||||
Name string
|
|
||||||
// Prompt to test
|
|
||||||
Prompt survey.Prompt
|
|
||||||
// Procedure defines the list of interaction with the console simulating user actions
|
|
||||||
Procedure func(*expect.Console)
|
|
||||||
// Expected result
|
|
||||||
Expected interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunPromptTest runs the specified PromptTest in the given testing context
|
|
||||||
func RunPromptTest(t *testing.T, test PromptTest) {
|
|
||||||
var answer interface{}
|
|
||||||
RunTest(t, test.Procedure, func(stdio terminal.Stdio) error {
|
|
||||||
var err error
|
|
||||||
if p, ok := test.Prompt.(wantsStdio); ok {
|
|
||||||
p.WithStdio(stdio)
|
|
||||||
}
|
|
||||||
answer, err = test.Prompt.Prompt()
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
require.Equal(t, test.Expected, answer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunTest runs the given test using the specified procedure simulating the user interaction with the console
|
|
||||||
func RunTest(t *testing.T, procedure func(*expect.Console), test func(terminal.Stdio) error) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
// Multiplex output to a buffer as well for the raw bytes.
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
c, state, err := vt10x.NewVT10XConsole(expect.WithStdout(buf))
|
|
||||||
require.Nil(t, err)
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
donec := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
defer close(donec)
|
|
||||||
procedure(c)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = test(Stdio(c))
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Close the slave end of the pty, and read the remaining bytes from the master end.
|
|
||||||
c.Tty().Close()
|
|
||||||
<-donec
|
|
||||||
|
|
||||||
t.Logf("Raw output: %q", buf.String())
|
|
||||||
|
|
||||||
// Dump the terminal's screen.
|
|
||||||
t.Logf("\n%s", expect.StripTrailingEmptyLines(state.String()))
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,7 @@ oc whoami
|
|||||||
# Integration tests
|
# Integration tests
|
||||||
make test-integration || error=true
|
make test-integration || error=true
|
||||||
make test-integration-devfile || error=true
|
make test-integration-devfile || error=true
|
||||||
|
make test-integration-interactive || error=true
|
||||||
make test-cmd-login-logout || error=true
|
make test-cmd-login-logout || error=true
|
||||||
make test-cmd-project || error=true
|
make test-cmd-project || error=true
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ elif [ "${ARCH}" == "ppc64le" ]; then
|
|||||||
else
|
else
|
||||||
# Integration tests
|
# Integration tests
|
||||||
make test-integration || error=true
|
make test-integration || error=true
|
||||||
|
make test-integration-interactive || error=true
|
||||||
make test-integration-devfile || error=true
|
make test-integration-devfile || error=true
|
||||||
make test-cmd-login-logout || error=true
|
make test-cmd-login-logout || error=true
|
||||||
make test-cmd-project || error=true
|
make test-cmd-project || error=true
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
//go:build tools
|
||||||
// +build tools
|
// +build tools
|
||||||
|
|
||||||
package tools
|
package tools
|
||||||
|
|||||||
66
tests/helper/helper_interactive.go
Normal file
66
tests/helper/helper_interactive.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//go:build linux || darwin || dragonfly || solaris || openbsd || netbsd || freebsd
|
||||||
|
// +build linux darwin dragonfly solaris openbsd netbsd freebsd
|
||||||
|
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/Netflix/go-expect"
|
||||||
|
"github.com/hinshun/vt10x"
|
||||||
|
"github.com/kr/pty"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunInteractive runs the command in interactive mode and returns the output, and error
|
||||||
|
// It takes command as array of strings, and a function `test` that contains steps to run the test as an argument
|
||||||
|
func RunInteractive(command []string, test func(*expect.Console, *bytes.Buffer)) (string, error) {
|
||||||
|
|
||||||
|
ptm, pts, err := pty.Open()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
term := vt10x.New(vt10x.WithWriter(pts))
|
||||||
|
|
||||||
|
c, err := expect.NewConsole(expect.WithStdin(ptm), expect.WithStdout(term), expect.WithCloser(pts, ptm))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
// execute the command
|
||||||
|
cmd := exec.Command(command[0], command[1:]...)
|
||||||
|
// setup stdin, stdout and stderr
|
||||||
|
cmd.Stdin = c.Tty()
|
||||||
|
cmd.Stdout = c.Tty()
|
||||||
|
cmd.Stderr = c.Tty()
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
test(c, buf)
|
||||||
|
err = cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// Close the slave end of the pty, and read the remaining bytes from the master end.
|
||||||
|
c.Tty().Close()
|
||||||
|
|
||||||
|
return buf.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendLine(c *expect.Console, line string) {
|
||||||
|
_, err := c.SendLine(line)
|
||||||
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExpectString(c *expect.Console, line string) string {
|
||||||
|
res, err := c.ExpectString(line)
|
||||||
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
return res
|
||||||
|
}
|
||||||
62
tests/integration/interactive/cmd_init_test.go
Normal file
62
tests/integration/interactive/cmd_init_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
//go:build linux || darwin || dragonfly || solaris || openbsd || netbsd || freebsd
|
||||||
|
// +build linux darwin dragonfly solaris openbsd netbsd freebsd
|
||||||
|
|
||||||
|
package interactive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Netflix/go-expect"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/redhat-developer/odo/tests/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("odo init interactive command tests", func() {
|
||||||
|
|
||||||
|
var commonVar helper.CommonVar
|
||||||
|
|
||||||
|
// This is run before every Spec (It)
|
||||||
|
var _ = BeforeEach(func() {
|
||||||
|
commonVar = helper.CommonBeforeEach()
|
||||||
|
helper.Chdir(commonVar.Context)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Clean up after the test
|
||||||
|
// This is run after every Spec (It)
|
||||||
|
var _ = AfterEach(func() {
|
||||||
|
helper.CommonAfterEach(commonVar)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should download correct devfile", func() {
|
||||||
|
|
||||||
|
command := []string{"odo", "init"}
|
||||||
|
output, err := helper.RunInteractive(command, func(c *expect.Console, output *bytes.Buffer) {
|
||||||
|
|
||||||
|
res := helper.ExpectString(c, "Select language")
|
||||||
|
fmt.Fprintln(output, res)
|
||||||
|
helper.SendLine(c, "go")
|
||||||
|
|
||||||
|
res = helper.ExpectString(c, "Select project type")
|
||||||
|
fmt.Fprintln(output, res)
|
||||||
|
helper.SendLine(c, "\n")
|
||||||
|
|
||||||
|
res = helper.ExpectString(c, "Which starter project do you want to use")
|
||||||
|
fmt.Fprintln(output, res)
|
||||||
|
helper.SendLine(c, "\n")
|
||||||
|
|
||||||
|
res = helper.ExpectString(c, "Enter component name")
|
||||||
|
fmt.Fprintln(output, res)
|
||||||
|
helper.SendLine(c, "my-go-app")
|
||||||
|
|
||||||
|
res = helper.ExpectString(c, "Your new component \"my-go-app\" is ready in the current directory.")
|
||||||
|
fmt.Fprintln(output, res)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(output).To(ContainSubstring("Your new component \"my-go-app\" is ready in the current directory."))
|
||||||
|
Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements("devfile.yaml"))
|
||||||
|
})
|
||||||
|
})
|
||||||
15
tests/integration/interactive/interactive_suit_test.go
Normal file
15
tests/integration/interactive/interactive_suit_test.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// +build linux darwin dragonfly solaris openbsd netbsd freebsd
|
||||||
|
//go:build !race
|
||||||
|
// +build !race
|
||||||
|
|
||||||
|
package interactive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/redhat-developer/odo/tests/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInteractive(t *testing.T) {
|
||||||
|
helper.RunTestSpecs(t, "Interactive Suite")
|
||||||
|
}
|
||||||
96
vendor/github.com/hinshun/vt10x/Gopkg.lock
generated
vendored
96
vendor/github.com/hinshun/vt10x/Gopkg.lock
generated
vendored
@@ -1,96 +0,0 @@
|
|||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
|
||||||
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/Netflix/go-expect"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "c93bf25de8e869da25cf26bcd2932b36141f61ae"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/davecgh/go-spew"
|
|
||||||
packages = ["spew"]
|
|
||||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/gdamore/encoding"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "b23993cbb6353f0e6aa98d0ee318a34728f628b9"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/gdamore/tcell"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"terminfo"
|
|
||||||
]
|
|
||||||
revision = "b3cebc399d6f98536af845ed8a5144ab586f6759"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/kr/pty"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "282ce0e5322c82529687d609ee670fac7c7d917c"
|
|
||||||
version = "v1.1.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/lucasb-eyer/go-colorful"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "345fbb3dbcdb252d9985ee899a84963c0fa24c82"
|
|
||||||
version = "v1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/mattn/go-runewidth"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
|
|
||||||
version = "v0.0.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/pmezard/go-difflib"
|
|
||||||
packages = ["difflib"]
|
|
||||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
|
||||||
version = "v1.0.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
packages = [
|
|
||||||
"assert",
|
|
||||||
"require"
|
|
||||||
]
|
|
||||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
|
||||||
version = "v1.2.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/crypto"
|
|
||||||
packages = ["ssh/terminal"]
|
|
||||||
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/sys"
|
|
||||||
packages = [
|
|
||||||
"unix",
|
|
||||||
"windows"
|
|
||||||
]
|
|
||||||
revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "golang.org/x/text"
|
|
||||||
packages = [
|
|
||||||
"encoding",
|
|
||||||
"encoding/internal/identifier",
|
|
||||||
"internal/gen",
|
|
||||||
"transform",
|
|
||||||
"unicode/cldr"
|
|
||||||
]
|
|
||||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
|
||||||
version = "v0.3.0"
|
|
||||||
|
|
||||||
[solve-meta]
|
|
||||||
analyzer-name = "dep"
|
|
||||||
analyzer-version = 1
|
|
||||||
inputs-digest = "bd24f29ad753e2f861768c734d71fbbc4e0380b5d7b43b6b101c01274cabcedb"
|
|
||||||
solver-name = "gps-cdcl"
|
|
||||||
solver-version = 1
|
|
||||||
38
vendor/github.com/hinshun/vt10x/Gopkg.toml
generated
vendored
38
vendor/github.com/hinshun/vt10x/Gopkg.toml
generated
vendored
@@ -1,38 +0,0 @@
|
|||||||
# Gopkg.toml example
|
|
||||||
#
|
|
||||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
|
||||||
# for detailed Gopkg.toml documentation.
|
|
||||||
#
|
|
||||||
# required = ["github.com/user/thing/cmd/thing"]
|
|
||||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project"
|
|
||||||
# version = "1.0.0"
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project2"
|
|
||||||
# branch = "dev"
|
|
||||||
# source = "github.com/myfork/project2"
|
|
||||||
#
|
|
||||||
# [[override]]
|
|
||||||
# name = "github.com/x/y"
|
|
||||||
# version = "2.4.0"
|
|
||||||
#
|
|
||||||
# [prune]
|
|
||||||
# non-go = false
|
|
||||||
# go-tests = true
|
|
||||||
# unused-packages = true
|
|
||||||
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/kr/pty"
|
|
||||||
version = "1.1.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
version = "1.2.1"
|
|
||||||
|
|
||||||
[prune]
|
|
||||||
go-tests = true
|
|
||||||
unused-packages = true
|
|
||||||
5
vendor/github.com/hinshun/vt10x/color.go
generated
vendored
5
vendor/github.com/hinshun/vt10x/color.go
generated
vendored
@@ -24,12 +24,13 @@ const (
|
|||||||
// For example, a transparent background. Otherwise, the simple case is to
|
// For example, a transparent background. Otherwise, the simple case is to
|
||||||
// map default colors to another color.
|
// map default colors to another color.
|
||||||
const (
|
const (
|
||||||
DefaultFG Color = 0xff80 + iota
|
DefaultFG Color = 1<<24 + iota
|
||||||
DefaultBG
|
DefaultBG
|
||||||
|
DefaultCursor
|
||||||
)
|
)
|
||||||
|
|
||||||
// Color maps to the ANSI colors [0, 16) and the xterm colors [16, 256).
|
// Color maps to the ANSI colors [0, 16) and the xterm colors [16, 256).
|
||||||
type Color uint16
|
type Color uint32
|
||||||
|
|
||||||
// ANSI returns true if Color is within [0, 16).
|
// ANSI returns true if Color is within [0, 16).
|
||||||
func (c Color) ANSI() bool {
|
func (c Color) ANSI() bool {
|
||||||
|
|||||||
40
vendor/github.com/hinshun/vt10x/csi.go
generated
vendored
40
vendor/github.com/hinshun/vt10x/csi.go
generated
vendored
@@ -74,26 +74,26 @@ func (t *State) handleCSI() {
|
|||||||
case '@': // ICH - insert <n> blank char
|
case '@': // ICH - insert <n> blank char
|
||||||
t.insertBlanks(c.arg(0, 1))
|
t.insertBlanks(c.arg(0, 1))
|
||||||
case 'A': // CUU - cursor <n> up
|
case 'A': // CUU - cursor <n> up
|
||||||
t.moveTo(t.cur.x, t.cur.y-c.maxarg(0, 1))
|
t.moveTo(t.cur.X, t.cur.Y-c.maxarg(0, 1))
|
||||||
case 'B', 'e': // CUD, VPR - cursor <n> down
|
case 'B', 'e': // CUD, VPR - cursor <n> down
|
||||||
t.moveTo(t.cur.x, t.cur.y+c.maxarg(0, 1))
|
t.moveTo(t.cur.X, t.cur.Y+c.maxarg(0, 1))
|
||||||
case 'c': // DA - device attributes
|
case 'c': // DA - device attributes
|
||||||
if c.arg(0, 0) == 0 {
|
if c.arg(0, 0) == 0 {
|
||||||
// TODO: write vt102 id
|
// TODO: write vt102 id
|
||||||
}
|
}
|
||||||
case 'C', 'a': // CUF, HPR - cursor <n> forward
|
case 'C', 'a': // CUF, HPR - cursor <n> forward
|
||||||
t.moveTo(t.cur.x+c.maxarg(0, 1), t.cur.y)
|
t.moveTo(t.cur.X+c.maxarg(0, 1), t.cur.Y)
|
||||||
case 'D': // CUB - cursor <n> backward
|
case 'D': // CUB - cursor <n> backward
|
||||||
t.moveTo(t.cur.x-c.maxarg(0, 1), t.cur.y)
|
t.moveTo(t.cur.X-c.maxarg(0, 1), t.cur.Y)
|
||||||
case 'E': // CNL - cursor <n> down and first col
|
case 'E': // CNL - cursor <n> down and first col
|
||||||
t.moveTo(0, t.cur.y+c.arg(0, 1))
|
t.moveTo(0, t.cur.Y+c.arg(0, 1))
|
||||||
case 'F': // CPL - cursor <n> up and first col
|
case 'F': // CPL - cursor <n> up and first col
|
||||||
t.moveTo(0, t.cur.y-c.arg(0, 1))
|
t.moveTo(0, t.cur.Y-c.arg(0, 1))
|
||||||
case 'g': // TBC - tabulation clear
|
case 'g': // TBC - tabulation clear
|
||||||
switch c.arg(0, 0) {
|
switch c.arg(0, 0) {
|
||||||
// clear current tab stop
|
// clear current tab stop
|
||||||
case 0:
|
case 0:
|
||||||
t.tabs[t.cur.x] = false
|
t.tabs[t.cur.X] = false
|
||||||
// clear all tabs
|
// clear all tabs
|
||||||
case 3:
|
case 3:
|
||||||
for i := range t.tabs {
|
for i := range t.tabs {
|
||||||
@@ -103,7 +103,7 @@ func (t *State) handleCSI() {
|
|||||||
goto unknown
|
goto unknown
|
||||||
}
|
}
|
||||||
case 'G', '`': // CHA, HPA - Move to <col>
|
case 'G', '`': // CHA, HPA - Move to <col>
|
||||||
t.moveTo(c.arg(0, 1)-1, t.cur.y)
|
t.moveTo(c.arg(0, 1)-1, t.cur.Y)
|
||||||
case 'H', 'f': // CUP, HVP - move to <row> <col>
|
case 'H', 'f': // CUP, HVP - move to <row> <col>
|
||||||
t.moveAbsTo(c.arg(1, 1)-1, c.arg(0, 1)-1)
|
t.moveAbsTo(c.arg(1, 1)-1, c.arg(0, 1)-1)
|
||||||
case 'I': // CHT - cursor forward tabulation <n> tab stops
|
case 'I': // CHT - cursor forward tabulation <n> tab stops
|
||||||
@@ -115,15 +115,15 @@ func (t *State) handleCSI() {
|
|||||||
// TODO: sel.ob.x = -1
|
// TODO: sel.ob.x = -1
|
||||||
switch c.arg(0, 0) {
|
switch c.arg(0, 0) {
|
||||||
case 0: // below
|
case 0: // below
|
||||||
t.clear(t.cur.x, t.cur.y, t.cols-1, t.cur.y)
|
t.clear(t.cur.X, t.cur.Y, t.cols-1, t.cur.Y)
|
||||||
if t.cur.y < t.rows-1 {
|
if t.cur.Y < t.rows-1 {
|
||||||
t.clear(0, t.cur.y+1, t.cols-1, t.rows-1)
|
t.clear(0, t.cur.Y+1, t.cols-1, t.rows-1)
|
||||||
}
|
}
|
||||||
case 1: // above
|
case 1: // above
|
||||||
if t.cur.y > 1 {
|
if t.cur.Y > 1 {
|
||||||
t.clear(0, 0, t.cols-1, t.cur.y-1)
|
t.clear(0, 0, t.cols-1, t.cur.Y-1)
|
||||||
}
|
}
|
||||||
t.clear(0, t.cur.y, t.cur.x, t.cur.y)
|
t.clear(0, t.cur.Y, t.cur.X, t.cur.Y)
|
||||||
case 2: // all
|
case 2: // all
|
||||||
t.clear(0, 0, t.cols-1, t.rows-1)
|
t.clear(0, 0, t.cols-1, t.rows-1)
|
||||||
default:
|
default:
|
||||||
@@ -132,11 +132,11 @@ func (t *State) handleCSI() {
|
|||||||
case 'K': // EL - clear line
|
case 'K': // EL - clear line
|
||||||
switch c.arg(0, 0) {
|
switch c.arg(0, 0) {
|
||||||
case 0: // right
|
case 0: // right
|
||||||
t.clear(t.cur.x, t.cur.y, t.cols-1, t.cur.y)
|
t.clear(t.cur.X, t.cur.Y, t.cols-1, t.cur.Y)
|
||||||
case 1: // left
|
case 1: // left
|
||||||
t.clear(0, t.cur.y, t.cur.x, t.cur.y)
|
t.clear(0, t.cur.Y, t.cur.X, t.cur.Y)
|
||||||
case 2: // all
|
case 2: // all
|
||||||
t.clear(0, t.cur.y, t.cols-1, t.cur.y)
|
t.clear(0, t.cur.Y, t.cols-1, t.cur.Y)
|
||||||
}
|
}
|
||||||
case 'S': // SU - scroll <n> lines up
|
case 'S': // SU - scroll <n> lines up
|
||||||
t.scrollUp(t.top, c.arg(0, 1))
|
t.scrollUp(t.top, c.arg(0, 1))
|
||||||
@@ -149,7 +149,7 @@ func (t *State) handleCSI() {
|
|||||||
case 'M': // DL - delete <n> lines
|
case 'M': // DL - delete <n> lines
|
||||||
t.deleteLines(c.arg(0, 1))
|
t.deleteLines(c.arg(0, 1))
|
||||||
case 'X': // ECH - erase <n> chars
|
case 'X': // ECH - erase <n> chars
|
||||||
t.clear(t.cur.x, t.cur.y, t.cur.x+c.arg(0, 1)-1, t.cur.y)
|
t.clear(t.cur.X, t.cur.Y, t.cur.X+c.arg(0, 1)-1, t.cur.Y)
|
||||||
case 'P': // DCH - delete <n> chars
|
case 'P': // DCH - delete <n> chars
|
||||||
t.deleteChars(c.arg(0, 1))
|
t.deleteChars(c.arg(0, 1))
|
||||||
case 'Z': // CBT - cursor backward tabulation <n> tab stops
|
case 'Z': // CBT - cursor backward tabulation <n> tab stops
|
||||||
@@ -158,7 +158,7 @@ func (t *State) handleCSI() {
|
|||||||
t.putTab(false)
|
t.putTab(false)
|
||||||
}
|
}
|
||||||
case 'd': // VPA - move to <row>
|
case 'd': // VPA - move to <row>
|
||||||
t.moveAbsTo(t.cur.x, c.arg(0, 1)-1)
|
t.moveAbsTo(t.cur.X, c.arg(0, 1)-1)
|
||||||
case 'h': // SM - set terminal mode
|
case 'h': // SM - set terminal mode
|
||||||
t.setMode(c.priv, true, c.args)
|
t.setMode(c.priv, true, c.args)
|
||||||
case 'm': // SGR - terminal attribute (color)
|
case 'm': // SGR - terminal attribute (color)
|
||||||
@@ -168,7 +168,7 @@ func (t *State) handleCSI() {
|
|||||||
case 5: // DSR - device status report
|
case 5: // DSR - device status report
|
||||||
t.w.Write([]byte("\033[0n"))
|
t.w.Write([]byte("\033[0n"))
|
||||||
case 6: // CPR - cursor position report
|
case 6: // CPR - cursor position report
|
||||||
t.w.Write([]byte(fmt.Sprintf("\033[%d;%dR", t.cur.y+1, t.cur.x+1)))
|
t.w.Write([]byte(fmt.Sprintf("\033[%d;%dR", t.cur.Y+1, t.cur.X+1)))
|
||||||
}
|
}
|
||||||
case 'r': // DECSTBM - set scrolling region
|
case 'r': // DECSTBM - set scrolling region
|
||||||
if c.priv {
|
if c.priv {
|
||||||
|
|||||||
29
vendor/github.com/hinshun/vt10x/expect.go
generated
vendored
29
vendor/github.com/hinshun/vt10x/expect.go
generated
vendored
@@ -1,29 +0,0 @@
|
|||||||
package vt10x
|
|
||||||
|
|
||||||
import (
|
|
||||||
expect "github.com/Netflix/go-expect"
|
|
||||||
"github.com/kr/pty"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewVT10XConsole returns a new expect.Console that multiplexes the
|
|
||||||
// Stdin/Stdout to a VT10X terminal, allowing Console to interact with an
|
|
||||||
// application sending ANSI escape sequences.
|
|
||||||
func NewVT10XConsole(opts ...expect.ConsoleOpt) (*expect.Console, *State, error) {
|
|
||||||
ptm, pts, err := pty.Open()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var state State
|
|
||||||
term, err := Create(&state, pts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := expect.NewConsole(append(opts, expect.WithStdin(ptm), expect.WithStdout(term), expect.WithCloser(pts, ptm, term))...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, &state, nil
|
|
||||||
}
|
|
||||||
3
vendor/github.com/hinshun/vt10x/go.mod
generated
vendored
Normal file
3
vendor/github.com/hinshun/vt10x/go.mod
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/hinshun/vt10x
|
||||||
|
|
||||||
|
go 1.14
|
||||||
36
vendor/github.com/hinshun/vt10x/parse.go
generated
vendored
36
vendor/github.com/hinshun/vt10x/parse.go
generated
vendored
@@ -7,27 +7,27 @@ func isControlCode(c rune) bool {
|
|||||||
func (t *State) parse(c rune) {
|
func (t *State) parse(c rune) {
|
||||||
t.logf("%q", string(c))
|
t.logf("%q", string(c))
|
||||||
if isControlCode(c) {
|
if isControlCode(c) {
|
||||||
if t.handleControlCodes(c) || t.cur.attr.mode&attrGfx == 0 {
|
if t.handleControlCodes(c) || t.cur.Attr.Mode&attrGfx == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: update selection; see st.c:2450
|
// TODO: update selection; see st.c:2450
|
||||||
|
|
||||||
if t.mode&ModeWrap != 0 && t.cur.state&cursorWrapNext != 0 {
|
if t.mode&ModeWrap != 0 && t.cur.State&cursorWrapNext != 0 {
|
||||||
t.lines[t.cur.y][t.cur.x].mode |= attrWrap
|
t.lines[t.cur.Y][t.cur.X].Mode |= attrWrap
|
||||||
t.newline(true)
|
t.newline(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.mode&ModeInsert != 0 && t.cur.x+1 < t.cols {
|
if t.mode&ModeInsert != 0 && t.cur.X+1 < t.cols {
|
||||||
// TODO: move shiz, look at st.c:2458
|
// TODO: move shiz, look at st.c:2458
|
||||||
t.logln("insert mode not implemented")
|
t.logln("insert mode not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.setChar(c, &t.cur.attr, t.cur.x, t.cur.y)
|
t.setChar(c, &t.cur.Attr, t.cur.X, t.cur.Y)
|
||||||
if t.cur.x+1 < t.cols {
|
if t.cur.X+1 < t.cols {
|
||||||
t.moveTo(t.cur.x+1, t.cur.y)
|
t.moveTo(t.cur.X+1, t.cur.Y)
|
||||||
} else {
|
} else {
|
||||||
t.cur.state |= cursorWrapNext
|
t.cur.State |= cursorWrapNext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,20 +56,20 @@ func (t *State) parseEsc(c rune) {
|
|||||||
'*', // set tertiary charset G2 (ignored)
|
'*', // set tertiary charset G2 (ignored)
|
||||||
'+': // set quaternary charset G3 (ignored)
|
'+': // set quaternary charset G3 (ignored)
|
||||||
case 'D': // IND - linefeed
|
case 'D': // IND - linefeed
|
||||||
if t.cur.y == t.bottom {
|
if t.cur.Y == t.bottom {
|
||||||
t.scrollUp(t.top, 1)
|
t.scrollUp(t.top, 1)
|
||||||
} else {
|
} else {
|
||||||
t.moveTo(t.cur.x, t.cur.y+1)
|
t.moveTo(t.cur.X, t.cur.Y+1)
|
||||||
}
|
}
|
||||||
case 'E': // NEL - next line
|
case 'E': // NEL - next line
|
||||||
t.newline(true)
|
t.newline(true)
|
||||||
case 'H': // HTS - horizontal tab stop
|
case 'H': // HTS - horizontal tab stop
|
||||||
t.tabs[t.cur.x] = true
|
t.tabs[t.cur.X] = true
|
||||||
case 'M': // RI - reverse index
|
case 'M': // RI - reverse index
|
||||||
if t.cur.y == t.top {
|
if t.cur.Y == t.top {
|
||||||
t.scrollDown(t.top, 1)
|
t.scrollDown(t.top, 1)
|
||||||
} else {
|
} else {
|
||||||
t.moveTo(t.cur.x, t.cur.y-1)
|
t.moveTo(t.cur.X, t.cur.Y-1)
|
||||||
}
|
}
|
||||||
case 'Z': // DECID - identify terminal
|
case 'Z': // DECID - identify terminal
|
||||||
// TODO: write to our writer our id
|
// TODO: write to our writer our id
|
||||||
@@ -132,9 +132,9 @@ func (t *State) parseEscAltCharset(c rune) {
|
|||||||
t.logf("%q", string(c))
|
t.logf("%q", string(c))
|
||||||
switch c {
|
switch c {
|
||||||
case '0': // line drawing set
|
case '0': // line drawing set
|
||||||
t.cur.attr.mode |= attrGfx
|
t.cur.Attr.Mode |= attrGfx
|
||||||
case 'B': // USASCII
|
case 'B': // USASCII
|
||||||
t.cur.attr.mode &^= attrGfx
|
t.cur.Attr.Mode &^= attrGfx
|
||||||
case 'A', // UK (ignored)
|
case 'A', // UK (ignored)
|
||||||
'<', // multinational (ignored)
|
'<', // multinational (ignored)
|
||||||
'5', // Finnish (ignored)
|
'5', // Finnish (ignored)
|
||||||
@@ -154,7 +154,7 @@ func (t *State) parseEscTest(c rune) {
|
|||||||
if c == '8' {
|
if c == '8' {
|
||||||
for y := 0; y < t.rows; y++ {
|
for y := 0; y < t.rows; y++ {
|
||||||
for x := 0; x < t.cols; x++ {
|
for x := 0; x < t.cols; x++ {
|
||||||
t.setChar('E', &t.cur.attr, x, y)
|
t.setChar('E', &t.cur.Attr, x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,10 +171,10 @@ func (t *State) handleControlCodes(c rune) bool {
|
|||||||
t.putTab(true)
|
t.putTab(true)
|
||||||
// BS
|
// BS
|
||||||
case '\b':
|
case '\b':
|
||||||
t.moveTo(t.cur.x-1, t.cur.y)
|
t.moveTo(t.cur.X-1, t.cur.Y)
|
||||||
// CR
|
// CR
|
||||||
case '\r':
|
case '\r':
|
||||||
t.moveTo(0, t.cur.y)
|
t.moveTo(0, t.cur.Y)
|
||||||
// LF, VT, LF
|
// LF, VT, LF
|
||||||
case '\f', '\v', '\n':
|
case '\f', '\v', '\n':
|
||||||
// go to first col if mode is set
|
// go to first col if mode is set
|
||||||
|
|||||||
209
vendor/github.com/hinshun/vt10x/state.go
generated
vendored
209
vendor/github.com/hinshun/vt10x/state.go
generated
vendored
@@ -62,18 +62,18 @@ const (
|
|||||||
ChangedTitle
|
ChangedTitle
|
||||||
)
|
)
|
||||||
|
|
||||||
type glyph struct {
|
type Glyph struct {
|
||||||
c rune
|
Char rune
|
||||||
mode int16
|
Mode int16
|
||||||
fg, bg Color
|
FG, BG Color
|
||||||
}
|
}
|
||||||
|
|
||||||
type line []glyph
|
type line []Glyph
|
||||||
|
|
||||||
type cursor struct {
|
type Cursor struct {
|
||||||
attr glyph
|
Attr Glyph
|
||||||
x, y int
|
X, Y int
|
||||||
state uint8
|
State uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
type parseState func(c rune)
|
type parseState func(c rune)
|
||||||
@@ -91,7 +91,7 @@ type State struct {
|
|||||||
altLines []line
|
altLines []line
|
||||||
dirty []bool // line dirtiness
|
dirty []bool // line dirtiness
|
||||||
anydirty bool
|
anydirty bool
|
||||||
cur, curSaved cursor
|
cur, curSaved Cursor
|
||||||
top, bottom int // scroll limits
|
top, bottom int // scroll limits
|
||||||
mode ModeFlag
|
mode ModeFlag
|
||||||
state parseState
|
state parseState
|
||||||
@@ -100,6 +100,14 @@ type State struct {
|
|||||||
numlock bool
|
numlock bool
|
||||||
tabs []bool
|
tabs []bool
|
||||||
title string
|
title string
|
||||||
|
colorOverride map[Color]Color
|
||||||
|
}
|
||||||
|
|
||||||
|
func newState(w io.Writer) *State {
|
||||||
|
return &State{
|
||||||
|
w: w,
|
||||||
|
colorOverride: make(map[Color]Color),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) logf(format string, args ...interface{}) {
|
func (t *State) logf(format string, args ...interface{}) {
|
||||||
@@ -133,15 +141,24 @@ func (t *State) Unlock() {
|
|||||||
t.mu.Unlock()
|
t.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cell returns the character code, foreground color, and background
|
// Cell returns the glyph containing the character code, foreground color, and
|
||||||
// color at position (x, y) relative to the top left of the terminal.
|
// background color at position (x, y) relative to the top left of the terminal.
|
||||||
func (t *State) Cell(x, y int) (ch rune, fg Color, bg Color) {
|
func (t *State) Cell(x, y int) Glyph {
|
||||||
return t.lines[y][x].c, Color(t.lines[y][x].fg), Color(t.lines[y][x].bg)
|
cell := t.lines[y][x]
|
||||||
|
fg, ok := t.colorOverride[cell.FG]
|
||||||
|
if ok {
|
||||||
|
cell.FG = fg
|
||||||
|
}
|
||||||
|
bg, ok := t.colorOverride[cell.BG]
|
||||||
|
if ok {
|
||||||
|
cell.BG = bg
|
||||||
|
}
|
||||||
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor returns the current position of the cursor.
|
// Cursor returns the current position of the cursor.
|
||||||
func (t *State) Cursor() (int, int) {
|
func (t *State) Cursor() Cursor {
|
||||||
return t.cur.x, t.cur.y
|
return t.cur
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorVisible returns the visible state of the cursor.
|
// CursorVisible returns the visible state of the cursor.
|
||||||
@@ -149,9 +166,9 @@ func (t *State) CursorVisible() bool {
|
|||||||
return t.mode&ModeHide == 0
|
return t.mode&ModeHide == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode tests if mode is currently set.
|
// Mode returns the current terminal mode.
|
||||||
func (t *State) Mode(mode ModeFlag) bool {
|
func (t *State) Mode() ModeFlag {
|
||||||
return t.mode&mode != 0
|
return t.mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Title returns the current title set via the tty.
|
// Title returns the current title set via the tty.
|
||||||
@@ -186,7 +203,7 @@ func (t *State) saveCursor() {
|
|||||||
|
|
||||||
func (t *State) restoreCursor() {
|
func (t *State) restoreCursor() {
|
||||||
t.cur = t.curSaved
|
t.cur = t.curSaved
|
||||||
t.moveTo(t.cur.x, t.cur.y)
|
t.moveTo(t.cur.X, t.cur.Y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) put(c rune) {
|
func (t *State) put(c rune) {
|
||||||
@@ -194,7 +211,7 @@ func (t *State) put(c rune) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) putTab(forward bool) {
|
func (t *State) putTab(forward bool) {
|
||||||
x := t.cur.x
|
x := t.cur.X
|
||||||
if forward {
|
if forward {
|
||||||
if x == t.cols {
|
if x == t.cols {
|
||||||
return
|
return
|
||||||
@@ -208,11 +225,11 @@ func (t *State) putTab(forward bool) {
|
|||||||
for x--; x > 0 && !t.tabs[x]; x-- {
|
for x--; x > 0 && !t.tabs[x]; x-- {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.moveTo(x, t.cur.y)
|
t.moveTo(x, t.cur.Y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) newline(firstCol bool) {
|
func (t *State) newline(firstCol bool) {
|
||||||
y := t.cur.y
|
y := t.cur.Y
|
||||||
if y == t.bottom {
|
if y == t.bottom {
|
||||||
cur := t.cur
|
cur := t.cur
|
||||||
t.cur = t.defaultCursor()
|
t.cur = t.defaultCursor()
|
||||||
@@ -224,7 +241,7 @@ func (t *State) newline(firstCol bool) {
|
|||||||
if firstCol {
|
if firstCol {
|
||||||
t.moveTo(0, y)
|
t.moveTo(0, y)
|
||||||
} else {
|
} else {
|
||||||
t.moveTo(t.cur.x, y)
|
t.moveTo(t.cur.X, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,8 +257,8 @@ var gfxCharTable = [62]rune{
|
|||||||
'│', '≤', '≥', 'π', '≠', '£', '·', // x - ~
|
'│', '≤', '≥', 'π', '≠', '£', '·', // x - ~
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) setChar(c rune, attr *glyph, x, y int) {
|
func (t *State) setChar(c rune, attr *Glyph, x, y int) {
|
||||||
if attr.mode&attrGfx != 0 {
|
if attr.Mode&attrGfx != 0 {
|
||||||
if c >= 0x41 && c <= 0x7e && gfxCharTable[c-0x41] != 0 {
|
if c >= 0x41 && c <= 0x7e && gfxCharTable[c-0x41] != 0 {
|
||||||
c = gfxCharTable[c-0x41]
|
c = gfxCharTable[c-0x41]
|
||||||
}
|
}
|
||||||
@@ -249,21 +266,21 @@ func (t *State) setChar(c rune, attr *glyph, x, y int) {
|
|||||||
t.changed |= ChangedScreen
|
t.changed |= ChangedScreen
|
||||||
t.dirty[y] = true
|
t.dirty[y] = true
|
||||||
t.lines[y][x] = *attr
|
t.lines[y][x] = *attr
|
||||||
t.lines[y][x].c = c
|
t.lines[y][x].Char = c
|
||||||
//if t.options.BrightBold && attr.mode&attrBold != 0 && attr.fg < 8 {
|
//if t.options.BrightBold && attr.Mode&attrBold != 0 && attr.FG < 8 {
|
||||||
if attr.mode&attrBold != 0 && attr.fg < 8 {
|
if attr.Mode&attrBold != 0 && attr.FG < 8 {
|
||||||
t.lines[y][x].fg = attr.fg + 8
|
t.lines[y][x].FG = attr.FG + 8
|
||||||
}
|
}
|
||||||
if attr.mode&attrReverse != 0 {
|
if attr.Mode&attrReverse != 0 {
|
||||||
t.lines[y][x].fg = attr.bg
|
t.lines[y][x].FG = attr.BG
|
||||||
t.lines[y][x].bg = attr.fg
|
t.lines[y][x].BG = attr.FG
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) defaultCursor() cursor {
|
func (t *State) defaultCursor() Cursor {
|
||||||
c := cursor{}
|
c := Cursor{}
|
||||||
c.attr.fg = DefaultFG
|
c.Attr.FG = DefaultFG
|
||||||
c.attr.bg = DefaultBG
|
c.Attr.BG = DefaultBG
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,7 +308,7 @@ func (t *State) resize(cols, rows int) bool {
|
|||||||
if cols < 1 || rows < 1 {
|
if cols < 1 || rows < 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
slide := t.cur.y - rows + 1
|
slide := t.cur.Y - rows + 1
|
||||||
if slide > 0 {
|
if slide > 0 {
|
||||||
copy(t.lines, t.lines[slide:slide+rows])
|
copy(t.lines, t.lines[slide:slide+rows])
|
||||||
copy(t.altLines, t.altLines[slide:slide+rows])
|
copy(t.altLines, t.altLines[slide:slide+rows])
|
||||||
@@ -329,7 +346,7 @@ func (t *State) resize(cols, rows int) bool {
|
|||||||
t.cols = cols
|
t.cols = cols
|
||||||
t.rows = rows
|
t.rows = rows
|
||||||
t.setScroll(0, rows-1)
|
t.setScroll(0, rows-1)
|
||||||
t.moveTo(t.cur.x, t.cur.y)
|
t.moveTo(t.cur.X, t.cur.Y)
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
if mincols < cols && minrows > 0 {
|
if mincols < cols && minrows > 0 {
|
||||||
t.clear(mincols, 0, cols-1, minrows-1)
|
t.clear(mincols, 0, cols-1, minrows-1)
|
||||||
@@ -357,8 +374,8 @@ func (t *State) clear(x0, y0, x1, y1 int) {
|
|||||||
for y := y0; y <= y1; y++ {
|
for y := y0; y <= y1; y++ {
|
||||||
t.dirty[y] = true
|
t.dirty[y] = true
|
||||||
for x := x0; x <= x1; x++ {
|
for x := x0; x <= x1; x++ {
|
||||||
t.lines[y][x] = t.cur.attr
|
t.lines[y][x] = t.cur.Attr
|
||||||
t.lines[y][x].c = ' '
|
t.lines[y][x].Char = ' '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,7 +385,7 @@ func (t *State) clearAll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) moveAbsTo(x, y int) {
|
func (t *State) moveAbsTo(x, y int) {
|
||||||
if t.cur.state&cursorOrigin != 0 {
|
if t.cur.State&cursorOrigin != 0 {
|
||||||
y += t.top
|
y += t.top
|
||||||
}
|
}
|
||||||
t.moveTo(x, y)
|
t.moveTo(x, y)
|
||||||
@@ -376,7 +393,7 @@ func (t *State) moveAbsTo(x, y int) {
|
|||||||
|
|
||||||
func (t *State) moveTo(x, y int) {
|
func (t *State) moveTo(x, y int) {
|
||||||
var miny, maxy int
|
var miny, maxy int
|
||||||
if t.cur.state&cursorOrigin != 0 {
|
if t.cur.State&cursorOrigin != 0 {
|
||||||
miny = t.top
|
miny = t.top
|
||||||
maxy = t.bottom
|
maxy = t.bottom
|
||||||
} else {
|
} else {
|
||||||
@@ -386,9 +403,9 @@ func (t *State) moveTo(x, y int) {
|
|||||||
x = clamp(x, 0, t.cols-1)
|
x = clamp(x, 0, t.cols-1)
|
||||||
y = clamp(y, miny, maxy)
|
y = clamp(y, miny, maxy)
|
||||||
t.changed |= ChangedScreen
|
t.changed |= ChangedScreen
|
||||||
t.cur.state &^= cursorWrapNext
|
t.cur.State &^= cursorWrapNext
|
||||||
t.cur.x = x
|
t.cur.X = x
|
||||||
t.cur.y = y
|
t.cur.Y = y
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) swapScreen() {
|
func (t *State) swapScreen() {
|
||||||
@@ -492,9 +509,9 @@ func (t *State) setMode(priv bool, set bool, args []int) {
|
|||||||
}
|
}
|
||||||
case 6: // DECOM - origin
|
case 6: // DECOM - origin
|
||||||
if set {
|
if set {
|
||||||
t.cur.state |= cursorOrigin
|
t.cur.State |= cursorOrigin
|
||||||
} else {
|
} else {
|
||||||
t.cur.state &^= cursorOrigin
|
t.cur.State &^= cursorOrigin
|
||||||
}
|
}
|
||||||
t.moveAbsTo(0, 0)
|
t.moveAbsTo(0, 0)
|
||||||
case 7: // DECAWM - auto wrap
|
case 7: // DECAWM - auto wrap
|
||||||
@@ -594,64 +611,80 @@ func (t *State) setAttr(attr []int) {
|
|||||||
a := attr[i]
|
a := attr[i]
|
||||||
switch a {
|
switch a {
|
||||||
case 0:
|
case 0:
|
||||||
t.cur.attr.mode &^= attrReverse | attrUnderline | attrBold | attrItalic | attrBlink
|
t.cur.Attr.Mode &^= attrReverse | attrUnderline | attrBold | attrItalic | attrBlink
|
||||||
t.cur.attr.fg = DefaultFG
|
t.cur.Attr.FG = DefaultFG
|
||||||
t.cur.attr.bg = DefaultBG
|
t.cur.Attr.BG = DefaultBG
|
||||||
case 1:
|
case 1:
|
||||||
t.cur.attr.mode |= attrBold
|
t.cur.Attr.Mode |= attrBold
|
||||||
case 3:
|
case 3:
|
||||||
t.cur.attr.mode |= attrItalic
|
t.cur.Attr.Mode |= attrItalic
|
||||||
case 4:
|
case 4:
|
||||||
t.cur.attr.mode |= attrUnderline
|
t.cur.Attr.Mode |= attrUnderline
|
||||||
case 5, 6: // slow, rapid blink
|
case 5, 6: // slow, rapid blink
|
||||||
t.cur.attr.mode |= attrBlink
|
t.cur.Attr.Mode |= attrBlink
|
||||||
case 7:
|
case 7:
|
||||||
t.cur.attr.mode |= attrReverse
|
t.cur.Attr.Mode |= attrReverse
|
||||||
case 21, 22:
|
case 21, 22:
|
||||||
t.cur.attr.mode &^= attrBold
|
t.cur.Attr.Mode &^= attrBold
|
||||||
case 23:
|
case 23:
|
||||||
t.cur.attr.mode &^= attrItalic
|
t.cur.Attr.Mode &^= attrItalic
|
||||||
case 24:
|
case 24:
|
||||||
t.cur.attr.mode &^= attrUnderline
|
t.cur.Attr.Mode &^= attrUnderline
|
||||||
case 25, 26:
|
case 25, 26:
|
||||||
t.cur.attr.mode &^= attrBlink
|
t.cur.Attr.Mode &^= attrBlink
|
||||||
case 27:
|
case 27:
|
||||||
t.cur.attr.mode &^= attrReverse
|
t.cur.Attr.Mode &^= attrReverse
|
||||||
case 38:
|
case 38:
|
||||||
if i+2 < len(attr) && attr[i+1] == 5 {
|
if i+2 < len(attr) && attr[i+1] == 5 {
|
||||||
i += 2
|
i += 2
|
||||||
if between(attr[i], 0, 255) {
|
if between(attr[i], 0, 255) {
|
||||||
t.cur.attr.fg = Color(attr[i])
|
t.cur.Attr.FG = Color(attr[i])
|
||||||
} else {
|
} else {
|
||||||
t.logf("bad fgcolor %d\n", attr[i])
|
t.logf("bad fgcolor %d\n", attr[i])
|
||||||
}
|
}
|
||||||
|
} else if i+4 < len(attr) && attr[i+1] == 2 {
|
||||||
|
i += 4
|
||||||
|
r, g, b := attr[i-2], attr[i-1], attr[i]
|
||||||
|
if !between(r, 0, 255) || !between(g, 0, 255) || !between(b, 0, 255) {
|
||||||
|
t.logf("bad fg rgb color (%d,%d,%d)\n", r, g, b)
|
||||||
|
} else {
|
||||||
|
t.cur.Attr.FG = Color(r<<16 | g<<8 | b)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t.logf("gfx attr %d unknown\n", a)
|
t.logf("gfx attr %d unknown\n", a)
|
||||||
}
|
}
|
||||||
case 39:
|
case 39:
|
||||||
t.cur.attr.fg = DefaultFG
|
t.cur.Attr.FG = DefaultFG
|
||||||
case 48:
|
case 48:
|
||||||
if i+2 < len(attr) && attr[i+1] == 5 {
|
if i+2 < len(attr) && attr[i+1] == 5 {
|
||||||
i += 2
|
i += 2
|
||||||
if between(attr[i], 0, 255) {
|
if between(attr[i], 0, 255) {
|
||||||
t.cur.attr.bg = Color(attr[i])
|
t.cur.Attr.BG = Color(attr[i])
|
||||||
} else {
|
} else {
|
||||||
t.logf("bad bgcolor %d\n", attr[i])
|
t.logf("bad bgcolor %d\n", attr[i])
|
||||||
}
|
}
|
||||||
|
} else if i+4 < len(attr) && attr[i+1] == 2 {
|
||||||
|
i += 4
|
||||||
|
r, g, b := attr[i-2], attr[i-1], attr[i]
|
||||||
|
if !between(r, 0, 255) || !between(g, 0, 255) || !between(b, 0, 255) {
|
||||||
|
t.logf("bad bg rgb color (%d,%d,%d)\n", r, g, b)
|
||||||
|
} else {
|
||||||
|
t.cur.Attr.BG = Color(r<<16 | g<<8 | b)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t.logf("gfx attr %d unknown\n", a)
|
t.logf("gfx attr %d unknown\n", a)
|
||||||
}
|
}
|
||||||
case 49:
|
case 49:
|
||||||
t.cur.attr.bg = DefaultBG
|
t.cur.Attr.BG = DefaultBG
|
||||||
default:
|
default:
|
||||||
if between(a, 30, 37) {
|
if between(a, 30, 37) {
|
||||||
t.cur.attr.fg = Color(a - 30)
|
t.cur.Attr.FG = Color(a - 30)
|
||||||
} else if between(a, 40, 47) {
|
} else if between(a, 40, 47) {
|
||||||
t.cur.attr.bg = Color(a - 40)
|
t.cur.Attr.BG = Color(a - 40)
|
||||||
} else if between(a, 90, 97) {
|
} else if between(a, 90, 97) {
|
||||||
t.cur.attr.fg = Color(a - 90 + 8)
|
t.cur.Attr.FG = Color(a - 90 + 8)
|
||||||
} else if between(a, 100, 107) {
|
} else if between(a, 100, 107) {
|
||||||
t.cur.attr.bg = Color(a - 100 + 8)
|
t.cur.Attr.BG = Color(a - 100 + 8)
|
||||||
} else {
|
} else {
|
||||||
t.logf("gfx attr %d unknown\n", a)
|
t.logf("gfx attr %d unknown\n", a)
|
||||||
}
|
}
|
||||||
@@ -660,46 +693,46 @@ func (t *State) setAttr(attr []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) insertBlanks(n int) {
|
func (t *State) insertBlanks(n int) {
|
||||||
src := t.cur.x
|
src := t.cur.X
|
||||||
dst := src + n
|
dst := src + n
|
||||||
size := t.cols - dst
|
size := t.cols - dst
|
||||||
t.changed |= ChangedScreen
|
t.changed |= ChangedScreen
|
||||||
t.dirty[t.cur.y] = true
|
t.dirty[t.cur.Y] = true
|
||||||
|
|
||||||
if dst >= t.cols {
|
if dst >= t.cols {
|
||||||
t.clear(t.cur.x, t.cur.y, t.cols-1, t.cur.y)
|
t.clear(t.cur.X, t.cur.Y, t.cols-1, t.cur.Y)
|
||||||
} else {
|
} else {
|
||||||
copy(t.lines[t.cur.y][dst:dst+size], t.lines[t.cur.y][src:src+size])
|
copy(t.lines[t.cur.Y][dst:dst+size], t.lines[t.cur.Y][src:src+size])
|
||||||
t.clear(src, t.cur.y, dst-1, t.cur.y)
|
t.clear(src, t.cur.Y, dst-1, t.cur.Y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) insertBlankLines(n int) {
|
func (t *State) insertBlankLines(n int) {
|
||||||
if t.cur.y < t.top || t.cur.y > t.bottom {
|
if t.cur.Y < t.top || t.cur.Y > t.bottom {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.scrollDown(t.cur.y, n)
|
t.scrollDown(t.cur.Y, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) deleteLines(n int) {
|
func (t *State) deleteLines(n int) {
|
||||||
if t.cur.y < t.top || t.cur.y > t.bottom {
|
if t.cur.Y < t.top || t.cur.Y > t.bottom {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.scrollUp(t.cur.y, n)
|
t.scrollUp(t.cur.Y, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) deleteChars(n int) {
|
func (t *State) deleteChars(n int) {
|
||||||
src := t.cur.x + n
|
src := t.cur.X + n
|
||||||
dst := t.cur.x
|
dst := t.cur.X
|
||||||
size := t.cols - src
|
size := t.cols - src
|
||||||
t.changed |= ChangedScreen
|
t.changed |= ChangedScreen
|
||||||
t.dirty[t.cur.y] = true
|
t.dirty[t.cur.Y] = true
|
||||||
|
|
||||||
if src >= t.cols {
|
if src >= t.cols {
|
||||||
t.clear(t.cur.x, t.cur.y, t.cols-1, t.cur.y)
|
t.clear(t.cur.X, t.cur.Y, t.cols-1, t.cur.Y)
|
||||||
} else {
|
} else {
|
||||||
copy(t.lines[t.cur.y][dst:dst+size], t.lines[t.cur.y][src:src+size])
|
copy(t.lines[t.cur.Y][dst:dst+size], t.lines[t.cur.Y][src:src+size])
|
||||||
t.clear(t.cols-n, t.cur.y, t.cols-1, t.cur.y)
|
t.clear(t.cols-n, t.cur.Y, t.cols-1, t.cur.Y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,8 +741,8 @@ func (t *State) setTitle(title string) {
|
|||||||
t.title = title
|
t.title = title
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) Size() (rows int, cols int) {
|
func (t *State) Size() (cols, rows int) {
|
||||||
return t.rows, t.cols
|
return t.cols, t.rows
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *State) String() string {
|
func (t *State) String() string {
|
||||||
@@ -719,8 +752,8 @@ func (t *State) String() string {
|
|||||||
var view []rune
|
var view []rune
|
||||||
for y := 0; y < t.rows; y++ {
|
for y := 0; y < t.rows; y++ {
|
||||||
for x := 0; x < t.cols; x++ {
|
for x := 0; x < t.cols; x++ {
|
||||||
c, _, _ := t.Cell(x, y)
|
attr := t.Cell(x, y)
|
||||||
view = append(view, c)
|
view = append(view, attr.Char)
|
||||||
}
|
}
|
||||||
view = append(view, '\n')
|
view = append(view, '\n')
|
||||||
}
|
}
|
||||||
|
|||||||
242
vendor/github.com/hinshun/vt10x/str.go
generated
vendored
242
vendor/github.com/hinshun/vt10x/str.go
generated
vendored
@@ -1,6 +1,9 @@
|
|||||||
package vt10x
|
package vt10x
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -59,20 +62,77 @@ func (t *State) handleSTR() {
|
|||||||
|
|
||||||
switch s.typ {
|
switch s.typ {
|
||||||
case ']': // OSC - operating system command
|
case ']': // OSC - operating system command
|
||||||
|
var p *string
|
||||||
switch d := s.arg(0, 0); d {
|
switch d := s.arg(0, 0); d {
|
||||||
case 0, 1, 2:
|
case 0, 1, 2:
|
||||||
title := s.argString(1, "")
|
title := s.argString(1, "")
|
||||||
if title != "" {
|
if title != "" {
|
||||||
t.setTitle(title)
|
t.setTitle(title)
|
||||||
}
|
}
|
||||||
|
case 10:
|
||||||
|
if len(s.args) < 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
c := s.argString(1, "")
|
||||||
|
p := &c
|
||||||
|
if p != nil && *p == "?" {
|
||||||
|
t.oscColorResponse(int(DefaultFG), 10)
|
||||||
|
} else if err := t.setColorName(int(DefaultFG), p); err != nil {
|
||||||
|
t.logf("invalid foreground color: %s\n", maybe(p))
|
||||||
|
} else {
|
||||||
|
// TODO: redraw
|
||||||
|
}
|
||||||
|
case 11:
|
||||||
|
if len(s.args) < 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
c := s.argString(1, "")
|
||||||
|
p := &c
|
||||||
|
if p != nil && *p == "?" {
|
||||||
|
t.oscColorResponse(int(DefaultBG), 11)
|
||||||
|
} else if err := t.setColorName(int(DefaultBG), p); err != nil {
|
||||||
|
t.logf("invalid cursor color: %s\n", maybe(p))
|
||||||
|
} else {
|
||||||
|
// TODO: redraw
|
||||||
|
}
|
||||||
|
// case 12:
|
||||||
|
// if len(s.args) < 2 {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
|
||||||
|
// c := s.argString(1, "")
|
||||||
|
// p := &c
|
||||||
|
// if p != nil && *p == "?" {
|
||||||
|
// t.oscColorResponse(int(DefaultCursor), 12)
|
||||||
|
// } else if err := t.setColorName(int(DefaultCursor), p); err != nil {
|
||||||
|
// t.logf("invalid background color: %s\n", p)
|
||||||
|
// } else {
|
||||||
|
// // TODO: redraw
|
||||||
|
// }
|
||||||
case 4: // color set
|
case 4: // color set
|
||||||
if len(s.args) < 3 {
|
if len(s.args) < 3 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// setcolorname(s.arg(1, 0), s.argString(2, ""))
|
|
||||||
|
c := s.argString(2, "")
|
||||||
|
p = &c
|
||||||
|
fallthrough
|
||||||
case 104: // color reset
|
case 104: // color reset
|
||||||
// TODO: complain about invalid color, redraw, etc.
|
j := -1
|
||||||
// setcolorname(s.arg(1, 0), nil)
|
if len(s.args) > 1 {
|
||||||
|
j = s.arg(1, 0)
|
||||||
|
}
|
||||||
|
if p != nil && *p == "?" { // report
|
||||||
|
t.osc4ColorResponse(j)
|
||||||
|
} else if err := t.setColorName(j, p); err != nil {
|
||||||
|
if !(d == 104 && len(s.args) <= 1) {
|
||||||
|
t.logf("invalid color j=%d, p=%s\n", j, maybe(p))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: redraw
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
t.logf("unknown OSC command %d\n", d)
|
t.logf("unknown OSC command %d\n", d)
|
||||||
// TODO: s.dump()
|
// TODO: s.dump()
|
||||||
@@ -92,3 +152,179 @@ func (t *State) handleSTR() {
|
|||||||
// t.str.dump()
|
// t.str.dump()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *State) setColorName(j int, p *string) error {
|
||||||
|
if !between(j, 0, 1<<24) {
|
||||||
|
return fmt.Errorf("invalid color value %d", j)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p == nil {
|
||||||
|
// restore color
|
||||||
|
delete(t.colorOverride, Color(j))
|
||||||
|
} else {
|
||||||
|
// set color
|
||||||
|
r, g, b, err := parseColor(*p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.colorOverride[Color(j)] = Color(r<<16 | g<<8 | b)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *State) oscColorResponse(j, num int) {
|
||||||
|
if j < 0 {
|
||||||
|
t.logf("failed to fetch osc color %d\n", j)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
k, ok := t.colorOverride[Color(j)]
|
||||||
|
if ok {
|
||||||
|
j = int(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, g, b := rgb(j)
|
||||||
|
t.w.Write([]byte(fmt.Sprintf("\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", num, r, r, g, g, b, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *State) osc4ColorResponse(j int) {
|
||||||
|
if j < 0 {
|
||||||
|
t.logf("failed to fetch osc4 color %d\n", j)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
k, ok := t.colorOverride[Color(j)]
|
||||||
|
if ok {
|
||||||
|
j = int(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, g, b := rgb(j)
|
||||||
|
t.w.Write([]byte(fmt.Sprintf("\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", j, r, r, g, g, b, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func rgb(j int) (r, g, b int) {
|
||||||
|
return (j >> 16) & 0xff, (j >> 8) & 0xff, j & 0xff
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
RGBPattern = regexp.MustCompile(`^([\da-f]{1})\/([\da-f]{1})\/([\da-f]{1})$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$`)
|
||||||
|
HashPattern = regexp.MustCompile(`[\da-f]`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseColor(p string) (r, g, b int, err error) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
err = fmt.Errorf("empty color spec")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
low := strings.ToLower(p)
|
||||||
|
if strings.HasPrefix(low, "rgb:") {
|
||||||
|
low = low[4:]
|
||||||
|
sm := RGBPattern.FindAllStringSubmatch(low, -1)
|
||||||
|
if len(sm) != 1 || len(sm[0]) == 0 {
|
||||||
|
err = fmt.Errorf("invalid rgb color spec: %s", p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m := sm[0]
|
||||||
|
|
||||||
|
var base float64
|
||||||
|
if len(m[1]) > 0 {
|
||||||
|
base = 15
|
||||||
|
} else if len(m[4]) > 0 {
|
||||||
|
base = 255
|
||||||
|
} else if len(m[7]) > 0 {
|
||||||
|
base = 4095
|
||||||
|
} else {
|
||||||
|
base = 65535
|
||||||
|
}
|
||||||
|
|
||||||
|
r64, err := strconv.ParseInt(firstNonEmpty(m[1], m[4], m[7], m[10]), 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
return r, g, b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g64, err := strconv.ParseInt(firstNonEmpty(m[2], m[5], m[8], m[11]), 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
return r, g, b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b64, err := strconv.ParseInt(firstNonEmpty(m[3], m[6], m[9], m[12]), 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
return r, g, b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r = int(math.Round(float64(r64) / base * 255))
|
||||||
|
g = int(math.Round(float64(g64) / base * 255))
|
||||||
|
b = int(math.Round(float64(b64) / base * 255))
|
||||||
|
return r, g, b, nil
|
||||||
|
} else if strings.HasPrefix(low, "#") {
|
||||||
|
low = low[1:]
|
||||||
|
m := HashPattern.FindAllString(low, -1)
|
||||||
|
if !oneOf(len(m), []int{3, 6, 9, 12}) {
|
||||||
|
err = fmt.Errorf("invalid hash color spec: %s", p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adv := len(low) / 3
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
c, err := strconv.ParseInt(low[adv*i:adv*i+adv], 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
return r, g, b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var v int64
|
||||||
|
switch adv {
|
||||||
|
case 1:
|
||||||
|
v = c << 4
|
||||||
|
case 2:
|
||||||
|
v = c
|
||||||
|
case 3:
|
||||||
|
v = c >> 4
|
||||||
|
default:
|
||||||
|
v = c >> 8
|
||||||
|
}
|
||||||
|
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
r = int(v)
|
||||||
|
case 1:
|
||||||
|
g = int(v)
|
||||||
|
case 2:
|
||||||
|
b = int(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("invalid color spec: %s", p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func maybe(p *string) string {
|
||||||
|
if p == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstNonEmpty(strs ...string) string {
|
||||||
|
if len(strs) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for _, str := range strs {
|
||||||
|
if len(str) > 0 {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strs[len(strs)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func oneOf(v int, is []int) bool {
|
||||||
|
for _, i := range is {
|
||||||
|
if v == i {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
89
vendor/github.com/hinshun/vt10x/vt.go
generated
vendored
Normal file
89
vendor/github.com/hinshun/vt10x/vt.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package vt10x
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Terminal represents the virtual terminal emulator.
|
||||||
|
type Terminal interface {
|
||||||
|
// View displays the virtual terminal.
|
||||||
|
View
|
||||||
|
|
||||||
|
// Write parses input and writes terminal changes to state.
|
||||||
|
io.Writer
|
||||||
|
|
||||||
|
// Parse blocks on read on pty or io.Reader, then parses sequences until
|
||||||
|
// buffer empties. State is locked as soon as first rune is read, and unlocked
|
||||||
|
// when buffer is empty.
|
||||||
|
Parse(bf *bufio.Reader) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// View represents the view of the virtual terminal emulator.
|
||||||
|
type View interface {
|
||||||
|
// String dumps the virtual terminal contents.
|
||||||
|
fmt.Stringer
|
||||||
|
|
||||||
|
// Size returns the size of the virtual terminal.
|
||||||
|
Size() (cols, rows int)
|
||||||
|
|
||||||
|
// Resize changes the size of the virtual terminal.
|
||||||
|
Resize(cols, rows int)
|
||||||
|
|
||||||
|
// Mode returns the current terminal mode.//
|
||||||
|
Mode() ModeFlag
|
||||||
|
|
||||||
|
// Title represents the title of the console window.
|
||||||
|
Title() string
|
||||||
|
|
||||||
|
// Cell returns the glyph containing the character code, foreground color, and
|
||||||
|
// background color at position (x, y) relative to the top left of the terminal.
|
||||||
|
Cell(x, y int) Glyph
|
||||||
|
|
||||||
|
// Cursor returns the current position of the cursor.
|
||||||
|
Cursor() Cursor
|
||||||
|
|
||||||
|
// CursorVisible returns the visible state of the cursor.
|
||||||
|
CursorVisible() bool
|
||||||
|
|
||||||
|
// Lock locks the state object's mutex.
|
||||||
|
Lock()
|
||||||
|
|
||||||
|
// Unlock resets change flags and unlocks the state object's mutex.
|
||||||
|
Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
type TerminalOption func(*TerminalInfo)
|
||||||
|
|
||||||
|
type TerminalInfo struct {
|
||||||
|
w io.Writer
|
||||||
|
cols, rows int
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithWriter(w io.Writer) TerminalOption {
|
||||||
|
return func(info *TerminalInfo) {
|
||||||
|
info.w = w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSize(cols, rows int) TerminalOption {
|
||||||
|
return func(info *TerminalInfo) {
|
||||||
|
info.cols = cols
|
||||||
|
info.rows = rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new virtual terminal emulator.
|
||||||
|
func New(opts ...TerminalOption) Terminal {
|
||||||
|
info := TerminalInfo{
|
||||||
|
w: ioutil.Discard,
|
||||||
|
cols: 80,
|
||||||
|
rows: 24,
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&info)
|
||||||
|
}
|
||||||
|
return newTerminal(info)
|
||||||
|
}
|
||||||
82
vendor/github.com/hinshun/vt10x/vt_other.go
generated
vendored
82
vendor/github.com/hinshun/vt10x/vt_other.go
generated
vendored
@@ -6,47 +6,34 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VT represents the virtual terminal emulator.
|
type terminal struct {
|
||||||
type VT struct {
|
*State
|
||||||
dest *State
|
|
||||||
rwc io.ReadWriteCloser
|
|
||||||
br *bufio.Reader
|
|
||||||
pty *os.File
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create initializes a virtual terminal emulator with the target state
|
func newTerminal(info TerminalInfo) *terminal {
|
||||||
// and io.ReadWriteCloser input.
|
t := &terminal{newState(info.w)}
|
||||||
func Create(state *State, rwc io.ReadWriteCloser) (*VT, error) {
|
t.init(info.cols, info.rows)
|
||||||
t := &VT{
|
return t
|
||||||
dest: state,
|
|
||||||
rwc: rwc,
|
|
||||||
}
|
|
||||||
t.init()
|
|
||||||
return t, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *VT) init() {
|
func (t *terminal) init(cols, rows int) {
|
||||||
t.br = bufio.NewReader(t.rwc)
|
t.numlock = true
|
||||||
t.dest.w = t.rwc
|
t.state = t.parse
|
||||||
t.dest.numlock = true
|
t.cur.attr.fg = DefaultFG
|
||||||
t.dest.state = t.dest.parse
|
t.cur.attr.bg = DefaultBG
|
||||||
t.dest.cur.attr.fg = DefaultFG
|
t.Resize(cols, rows)
|
||||||
t.dest.cur.attr.bg = DefaultBG
|
t.reset()
|
||||||
t.Resize(80, 24)
|
|
||||||
t.dest.reset()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write parses input and writes terminal changes to state.
|
func (t *terminal) Write(p []byte) (int, error) {
|
||||||
func (t *VT) Write(p []byte) (int, error) {
|
|
||||||
var written int
|
var written int
|
||||||
r := bytes.NewReader(p)
|
r := bytes.NewReader(p)
|
||||||
t.dest.lock()
|
t.lock()
|
||||||
defer t.dest.unlock()
|
defer t.unlock()
|
||||||
for {
|
for {
|
||||||
c, sz, err := r.ReadRune()
|
c, sz, err := r.ReadRune()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -61,51 +48,43 @@ func (t *VT) Write(p []byte) (int, error) {
|
|||||||
// not enough bytes for a full rune
|
// not enough bytes for a full rune
|
||||||
return written - 1, nil
|
return written - 1, nil
|
||||||
}
|
}
|
||||||
t.dest.logln("invalid utf8 sequence")
|
t.logln("invalid utf8 sequence")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.dest.put(c)
|
t.put(c)
|
||||||
}
|
}
|
||||||
return written, nil
|
return written, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the io.ReadWriteCloser.
|
|
||||||
func (t *VT) Close() error {
|
|
||||||
return t.rwc.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse blocks on read on io.ReadWriteCloser, then parses sequences until
|
|
||||||
// buffer empties. State is locked as soon as first rune is read, and unlocked
|
|
||||||
// when buffer is empty.
|
|
||||||
// TODO: add tests for expected blocking behavior
|
// TODO: add tests for expected blocking behavior
|
||||||
func (t *VT) Parse() error {
|
func (t *terminal) Parse(br *bufio.Reader) error {
|
||||||
var locked bool
|
var locked bool
|
||||||
defer func() {
|
defer func() {
|
||||||
if locked {
|
if locked {
|
||||||
t.dest.unlock()
|
t.unlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
c, sz, err := t.br.ReadRune()
|
c, sz, err := br.ReadRune()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if c == unicode.ReplacementChar && sz == 1 {
|
if c == unicode.ReplacementChar && sz == 1 {
|
||||||
t.dest.logln("invalid utf8 sequence")
|
t.logln("invalid utf8 sequence")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !locked {
|
if !locked {
|
||||||
t.dest.lock()
|
t.lock()
|
||||||
locked = true
|
locked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// put rune for parsing and update state
|
// put rune for parsing and update state
|
||||||
t.dest.put(c)
|
t.put(c)
|
||||||
|
|
||||||
// break if our buffer is empty, or if buffer contains an
|
// break if our buffer is empty, or if buffer contains an
|
||||||
// incomplete rune.
|
// incomplete rune.
|
||||||
n := t.br.Buffered()
|
n := br.Buffered()
|
||||||
if n == 0 || (n < 4 && !fullRuneBuffered(t.br)) {
|
if n == 0 || (n < 4 && !fullRuneBuffered(br)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,9 +100,8 @@ func fullRuneBuffered(br *bufio.Reader) bool {
|
|||||||
return utf8.FullRune(buf)
|
return utf8.FullRune(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize reports new size to pty and updates state.
|
func (t *terminal) Resize(cols, rows int) {
|
||||||
func (t *VT) Resize(cols, rows int) {
|
t.lock()
|
||||||
t.dest.lock()
|
defer t.unlock()
|
||||||
defer t.dest.unlock()
|
_ = t.resize(cols, rows)
|
||||||
_ = t.dest.resize(cols, rows)
|
|
||||||
}
|
}
|
||||||
|
|||||||
79
vendor/github.com/hinshun/vt10x/vt_posix.go
generated
vendored
79
vendor/github.com/hinshun/vt10x/vt_posix.go
generated
vendored
@@ -10,41 +10,31 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VT represents the virtual terminal emulator.
|
type terminal struct {
|
||||||
type VT struct {
|
*State
|
||||||
dest *State
|
|
||||||
rwc io.ReadWriteCloser
|
|
||||||
br *bufio.Reader
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create initializes a virtual terminal emulator with the target state
|
func newTerminal(info TerminalInfo) *terminal {
|
||||||
// and io.ReadWriteCloser input.
|
t := &terminal{newState(info.w)}
|
||||||
func Create(state *State, rwc io.ReadWriteCloser) (*VT, error) {
|
t.init(info.cols, info.rows)
|
||||||
t := &VT{
|
return t
|
||||||
dest: state,
|
|
||||||
rwc: rwc,
|
|
||||||
}
|
|
||||||
t.init()
|
|
||||||
return t, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *VT) init() {
|
func (t *terminal) init(cols, rows int) {
|
||||||
t.br = bufio.NewReader(t.rwc)
|
t.numlock = true
|
||||||
t.dest.w = t.rwc
|
t.state = t.parse
|
||||||
t.dest.numlock = true
|
t.cur.Attr.FG = DefaultFG
|
||||||
t.dest.state = t.dest.parse
|
t.cur.Attr.BG = DefaultBG
|
||||||
t.dest.cur.attr.fg = DefaultFG
|
t.Resize(cols, rows)
|
||||||
t.dest.cur.attr.bg = DefaultBG
|
t.reset()
|
||||||
t.Resize(80, 24)
|
|
||||||
t.dest.reset()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write parses input and writes terminal changes to state.
|
// Write parses input and writes terminal changes to state.
|
||||||
func (t *VT) Write(p []byte) (int, error) {
|
func (t *terminal) Write(p []byte) (int, error) {
|
||||||
var written int
|
var written int
|
||||||
r := bytes.NewReader(p)
|
r := bytes.NewReader(p)
|
||||||
t.dest.lock()
|
t.lock()
|
||||||
defer t.dest.unlock()
|
defer t.unlock()
|
||||||
for {
|
for {
|
||||||
c, sz, err := r.ReadRune()
|
c, sz, err := r.ReadRune()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -59,51 +49,43 @@ func (t *VT) Write(p []byte) (int, error) {
|
|||||||
// not enough bytes for a full rune
|
// not enough bytes for a full rune
|
||||||
return written - 1, nil
|
return written - 1, nil
|
||||||
}
|
}
|
||||||
t.dest.logln("invalid utf8 sequence")
|
t.logln("invalid utf8 sequence")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.dest.put(c)
|
t.put(c)
|
||||||
}
|
}
|
||||||
return written, nil
|
return written, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the io.ReadWriteCloser.
|
|
||||||
func (t *VT) Close() error {
|
|
||||||
return t.rwc.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse blocks on read on pty or io.ReadCloser, then parses sequences until
|
|
||||||
// buffer empties. State is locked as soon as first rune is read, and unlocked
|
|
||||||
// when buffer is empty.
|
|
||||||
// TODO: add tests for expected blocking behavior
|
// TODO: add tests for expected blocking behavior
|
||||||
func (t *VT) Parse() error {
|
func (t *terminal) Parse(br *bufio.Reader) error {
|
||||||
var locked bool
|
var locked bool
|
||||||
defer func() {
|
defer func() {
|
||||||
if locked {
|
if locked {
|
||||||
t.dest.unlock()
|
t.unlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
c, sz, err := t.br.ReadRune()
|
c, sz, err := br.ReadRune()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if c == unicode.ReplacementChar && sz == 1 {
|
if c == unicode.ReplacementChar && sz == 1 {
|
||||||
t.dest.logln("invalid utf8 sequence")
|
t.logln("invalid utf8 sequence")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !locked {
|
if !locked {
|
||||||
t.dest.lock()
|
t.lock()
|
||||||
locked = true
|
locked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// put rune for parsing and update state
|
// put rune for parsing and update state
|
||||||
t.dest.put(c)
|
t.put(c)
|
||||||
|
|
||||||
// break if our buffer is empty, or if buffer contains an
|
// break if our buffer is empty, or if buffer contains an
|
||||||
// incomplete rune.
|
// incomplete rune.
|
||||||
n := t.br.Buffered()
|
n := br.Buffered()
|
||||||
if n == 0 || (n < 4 && !fullRuneBuffered(t.br)) {
|
if n == 0 || (n < 4 && !fullRuneBuffered(br)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,9 +101,8 @@ func fullRuneBuffered(br *bufio.Reader) bool {
|
|||||||
return utf8.FullRune(buf)
|
return utf8.FullRune(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize reports new size to pty and updates state.
|
func (t *terminal) Resize(cols, rows int) {
|
||||||
func (t *VT) Resize(cols, rows int) {
|
t.lock()
|
||||||
t.dest.lock()
|
defer t.unlock()
|
||||||
defer t.dest.unlock()
|
_ = t.resize(cols, rows)
|
||||||
_ = t.dest.resize(cols, rows)
|
|
||||||
}
|
}
|
||||||
|
|||||||
28
vendor/github.com/stretchr/testify/require/doc.go
generated
vendored
28
vendor/github.com/stretchr/testify/require/doc.go
generated
vendored
@@ -1,28 +0,0 @@
|
|||||||
// Package require implements the same assertions as the `assert` package but
|
|
||||||
// stops test execution when a test fails.
|
|
||||||
//
|
|
||||||
// Example Usage
|
|
||||||
//
|
|
||||||
// The following is a complete example using require in a standard test function:
|
|
||||||
// import (
|
|
||||||
// "testing"
|
|
||||||
// "github.com/stretchr/testify/require"
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// func TestSomething(t *testing.T) {
|
|
||||||
//
|
|
||||||
// var a string = "Hello"
|
|
||||||
// var b string = "Hello"
|
|
||||||
//
|
|
||||||
// require.Equal(t, a, b, "The two words should be the same.")
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Assertions
|
|
||||||
//
|
|
||||||
// The `require` package have same global functions as in the `assert` package,
|
|
||||||
// but instead of returning a boolean result they call `t.FailNow()`.
|
|
||||||
//
|
|
||||||
// Every assertion function also takes an optional string message as the final argument,
|
|
||||||
// allowing custom error messages to be appended to the message the assertion method outputs.
|
|
||||||
package require
|
|
||||||
16
vendor/github.com/stretchr/testify/require/forward_requirements.go
generated
vendored
16
vendor/github.com/stretchr/testify/require/forward_requirements.go
generated
vendored
@@ -1,16 +0,0 @@
|
|||||||
package require
|
|
||||||
|
|
||||||
// Assertions provides assertion methods around the
|
|
||||||
// TestingT interface.
|
|
||||||
type Assertions struct {
|
|
||||||
t TestingT
|
|
||||||
}
|
|
||||||
|
|
||||||
// New makes a new Assertions object for the specified TestingT.
|
|
||||||
func New(t TestingT) *Assertions {
|
|
||||||
return &Assertions{
|
|
||||||
t: t,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs"
|
|
||||||
1879
vendor/github.com/stretchr/testify/require/require.go
generated
vendored
1879
vendor/github.com/stretchr/testify/require/require.go
generated
vendored
File diff suppressed because it is too large
Load Diff
6
vendor/github.com/stretchr/testify/require/require.go.tmpl
generated
vendored
6
vendor/github.com/stretchr/testify/require/require.go.tmpl
generated
vendored
@@ -1,6 +0,0 @@
|
|||||||
{{.Comment}}
|
|
||||||
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
|
|
||||||
if h, ok := t.(tHelper); ok { h.Helper() }
|
|
||||||
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
1471
vendor/github.com/stretchr/testify/require/require_forward.go
generated
vendored
1471
vendor/github.com/stretchr/testify/require/require_forward.go
generated
vendored
File diff suppressed because it is too large
Load Diff
5
vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
generated
vendored
5
vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
generated
vendored
@@ -1,5 +0,0 @@
|
|||||||
{{.CommentWithoutT "a"}}
|
|
||||||
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
|
|
||||||
if h, ok := a.t.(tHelper); ok { h.Helper() }
|
|
||||||
{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
|
||||||
}
|
|
||||||
29
vendor/github.com/stretchr/testify/require/requirements.go
generated
vendored
29
vendor/github.com/stretchr/testify/require/requirements.go
generated
vendored
@@ -1,29 +0,0 @@
|
|||||||
package require
|
|
||||||
|
|
||||||
// TestingT is an interface wrapper around *testing.T
|
|
||||||
type TestingT interface {
|
|
||||||
Errorf(format string, args ...interface{})
|
|
||||||
FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
type tHelper interface {
|
|
||||||
Helper()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
|
|
||||||
// for table driven tests.
|
|
||||||
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
|
|
||||||
|
|
||||||
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
|
|
||||||
// for table driven tests.
|
|
||||||
type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
|
|
||||||
|
|
||||||
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
|
|
||||||
// for table driven tests.
|
|
||||||
type BoolAssertionFunc func(TestingT, bool, ...interface{})
|
|
||||||
|
|
||||||
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
|
|
||||||
// for table driven tests.
|
|
||||||
type ErrorAssertionFunc func(TestingT, error, ...interface{})
|
|
||||||
|
|
||||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs"
|
|
||||||
5
vendor/modules.txt
vendored
5
vendor/modules.txt
vendored
@@ -286,7 +286,7 @@ github.com/hashicorp/errwrap
|
|||||||
github.com/hashicorp/go-multierror
|
github.com/hashicorp/go-multierror
|
||||||
# github.com/hashicorp/go-version v1.3.0
|
# github.com/hashicorp/go-version v1.3.0
|
||||||
github.com/hashicorp/go-version
|
github.com/hashicorp/go-version
|
||||||
# github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c
|
# github.com/hinshun/vt10x v0.0.0-20220127042424-3ca73d0126d7
|
||||||
## explicit
|
## explicit
|
||||||
github.com/hinshun/vt10x
|
github.com/hinshun/vt10x
|
||||||
# github.com/hpcloud/tail v1.0.0
|
# github.com/hpcloud/tail v1.0.0
|
||||||
@@ -312,6 +312,7 @@ github.com/kballard/go-shellquote
|
|||||||
# github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351
|
# github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351
|
||||||
github.com/kevinburke/ssh_config
|
github.com/kevinburke/ssh_config
|
||||||
# github.com/kr/pty v1.1.5
|
# github.com/kr/pty v1.1.5
|
||||||
|
## explicit
|
||||||
github.com/kr/pty
|
github.com/kr/pty
|
||||||
# github.com/kubernetes-sigs/service-catalog v0.3.1
|
# github.com/kubernetes-sigs/service-catalog v0.3.1
|
||||||
## explicit
|
## explicit
|
||||||
@@ -585,9 +586,7 @@ github.com/spf13/cobra
|
|||||||
## explicit
|
## explicit
|
||||||
github.com/spf13/pflag
|
github.com/spf13/pflag
|
||||||
# github.com/stretchr/testify v1.7.0
|
# github.com/stretchr/testify v1.7.0
|
||||||
## explicit
|
|
||||||
github.com/stretchr/testify/assert
|
github.com/stretchr/testify/assert
|
||||||
github.com/stretchr/testify/require
|
|
||||||
# github.com/tidwall/gjson v1.9.3
|
# github.com/tidwall/gjson v1.9.3
|
||||||
## explicit
|
## explicit
|
||||||
github.com/tidwall/gjson
|
github.com/tidwall/gjson
|
||||||
|
|||||||
Reference in New Issue
Block a user