diff --git a/README.md b/README.md index cb7c726..bdb5543 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Coverage Status Go ReportCard
- Example terminal output + Example terminal output

`termenv` lets you safely use advanced styling options on the terminal. It @@ -337,7 +337,7 @@ you need to enable ANSI processing in your application first: ## Color Chart -![ANSI color chart](https://github.com/muesli/termenv/raw/master/examples/color-chart/color-chart.png) +![ANSI color chart](https://github.com/muesli/termenv/raw/master/_examples/color-chart/color-chart.png) You can find the source code used to create this chart in `termenv`'s examples. diff --git a/examples/color-chart/color-chart.png b/_examples/color-chart/color-chart.png similarity index 100% rename from examples/color-chart/color-chart.png rename to _examples/color-chart/color-chart.png diff --git a/examples/color-chart/main.go b/_examples/color-chart/main.go similarity index 100% rename from examples/color-chart/main.go rename to _examples/color-chart/main.go diff --git a/examples/hello-world/hello-world.png b/_examples/hello-world/hello-world.png similarity index 100% rename from examples/hello-world/hello-world.png rename to _examples/hello-world/hello-world.png diff --git a/examples/hello-world/main.go b/_examples/hello-world/main.go similarity index 98% rename from examples/hello-world/main.go rename to _examples/hello-world/main.go index 8d96c7b..48633c8 100644 --- a/examples/hello-world/main.go +++ b/_examples/hello-world/main.go @@ -40,11 +40,13 @@ func main() { fmt.Printf("\n\t%s %s\n", termenv.String("Has foreground color").Bold(), termenv.ForegroundColor()) fmt.Printf("\t%s %s\n", termenv.String("Has background color").Bold(), termenv.BackgroundColor()) fmt.Printf("\t%s %t\n", termenv.String("Has dark background?").Bold(), termenv.HasDarkBackground()) + fmt.Println() hw := "Hello, world!" termenv.Copy(hw) - fmt.Println() fmt.Printf("\t%q copied to clipboard\n", hw) + fmt.Println() fmt.Printf("\t%s", termenv.Hyperlink("http://example.com", "This is a link")) + fmt.Println() } diff --git a/_examples/ssh/main.go b/_examples/ssh/main.go new file mode 100644 index 0000000..488937e --- /dev/null +++ b/_examples/ssh/main.go @@ -0,0 +1,124 @@ +package main + +import ( + "fmt" + "log" + "os" + "strings" + + "github.com/charmbracelet/wish" + "github.com/creack/pty" + "github.com/gliderlabs/ssh" + "github.com/muesli/termenv" +) + +type sshOutput struct { + ssh.Session + pty *os.File +} + +func (s *sshOutput) Fd() uintptr { + return s.pty.Fd() +} + +type sshEnviron struct { + environ []string +} + +func (s *sshEnviron) Getenv(key string) string { + for _, v := range s.environ { + if strings.HasPrefix(v, key+"=") { + return v[len(key)+1:] + } + } + return "" +} + +func (s *sshEnviron) Environ() []string { + return s.environ +} + +func outputFromSession(s ssh.Session) *termenv.Output { + sshPty, _, _ := s.Pty() + pty, _, err := pty.Open() + if err != nil { + panic(err) + } + o := &sshOutput{ + Session: s, + pty: pty, + } + environ := s.Environ() + environ = append(environ, fmt.Sprintf("TERM=%s", sshPty.Term)) + e := &sshEnviron{ + environ: environ, + } + return termenv.NewOutput(o, e) +} + +func main() { + s, err := wish.NewServer( + wish.WithAddress(":2345"), + wish.WithHostKeyPath("termenv"), + wish.WithMiddleware( + func(sh ssh.Handler) ssh.Handler { + return func(s ssh.Session) { + output := outputFromSession(s) + + p := output.ColorProfile() + fmt.Fprintf(s, "\tColor Profile: %d\n", p) + + fmt.Fprintf(s, "\n\t%s %s %s %s %s", + output.String("bold").Bold(), + output.String("faint").Faint(), + output.String("italic").Italic(), + output.String("underline").Underline(), + output.String("crossout").CrossOut(), + ) + + fmt.Fprintf(s, "\n\t%s %s %s %s %s %s %s", + output.String("red").Foreground(p.Color("#E88388")), + output.String("green").Foreground(p.Color("#A8CC8C")), + output.String("yellow").Foreground(p.Color("#DBAB79")), + output.String("blue").Foreground(p.Color("#71BEF2")), + output.String("magenta").Foreground(p.Color("#D290E4")), + output.String("cyan").Foreground(p.Color("#66C2CD")), + output.String("gray").Foreground(p.Color("#B9BFCA")), + ) + + fmt.Fprintf(s, "\n\t%s %s %s %s %s %s %s\n\n", + output.String("red").Foreground(p.Color("0")).Background(p.Color("#E88388")), + output.String("green").Foreground(p.Color("0")).Background(p.Color("#A8CC8C")), + output.String("yellow").Foreground(p.Color("0")).Background(p.Color("#DBAB79")), + output.String("blue").Foreground(p.Color("0")).Background(p.Color("#71BEF2")), + output.String("magenta").Foreground(p.Color("0")).Background(p.Color("#D290E4")), + output.String("cyan").Foreground(p.Color("0")).Background(p.Color("#66C2CD")), + output.String("gray").Foreground(p.Color("0")).Background(p.Color("#B9BFCA")), + ) + + fmt.Fprintf(s, "\n\t%s %s\n", output.String("Has foreground color").Bold(), output.ForegroundColor()) + fmt.Fprintf(s, "\t%s %s\n", output.String("Has background color").Bold(), output.BackgroundColor()) + fmt.Fprintf(s, "\t%s %t\n", output.String("Has dark background?").Bold(), output.HasDarkBackground()) + fmt.Fprintln(s) + + hw := "Hello, world!" + output.Copy(hw) + fmt.Fprintf(s, "\t%q copied to clipboard\n", hw) + fmt.Fprintln(s) + + fmt.Fprintf(s, "\t%s", output.Hyperlink("http://example.com", "This is a link")) + fmt.Fprintln(s) + + sh(s) + } + }, + ), + ) + if err != nil { + log.Fatal(err) + } + log.Printf("Listening on %s", s.Addr) + if err := s.ListenAndServe(); err != nil { + log.Fatal(err) + } +} diff --git a/termenv_unix.go b/termenv_unix.go index c392a77..635fa4a 100644 --- a/termenv_unix.go +++ b/termenv_unix.go @@ -232,7 +232,7 @@ func (o Output) termStatusReport(sequence int) (string, error) { t, err := unix.IoctlGetTermios(fd, tcgetattr) if err != nil { - return "", ErrStatusReport + return "", fmt.Errorf("%s: %s", ErrStatusReport, err) } defer unix.IoctlSetTermios(fd, tcsetattr, t) //nolint:errcheck @@ -240,7 +240,7 @@ func (o Output) termStatusReport(sequence int) (string, error) { noecho.Lflag = noecho.Lflag &^ unix.ECHO noecho.Lflag = noecho.Lflag &^ unix.ICANON if err := unix.IoctlSetTermios(fd, tcsetattr, &noecho); err != nil { - return "", ErrStatusReport + return "", fmt.Errorf("%s: %s", ErrStatusReport, err) } // first, send OSC query, which is ignored by terminal which do not support it @@ -252,7 +252,7 @@ func (o Output) termStatusReport(sequence int) (string, error) { // read the next response res, isOSC, err := readNextResponse(o.tty) if err != nil { - return "", err + return "", fmt.Errorf("%s: %s", ErrStatusReport, err) } // if this is not OSC response, then the terminal does not support it