From 6a802c3ad801fbb1124a64bacdb465b4fcd61e22 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Tue, 12 Mar 2024 00:25:20 +0100 Subject: [PATCH] Added terminal detection --- Benchmarks_test.go | 19 ------------------- Color.go | 11 ----------- Color_test.go | 15 --------------- README.md | 18 +++++++----------- Terminal.go | 4 +++- ansi/Code.go | 11 ----------- ansi/Code_test.go | 10 ---------- go.mod | 5 ++++- go.sum | 2 ++ tty/Terminal_darwin.go | 6 ++++++ tty/Terminal_linux.go | 9 +++++++++ tty/Terminal_windows.go | 6 ++++++ 12 files changed, 37 insertions(+), 79 deletions(-) create mode 100644 tty/Terminal_darwin.go create mode 100644 tty/Terminal_linux.go create mode 100644 tty/Terminal_windows.go diff --git a/Benchmarks_test.go b/Benchmarks_test.go index 27403b3..012c8e0 100644 --- a/Benchmarks_test.go +++ b/Benchmarks_test.go @@ -1,7 +1,6 @@ package color_test import ( - "io" "testing" "git.akyoto.dev/go/color" @@ -19,24 +18,6 @@ func BenchmarkLCH(b *testing.B) { } } -func BenchmarkFprint(b *testing.B) { - color.Terminal = true - c := color.RGB(1.0, 1.0, 1.0) - - for i := 0; i < b.N; i++ { - c.Fprint(io.Discard, "") - } -} - -func BenchmarkFprintRaw(b *testing.B) { - color.Terminal = false - c := color.RGB(1.0, 1.0, 1.0) - - for i := 0; i < b.N; i++ { - c.Fprint(io.Discard, "") - } -} - func BenchmarkPrint(b *testing.B) { color.Terminal = true c := color.RGB(1.0, 1.0, 1.0) diff --git a/Color.go b/Color.go index cff542b..04489e9 100644 --- a/Color.go +++ b/Color.go @@ -2,7 +2,6 @@ package color import ( "fmt" - "io" ) // Value is a type definition for the data type of a single color component. @@ -20,16 +19,6 @@ func RGB(r Value, g Value, b Value) Color { return Color{r, g, b} } -// Fprint writes the text in the given color to the writer. -func (c Color) Fprint(writer io.Writer, args ...any) { - if !Terminal { - fmt.Fprint(writer, args...) - return - } - - fmt.Fprintf(writer, "\x1b[38;2;%d;%d;%dm%s\x1b[0m", byte(c.R*255), byte(c.G*255), byte(c.B*255), fmt.Sprint(args...)) -} - // Print writes the text in the given color to standard output. func (c Color) Print(args ...any) { if !Terminal { diff --git a/Color_test.go b/Color_test.go index 45646d7..f21e033 100644 --- a/Color_test.go +++ b/Color_test.go @@ -1,27 +1,12 @@ package color_test import ( - "io" "testing" "git.akyoto.dev/go/assert" "git.akyoto.dev/go/color" ) -func TestFprint(t *testing.T) { - color.Terminal = true - - color.RGB(1, 0, 0).Fprint(io.Discard, "red") - color.RGB(0, 1, 0).Fprint(io.Discard, "green") - color.RGB(0, 0, 1).Fprint(io.Discard, "blue") - - color.Terminal = false - - color.RGB(1, 0, 0).Fprint(io.Discard, "red") - color.RGB(0, 1, 0).Fprint(io.Discard, "green") - color.RGB(0, 0, 1).Fprint(io.Discard, "blue") -} - func TestPrint(t *testing.T) { color.Terminal = true diff --git a/README.md b/README.md index 6a7ce08..e7ff716 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,9 @@ Adds color to your terminal output. ## Features -- RGB color space -- LCH color space (oklch) -- Truecolor terminal output -- Zero dependencies (excluding tests) +- ANSI colors +- LCH colors +- RGB colors ## Installation @@ -28,7 +27,6 @@ orange.Println("orange text") ## Tests ``` -PASS: TestFprint PASS: TestPrint PASS: TestPrintf PASS: TestPrintln @@ -41,12 +39,10 @@ coverage: 100.0% of statements ## Benchmarks ``` -BenchmarkRGB-12 1000000000 0.3211 ns/op 0 B/op 0 allocs/op -BenchmarkLCH-12 4767306 251.8 ns/op 0 B/op 0 allocs/op -BenchmarkFprint-12 4869368 245.7 ns/op 0 B/op 0 allocs/op -BenchmarkFprintRaw-12 23155356 43.73 ns/op 0 B/op 0 allocs/op -BenchmarkPrint-12 358099 3560 ns/op 0 B/op 0 allocs/op -BenchmarkPrintRaw-12 3144412 378.9 ns/op 0 B/op 0 allocs/op +BenchmarkRGB-12 1000000000 0.3141 ns/op 0 B/op 0 allocs/op +BenchmarkLCH-12 4780176 250.9 ns/op 0 B/op 0 allocs/op +BenchmarkPrint-12 375394 3343 ns/op 0 B/op 0 allocs/op +BenchmarkPrintRaw-12 3105022 387.3 ns/op 0 B/op 0 allocs/op ``` ## License diff --git a/Terminal.go b/Terminal.go index d6ab79f..e6573d5 100644 --- a/Terminal.go +++ b/Terminal.go @@ -2,7 +2,9 @@ package color import ( "os" + + "git.akyoto.dev/go/color/tty" ) // Terminal is a boolean that indicates if we're in a terminal with truecolor support. -var Terminal = os.Getenv("COLORTERM") == "truecolor" +var Terminal = tty.IsTerminal(os.Stdout.Fd()) && os.Getenv("COLORTERM") == "truecolor" diff --git a/ansi/Code.go b/ansi/Code.go index 037dd8d..a0f8510 100644 --- a/ansi/Code.go +++ b/ansi/Code.go @@ -2,7 +2,6 @@ package ansi import ( "fmt" - "io" "git.akyoto.dev/go/color" ) @@ -10,16 +9,6 @@ import ( // Code represents an ANSI escape code. type Code int -// Fprint writes the text in the given color to the writer. -func (code Code) Fprint(writer io.Writer, args ...any) { - if !color.Terminal { - fmt.Fprint(writer, args...) - return - } - - fmt.Fprintf(writer, "\x1b[%dm%s\x1b[0m", code, fmt.Sprint(args...)) -} - // Print writes the text in the given color to standard output. func (code Code) Print(args ...any) { if !color.Terminal { diff --git a/ansi/Code_test.go b/ansi/Code_test.go index 6f2455e..a2230d6 100644 --- a/ansi/Code_test.go +++ b/ansi/Code_test.go @@ -1,7 +1,6 @@ package ansi_test import ( - "os" "testing" "git.akyoto.dev/go/color" @@ -19,15 +18,6 @@ func TestPrintRaw(t *testing.T) { } func testColors() { - ansi.Black.Fprint(os.Stdout, "Black\n") - ansi.White.Fprint(os.Stdout, "White\n") - ansi.Red.Fprint(os.Stdout, "Red\n") - ansi.Green.Fprint(os.Stdout, "Green\n") - ansi.Blue.Fprint(os.Stdout, "Blue\n") - ansi.Yellow.Fprint(os.Stdout, "Yellow\n") - ansi.Magenta.Fprint(os.Stdout, "Magenta\n") - ansi.Cyan.Fprint(os.Stdout, "Cyan\n") - ansi.Black.Print("Black\n") ansi.White.Print("White\n") ansi.Red.Print("Red\n") diff --git a/go.mod b/go.mod index 481b841..baf7b50 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module git.akyoto.dev/go/color go 1.22.0 -require git.akyoto.dev/go/assert v0.1.3 +require ( + git.akyoto.dev/go/assert v0.1.3 + golang.org/x/sys v0.18.0 +) diff --git a/go.sum b/go.sum index 9fc2547..895b93c 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ git.akyoto.dev/go/assert v0.1.3 h1:QwCUbmG4aZYsNk/OuRBz1zWVKmGlDUHhOnnDBfn8Qw8= git.akyoto.dev/go/assert v0.1.3/go.mod h1:0GzMaM0eURuDwtGkJJkCsI7r2aUKr+5GmWNTFPgDocM= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/tty/Terminal_darwin.go b/tty/Terminal_darwin.go new file mode 100644 index 0000000..48257c4 --- /dev/null +++ b/tty/Terminal_darwin.go @@ -0,0 +1,6 @@ +package tty + +// IsTerminal returns true if the file descriptor is a terminal. +func IsTerminal(fd uintptr) bool { + return false +} diff --git a/tty/Terminal_linux.go b/tty/Terminal_linux.go new file mode 100644 index 0000000..4e44a64 --- /dev/null +++ b/tty/Terminal_linux.go @@ -0,0 +1,9 @@ +package tty + +import "golang.org/x/sys/unix" + +// IsTerminal returns true if the file descriptor is a terminal. +func IsTerminal(fd uintptr) bool { + _, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) + return err == nil +} diff --git a/tty/Terminal_windows.go b/tty/Terminal_windows.go new file mode 100644 index 0000000..48257c4 --- /dev/null +++ b/tty/Terminal_windows.go @@ -0,0 +1,6 @@ +package tty + +// IsTerminal returns true if the file descriptor is a terminal. +func IsTerminal(fd uintptr) bool { + return false +}