perf: use strings.Builder instead of buffer

This commit is contained in:
Jan De Dobbeleer 2021-01-06 08:52:43 +01:00 committed by Jan De Dobbeleer
parent 5d6d64508d
commit 3a86f49b72
6 changed files with 22 additions and 49 deletions

View file

@ -1,7 +1,6 @@
package main package main
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
@ -46,7 +45,7 @@ func getColorFromName(colorName string, isBackground bool) (string, error) {
// AnsiColor writes colorized strings // AnsiColor writes colorized strings
type AnsiColor struct { type AnsiColor struct {
buffer *bytes.Buffer builder strings.Builder
formats *ansiFormats formats *ansiFormats
} }
@ -84,7 +83,7 @@ func (a *AnsiColor) writeColoredText(background, foreground, text string) {
fgAnsiColor := a.getAnsiFromColorString(foreground, false) fgAnsiColor := a.getAnsiFromColorString(foreground, false)
coloredText = fmt.Sprintf(a.formats.colorFull, bgAnsiColor, fgAnsiColor, text) coloredText = fmt.Sprintf(a.formats.colorFull, bgAnsiColor, fgAnsiColor, text)
} }
a.buffer.WriteString(coloredText) a.builder.WriteString(coloredText)
} }
func (a *AnsiColor) writeAndRemoveText(background, foreground, text, textToRemove, parentText string) string { func (a *AnsiColor) writeAndRemoveText(background, foreground, text, textToRemove, parentText string) string {
@ -122,9 +121,9 @@ func (a *AnsiColor) write(background, foreground, text string) {
} }
func (a *AnsiColor) string() string { func (a *AnsiColor) string() string {
return a.buffer.String() return a.builder.String()
} }
func (a *AnsiColor) reset() { func (a *AnsiColor) reset() {
a.buffer.Reset() a.builder.Reset()
} }

View file

@ -1,7 +1,6 @@
package main package main
import ( import (
"bytes"
"testing" "testing"
"github.com/gookit/color" "github.com/gookit/color"
@ -16,7 +15,6 @@ func TestWriteAndRemoveText(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := renderer.writeAndRemoveText("#193549", "#fff", "This is white, ", "This is white, ", inputText) text := renderer.writeAndRemoveText("#193549", "#fff", "This is white, ", "This is white, ", inputText)
@ -28,7 +26,6 @@ func TestWriteAndRemoveTextColored(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := renderer.writeAndRemoveText("#193549", "#ff5733", "this is orange", "<#ff5733>this is orange</>", inputText) text := renderer.writeAndRemoveText("#193549", "#ff5733", "this is orange", "<#ff5733>this is orange</>", inputText)
@ -40,7 +37,6 @@ func TestWriteColorOverride(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
renderer.write("#193549", "#ff5733", inputText) renderer.write("#193549", "#ff5733", inputText)
@ -51,7 +47,6 @@ func TestWriteColorOverrideBackground(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := "This is white, <,#000000>this is black</>, white again" text := "This is white, <,#000000>this is black</>, white again"
@ -63,7 +58,6 @@ func TestWriteColorOverrideBackground16(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := "This is default <,white> this background is changed</> default again" text := "This is default <,white> this background is changed</> default again"
@ -77,7 +71,6 @@ func TestWriteColorOverrideBoth(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := "This is white, <#000000,#ffffff>this is black</>, white again" text := "This is white, <#000000,#ffffff>this is black</>, white again"
@ -90,7 +83,6 @@ func TestWriteColorOverrideBoth16(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := "This is white, <black,white>this is black</>, white again" text := "This is white, <black,white>this is black</>, white again"
@ -103,7 +95,6 @@ func TestWriteColorOverrideDouble(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := "<#ffffff>jan</>@<#ffffff>Jans-MBP</>" text := "<#ffffff>jan</>@<#ffffff>Jans-MBP</>"
@ -116,7 +107,6 @@ func TestWriteColorTransparent(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := "This is white" text := "This is white"
@ -128,7 +118,6 @@ func TestWriteColorName(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := "This is white, <red>this is red</>, white again" text := "This is white, <red>this is red</>, white again"
@ -140,7 +129,6 @@ func TestWriteColorInvalid(t *testing.T) {
formats := &ansiFormats{} formats := &ansiFormats{}
formats.init("pwsh") formats.init("pwsh")
renderer := &AnsiColor{ renderer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
text := "This is white, <invalid>this is orange</>, white again" text := "This is white, <invalid>this is orange</>, white again"
@ -149,41 +137,31 @@ func TestWriteColorInvalid(t *testing.T) {
} }
func TestGetAnsiFromColorStringBg(t *testing.T) { func TestGetAnsiFromColorStringBg(t *testing.T) {
renderer := &AnsiColor{ renderer := &AnsiColor{}
buffer: new(bytes.Buffer),
}
colorCode := renderer.getAnsiFromColorString("blue", true) colorCode := renderer.getAnsiFromColorString("blue", true)
assert.Equal(t, color.BgBlue.Code(), colorCode) assert.Equal(t, color.BgBlue.Code(), colorCode)
} }
func TestGetAnsiFromColorStringFg(t *testing.T) { func TestGetAnsiFromColorStringFg(t *testing.T) {
renderer := &AnsiColor{ renderer := &AnsiColor{}
buffer: new(bytes.Buffer),
}
colorCode := renderer.getAnsiFromColorString("red", false) colorCode := renderer.getAnsiFromColorString("red", false)
assert.Equal(t, color.FgRed.Code(), colorCode) assert.Equal(t, color.FgRed.Code(), colorCode)
} }
func TestGetAnsiFromColorStringHex(t *testing.T) { func TestGetAnsiFromColorStringHex(t *testing.T) {
renderer := &AnsiColor{ renderer := &AnsiColor{}
buffer: new(bytes.Buffer),
}
colorCode := renderer.getAnsiFromColorString("#AABBCC", false) colorCode := renderer.getAnsiFromColorString("#AABBCC", false)
assert.Equal(t, color.HEX("#AABBCC").Code(), colorCode) assert.Equal(t, color.HEX("#AABBCC").Code(), colorCode)
} }
func TestGetAnsiFromColorStringInvalidFg(t *testing.T) { func TestGetAnsiFromColorStringInvalidFg(t *testing.T) {
renderer := &AnsiColor{ renderer := &AnsiColor{}
buffer: new(bytes.Buffer),
}
colorCode := renderer.getAnsiFromColorString("invalid", false) colorCode := renderer.getAnsiFromColorString("invalid", false)
assert.Equal(t, "", colorCode) assert.Equal(t, "", colorCode)
} }
func TestGetAnsiFromColorStringInvalidBg(t *testing.T) { func TestGetAnsiFromColorStringInvalidBg(t *testing.T) {
renderer := &AnsiColor{ renderer := &AnsiColor{}
buffer: new(bytes.Buffer),
}
colorCode := renderer.getAnsiFromColorString("invalid", true) colorCode := renderer.getAnsiFromColorString("invalid", true)
assert.Equal(t, "", colorCode) assert.Equal(t, "", colorCode)
} }

View file

@ -1,23 +1,23 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"strings"
) )
// AnsiRenderer exposes functionality using ANSI // AnsiRenderer exposes functionality using ANSI
type AnsiRenderer struct { type AnsiRenderer struct {
buffer *bytes.Buffer builder strings.Builder
formats *ansiFormats formats *ansiFormats
} }
func (r *AnsiRenderer) carriageForward() { func (r *AnsiRenderer) carriageForward() {
r.buffer.WriteString(fmt.Sprintf(r.formats.left, 1000)) r.builder.WriteString(fmt.Sprintf(r.formats.left, 1000))
} }
func (r *AnsiRenderer) setCursorForRightWrite(text string, offset int) { func (r *AnsiRenderer) setCursorForRightWrite(text string, offset int) {
strippedLen := r.formats.lenWithoutANSI(text) + -offset strippedLen := r.formats.lenWithoutANSI(text) + -offset
r.buffer.WriteString(fmt.Sprintf(r.formats.right, strippedLen)) r.builder.WriteString(fmt.Sprintf(r.formats.right, strippedLen))
} }
func (r *AnsiRenderer) changeLine(numberOfLines int) { func (r *AnsiRenderer) changeLine(numberOfLines int) {
@ -26,32 +26,32 @@ func (r *AnsiRenderer) changeLine(numberOfLines int) {
position = "F" position = "F"
numberOfLines = -numberOfLines numberOfLines = -numberOfLines
} }
r.buffer.WriteString(fmt.Sprintf(r.formats.linechange, numberOfLines, position)) r.builder.WriteString(fmt.Sprintf(r.formats.linechange, numberOfLines, position))
} }
func (r *AnsiRenderer) creset() { func (r *AnsiRenderer) creset() {
r.buffer.WriteString(r.formats.creset) r.builder.WriteString(r.formats.creset)
} }
func (r *AnsiRenderer) print(text string) { func (r *AnsiRenderer) print(text string) {
r.buffer.WriteString(text) r.builder.WriteString(text)
// Due to a bug in Powershell, the end of the line needs to be cleared. // Due to a bug in Powershell, the end of the line needs to be cleared.
// If this doesn't happen, the portion after the prompt gets colored in the background // If this doesn't happen, the portion after the prompt gets colored in the background
// color of the line above the new input line. Clearing the line fixes this, // color of the line above the new input line. Clearing the line fixes this,
// but can hopefully one day be removed when this is resolved natively. // but can hopefully one day be removed when this is resolved natively.
if r.formats.shell == pwsh || r.formats.shell == powershell5 { if r.formats.shell == pwsh || r.formats.shell == powershell5 {
r.buffer.WriteString(r.formats.clearEOL) r.builder.WriteString(r.formats.clearEOL)
} }
} }
func (r *AnsiRenderer) string() string { func (r *AnsiRenderer) string() string {
return r.buffer.String() return r.builder.String()
} }
func (r *AnsiRenderer) saveCursorPosition() { func (r *AnsiRenderer) saveCursorPosition() {
r.buffer.WriteString(r.formats.saveCursorPosition) r.builder.WriteString(r.formats.saveCursorPosition)
} }
func (r *AnsiRenderer) restoreCursorPosition() { func (r *AnsiRenderer) restoreCursorPosition() {
r.buffer.WriteString(r.formats.restoreCursorPosition) r.builder.WriteString(r.formats.restoreCursorPosition)
} }

View file

@ -202,7 +202,7 @@ func (e *engine) debug() {
e.writePowerLineSeparator(Transparent, e.activeSegment.Background, true) e.writePowerLineSeparator(Transparent, e.activeSegment.Background, true)
} }
segmentTiming.stringValue = e.color.string() segmentTiming.stringValue = e.color.string()
e.color.buffer.Reset() e.color.builder.Reset()
} }
segmentTimings = append(segmentTimings, segmentTiming) segmentTimings = append(segmentTimings, segmentTiming)
} }

View file

@ -3,7 +3,6 @@
package main package main
import ( import (
"bytes"
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
@ -134,11 +133,9 @@ func main() {
formats.init(env.getShellName()) formats.init(env.getShellName())
renderer := &AnsiRenderer{ renderer := &AnsiRenderer{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
colorer := &AnsiColor{ colorer := &AnsiColor{
buffer: new(bytes.Buffer),
formats: formats, formats: formats,
} }
title := &consoleTitle{ title := &consoleTitle{

View file

@ -1,7 +1,6 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"path/filepath" "path/filepath"
"sort" "sort"
@ -70,7 +69,7 @@ func (pt *path) init(props *properties, env environmentInfo) {
} }
func (pt *path) getAgnosterPath() string { func (pt *path) getAgnosterPath() string {
buffer := new(bytes.Buffer) var buffer strings.Builder
pwd := pt.getPwd() pwd := pt.getPwd()
buffer.WriteString(pt.rootLocation()) buffer.WriteString(pt.rootLocation())
pathDepth := pt.pathDepth(pwd) pathDepth := pt.pathDepth(pwd)