Skip to content

Commit

Permalink
Don't track the formatter
Browse files Browse the repository at this point in the history
They are only needed at startup, so let's not keep them around while
paging.
  • Loading branch information
walles committed Dec 17, 2023
1 parent 52516b2 commit 21afb4f
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 61 deletions.
2 changes: 1 addition & 1 deletion m/embed-api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func (p *Pager) Page() error {
return e
}

p.StartPaging(screen)
p.StartPaging(screen, nil, nil)
screen.Close()
if p.DeInit {
return nil
Expand Down
25 changes: 10 additions & 15 deletions m/pager.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,6 @@ type Pager struct {
// clear the last line, and show the cursor.
DeInit bool

// Render the UI using this style
ChromaStyle *chroma.Style

// Render the UI using this formatter
ChromaFormatter *chroma.Formatter

// Optional ANSI to prefix each text line with. Initialised using
// ChromaStyle and ChromaFormatter.
linePrefix string
Expand Down Expand Up @@ -444,16 +438,17 @@ func (p *Pager) onRune(char rune) {
}
}

func (p *Pager) initStyle() {
if p.ChromaStyle == nil && p.ChromaFormatter == nil {
return
// Return an ANSI SGR sequence to use for plain text. Can be "".
func getLineColorPrefix(chromaStyle *chroma.Style, chromaFormatter *chroma.Formatter) string {
if chromaStyle == nil && chromaFormatter == nil {
return ""
}
if p.ChromaStyle == nil || p.ChromaFormatter == nil {
if chromaStyle == nil || chromaFormatter == nil {
panic("Both ChromaStyle and ChromaFormatter should be set or neither")
}

stringBuilder := strings.Builder{}
err := (*p.ChromaFormatter).Format(&stringBuilder, p.ChromaStyle, chroma.Literator(chroma.Token{
err := (*chromaFormatter).Format(&stringBuilder, chromaStyle, chroma.Literator(chroma.Token{
Type: chroma.None,
Value: "XXX",
}))
Expand All @@ -467,11 +462,11 @@ func (p *Pager) initStyle() {
panic("XXX not found in " + formatted)
}

p.linePrefix = formatted[:cutoff]
return formatted[:cutoff]
}

// StartPaging brings up the pager on screen
func (p *Pager) StartPaging(screen twin.Screen) {
func (p *Pager) StartPaging(screen twin.Screen, chromaStyle *chroma.Style, chromaFormatter *chroma.Formatter) {
log.Trace("Pager starting")
defer log.Trace("Pager done")

Expand All @@ -482,10 +477,10 @@ func (p *Pager) StartPaging(screen twin.Screen) {
}()

unprintableStyle = p.UnprintableStyle
ConsumeLessTermcapEnvs(p.ChromaStyle, p.ChromaFormatter)
ConsumeLessTermcapEnvs(chromaStyle, chromaFormatter)

p.screen = screen
p.initStyle()
p.linePrefix = getLineColorPrefix(chromaStyle, chromaFormatter)

go func() {
for range p.reader.moreLinesAdded {
Expand Down
33 changes: 15 additions & 18 deletions m/pager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func startPaging(t *testing.T, reader *Reader) *twin.FakeScreen {
pager.Quit()

// Except for just quitting, this also associates our FakeScreen with the Pager
pager.StartPaging(screen)
pager.StartPaging(screen, nil, nil)

// This makes sure at least one frame gets rendered
pager.redraw("")
Expand Down Expand Up @@ -341,7 +341,7 @@ func TestScrollToBottomWrapNextToLastLine(t *testing.T) {
pager.Quit()

// Get contents onto our fake screen
pager.StartPaging(screen)
pager.StartPaging(screen, nil, nil)
pager.redraw("")

actual := strings.Join([]string{
Expand Down Expand Up @@ -372,7 +372,7 @@ func TestScrollToEndLongInput(t *testing.T) {
// Connect the pager with a screen
const screenHeight = 10
screen := twin.NewFakeScreen(20, screenHeight)
pager.StartPaging(screen)
pager.StartPaging(screen, nil, nil)

// This is what we're really testing
pager.scrollToEnd()
Expand Down Expand Up @@ -507,7 +507,7 @@ func TestPageSamples(t *testing.T) {
pager.Quit()

// Get contents onto our fake screen
pager.StartPaging(screen)
pager.StartPaging(screen, nil, nil)
pager.redraw("")

firstReaderLine := myReader.GetLine(0)
Expand Down Expand Up @@ -563,7 +563,7 @@ func TestClearToEndOfLine_ClearFromStartScrolledRight(t *testing.T) {

// Except for just quitting, this also associates a FakeScreen with the Pager
screen := twin.NewFakeScreen(3, 10)
pager.StartPaging(screen)
pager.StartPaging(screen, nil, nil)

// Scroll right, this is what we're testing
pager.leftColumnZeroBased = 44
Expand All @@ -583,22 +583,19 @@ func TestClearToEndOfLine_ClearFromStartScrolledRight(t *testing.T) {
assert.DeepEqual(t, actual, expected, cmp.AllowUnexported(twin.Style{}))
}

func TestInitStyle(t *testing.T) {
testMe := Pager{
ChromaStyle: styles.Registry["gruvbox"],
ChromaFormatter: &formatters.TTY16m,
}
testMe.initStyle()
assert.Equal(t, testMe.linePrefix, "\x1b[38;2;235;219;178m")
func TestGetLineColorPrefix(t *testing.T) {
assert.Equal(t,
getLineColorPrefix(styles.Registry["gruvbox"], &formatters.TTY16m),
"\x1b[38;2;235;219;178m",
)
}

func TestInitStyle256(t *testing.T) {
testMe := Pager{
ChromaStyle: styles.Registry["catppuccin-macchiato"],
ChromaFormatter: &formatters.TTY256,
}
testMe.initStyle()
assert.Equal(t, testMe.linePrefix, "\x1b[38;5;189m")
assert.Equal(t,
getLineColorPrefix(
styles.Registry["catppuccin-macchiato"],
&formatters.TTY256), "\x1b[38;5;189m",
)
}

func benchmarkSearch(b *testing.B, highlighted bool) {
Expand Down
2 changes: 1 addition & 1 deletion m/screenLines_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func TestWrapping(t *testing.T) {
pager.Quit()

// Get contents onto our fake screen
pager.StartPaging(screen)
pager.StartPaging(screen, nil, nil)
pager.redraw("")

actual := strings.Join([]string{
Expand Down
34 changes: 21 additions & 13 deletions moar.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func parseStyleOption(styleOption string) (chroma.Style, error) {
return *style, nil
}

func parseColorsOption(colorsOption string) (chroma.Formatter, error) {
func parseColorsOption(colorsOption string) (twin.ColorType, error) {
if strings.ToLower(colorsOption) == "auto" {
colorsOption = "16M"
if strings.Contains(os.Getenv("TERM"), "256") {
Expand All @@ -177,16 +177,17 @@ func parseColorsOption(colorsOption string) (chroma.Formatter, error) {

switch strings.ToUpper(colorsOption) {
case "8":
return formatters.TTY8, nil
return twin.ColorType8, nil
case "16":
return formatters.TTY16, nil
return twin.ColorType16, nil
case "256":
return formatters.TTY256, nil
return twin.ColorType256, nil
case "16M":
return formatters.TTY16m, nil
return twin.ColorType24bit, nil
}

return nil, fmt.Errorf("Valid counts are 8, 16, 256, 16M or auto.")
var noColor twin.ColorType
return noColor, fmt.Errorf("Valid counts are 8, 16, 256, 16M or auto.")
}

func parseStatusBarStyle(styleOption string) (m.StatusBarStyle, error) {
Expand Down Expand Up @@ -385,7 +386,7 @@ func main() {
if err != nil {
panic(fmt.Errorf("Failed parsing default formatter: %w", err))
}
formatter := flagSetFunc(flagSet,
terminalColorsCount := flagSetFunc(flagSet,
"colors", defaultFormatter, "Highlighting palette size: 8, 16, 256, 16M, auto", parseColorsOption)

noLineNumbers := flagSet.Bool("no-linenumbers", false, "Hide line numbers on startup, press left arrow key to show")
Expand Down Expand Up @@ -511,13 +512,22 @@ func main() {
return
}

formatter := formatters.TTY256
if *terminalColorsCount == twin.ColorType8 {
formatter = formatters.TTY8
} else if *terminalColorsCount == twin.ColorType16 {
formatter = formatters.TTY16
} else if *terminalColorsCount == twin.ColorType24bit {
formatter = formatters.TTY
}

var reader *m.Reader
if stdinIsRedirected {
// Display input pipe contents
reader = m.NewReaderFromStream("", os.Stdin)
} else {
// Display the input file contents
reader, err = m.NewReaderFromFilename(*inputFilename, *style, *formatter)
reader, err = m.NewReaderFromFilename(*inputFilename, *style, formatter)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
os.Exit(1)
Expand All @@ -535,15 +545,13 @@ func main() {
pager.ScrollLeftHint = *scrollLeftHint
pager.ScrollRightHint = *scrollRightHint
pager.SideScrollAmount = int(*shift)
pager.ChromaStyle = style
pager.ChromaFormatter = formatter

pager.TargetLineNumberOneBased = targetLineNumberOneBased
if *follow && pager.TargetLineNumberOneBased == 0 {
pager.TargetLineNumberOneBased = math.MaxInt
}

startPaging(pager, screen)
startPaging(pager, screen, style, &formatter)
}

// Define a generic flag with specified name, default value, and usage string.
Expand All @@ -564,7 +572,7 @@ func flagSetFunc[T any](flagSet *flag.FlagSet, name string, defaultValue T, usag
return &parsed
}

func startPaging(pager *m.Pager, screen twin.Screen) {
func startPaging(pager *m.Pager, screen twin.Screen, chromaStyle *chroma.Style, chromaFormatter *chroma.Formatter) {
defer func() {
// Restore screen...
screen.Close()
Expand All @@ -583,5 +591,5 @@ func startPaging(pager *m.Pager, screen twin.Screen) {
}
}()

pager.StartPaging(screen)
pager.StartPaging(screen, chromaStyle, chromaFormatter)
}
32 changes: 19 additions & 13 deletions twin/colors.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ const (
colorTypeDefault ColorType = iota

// https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit
colorType16
//
// Note that this type is only used for output, on input we store 3 bit
// colors as 4 bit colors since they map to the same values.
ColorType8

// https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit
ColorType16

// https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
colorType256
ColorType256

// RGB: https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit
colorType24bit
ColorType24bit
)

// Reset to default foreground / background color
Expand Down Expand Up @@ -51,19 +57,19 @@ func newColor(colorType ColorType, value uint32) Color {
// Four bit colors as defined here:
// https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit
func NewColor16(colorNumber0to15 int) Color {
return newColor(colorType16, uint32(colorNumber0to15))
return newColor(ColorType16, uint32(colorNumber0to15))
}

func NewColor256(colorNumber uint8) Color {
return newColor(colorType256, uint32(colorNumber))
return newColor(ColorType256, uint32(colorNumber))
}

func NewColor24Bit(red uint8, green uint8, blue uint8) Color {
return newColor(colorType24bit, (uint32(red)<<16)+(uint32(green)<<8)+(uint32(blue)<<0))
return newColor(ColorType24bit, (uint32(red)<<16)+(uint32(green)<<8)+(uint32(blue)<<0))
}

func NewColorHex(rgb uint32) Color {
return newColor(colorType24bit, rgb)
return newColor(ColorType24bit, rgb)
}

func (color Color) colorType() ColorType {
Expand All @@ -85,7 +91,7 @@ func (color Color) ansiString(foreground bool) string {
fgBgMarker = "4"
}

if color.colorType() == colorType16 {
if color.colorType() == ColorType16 {
if value < 8 {
return fmt.Sprint("\x1b[", fgBgMarker, value, "m")
} else if value <= 15 {
Expand All @@ -97,13 +103,13 @@ func (color Color) ansiString(foreground bool) string {
}
}

if color.colorType() == colorType256 {
if color.colorType() == ColorType256 {
if value <= 255 {
return fmt.Sprint("\x1b[", fgBgMarker, "8;5;", value, "m")
}
}

if color.colorType() == colorType24bit {
if color.colorType() == ColorType24bit {
red := (value & 0xff0000) >> 16
green := (value & 0xff00) >> 8
blue := value & 0xff
Expand Down Expand Up @@ -133,16 +139,16 @@ func (color Color) String() string {
case colorTypeDefault:
return "Default color"

case colorType16:
case ColorType16:
return colorNames16[int(color.colorValue())]

case colorType256:
case ColorType256:
if color.colorValue() < 16 {
return colorNames16[int(color.colorValue())]
}
return fmt.Sprintf("#%02x", color.colorValue())

case colorType24bit:
case ColorType24bit:
return fmt.Sprintf("#%06x", color.colorValue())
}

Expand Down

0 comments on commit 21afb4f

Please sign in to comment.