Improvements to display code

Now switchable, detects terminal. Don't be weird with tabs. Known issues are
not being themeable and bold match output stopping if colours are used inside.
This commit is contained in:
Laurence Withers 2023-05-13 10:58:06 +01:00
parent b438aef169
commit 4fd3ae4c7e
2 changed files with 81 additions and 17 deletions

54
display.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
"fmt"
"github.com/logrusorgru/aurora/v4"
"golang.org/x/sys/unix"
)
type Display struct {
a *aurora.Aurora
}
func NewDisplay(noColour bool) *Display {
if _, err := unix.IoctlGetTermios(1, unix.TCGETS); err != nil {
noColour = true
}
a := aurora.New(aurora.WithColors(!noColour))
return &Display{
a: a,
}
}
func (d *Display) Filename(name string) aurora.Value {
return d.a.BgBlue(d.a.White(name))
}
func (d *Display) LineNumber(lineNum int) aurora.Value {
return d.a.Green(lineNum)
}
func (d *Display) Match(text string) aurora.Value {
return d.a.Bold(text)
}
func (d *Display) TruncatedMarker() aurora.Value {
return d.a.Magenta("…")
}
func (d *Display) TruncatedBytes(byteCount int) aurora.Value {
return d.a.Faint(fmt.Sprintf("(%d bytes)", byteCount))
}
func (d *Display) BadUTF8Char() aurora.Value {
return d.a.Magenta("\uFFFD")
}
func (d *Display) CarriageReturn() aurora.Value {
return d.a.Magenta(`\r`)
}
func (d *Display) UnprintableChar() aurora.Value {
return d.a.Magenta(`·`)
}

44
main.go
View File

@ -14,14 +14,12 @@ import (
"unicode"
"unicode/utf8"
"github.com/logrusorgru/aurora/v4"
"github.com/spf13/cobra"
"golang.org/x/sys/unix"
)
// TODO:
// - option to squelch aurora output
// - detect if terminal
// - bold of escaped output doesn't work
// - binary file detection
// - long-line / minified-file detection
// - ignore files by extension (or glob?)
@ -65,6 +63,9 @@ var (
ignoreList []string
ignoreMap map[string]struct{}
ignoreCase bool
noColour bool
display *Display
matchedAny bool
)
func init() {
@ -72,9 +73,12 @@ func init() {
rootCmd.Flags().StringSliceVarP(&searchFixed, "fixed", "Q", nil, "pattern to match (fixed string)")
rootCmd.Flags().StringSliceVarP(&ignoreList, "exclude", "x", []string{".git"}, "files/directories to exclude")
rootCmd.Flags().BoolVarP(&ignoreCase, "ignore-case", "i", false, "make all searches case insensitive")
rootCmd.Flags().BoolVarP(&noColour, "no-colour", "C", false, "disable colour output")
}
func run(c *cobra.Command, args []string) error {
display = NewDisplay(noColour)
if len(searchRegexp) == 0 && len(searchFixed) == 0 {
if len(args) == 0 {
return errors.New("no pattern specified")
@ -196,11 +200,16 @@ func search(path string) error {
if !printedHeader {
printedHeader = true
fmt.Println(aurora.BgBlue(aurora.Bold(path)))
if !matchedAny {
matchedAny = true
} else {
fmt.Println("")
}
fmt.Println(display.Filename(path))
}
b.Reset()
fmt.Fprintf(&b, "%4d: ", aurora.Gray(16, lineNum))
fmt.Fprintf(&b, "%4d: ", display.LineNumber(lineNum))
if loc[0] < 128 {
escape(&b, line[0:loc[0]])
@ -213,14 +222,15 @@ func search(path string) error {
start++
}
fmt.Fprintf(&b, "(%d bytes)%s", start, aurora.Magenta("…"))
b.WriteString(display.TruncatedBytes(start).String())
b.WriteString(display.TruncatedMarker().String())
escape(&b, line[start:loc[0]])
}
if loc[1]-loc[0] < 128 {
b2.Reset()
escape(&b2, line[loc[0]:loc[1]])
b.WriteString(aurora.Bold(b2.String()).String())
b.WriteString(display.Match(b2.String()).String())
if loc[1]+128 > len(line) {
escape(&b, line[loc[1]:])
@ -233,7 +243,8 @@ func search(path string) error {
end--
}
escape(&b, line[loc[1]:end])
fmt.Fprintf(&b, "(%d bytes)%s", len(line)-end, aurora.Magenta("…"))
b.WriteString(display.TruncatedBytes(len(line) - end).String())
b.WriteString(display.TruncatedMarker().String())
}
} else {
@ -247,8 +258,9 @@ func search(path string) error {
b2.Reset()
escape(&b2, line[loc[0]:end])
b.WriteString(aurora.Bold(b2.String()).String())
fmt.Fprintf(&b, "%s(%d bytes)", aurora.Magenta("…"), len(line)-end)
b.WriteString(display.Match(b2.String()).String())
b.WriteString(display.TruncatedMarker().String())
b.WriteString(display.TruncatedBytes(len(line) - end).String())
}
@ -282,19 +294,17 @@ func escape(b *strings.Builder, s []byte) {
switch {
case r == utf8.RuneError && size == 1:
b.WriteString(aurora.Magenta("\uFFFD").String())
b.WriteString(display.BadUTF8Char().String())
case r == '\r':
b.WriteString(aurora.Magenta(`\r`).String())
b.WriteString(display.CarriageReturn().String())
case r == '\t':
b.WriteString(aurora.Magenta(`\t`).String())
case unicode.IsPrint(r):
case r == '\t',
unicode.IsPrint(r):
b.WriteRune(r)
default:
b.WriteString(aurora.Magenta(".").String())
b.WriteString(display.UnprintableChar().String())
}
}
}