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:
parent
b438aef169
commit
4fd3ae4c7e
|
@ -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
44
main.go
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue