Skip to content

Commit dca8a44

Browse files
committed
Optimise writeString for Windows with vtEnabled
Instead of doing 3 `WriteConsole` calls, we do a single call that sets the cursor, sets the style and writes the content. This gives us a performance boost of up to 3x faster.
1 parent 7815866 commit dca8a44

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

console_win.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -655,12 +655,15 @@ var vkKeys = map[uint16]Key{
655655
func getu32(v []byte) uint32 {
656656
return uint32(v[0]) + (uint32(v[1]) << 8) + (uint32(v[2]) << 16) + (uint32(v[3]) << 24)
657657
}
658+
658659
func geti32(v []byte) int32 {
659660
return int32(getu32(v))
660661
}
662+
661663
func getu16(v []byte) uint16 {
662664
return uint16(v[0]) + (uint16(v[1]) << 8)
663665
}
666+
664667
func geti16(v []byte) int16 {
665668
return int16(getu16(v))
666669
}
@@ -938,7 +941,7 @@ func (s *cScreen) mapStyle(style Style) uint16 {
938941
return attr
939942
}
940943

941-
func (s *cScreen) sendVtStyle(style Style) {
944+
func (s *cScreen) makeVtStyle(style Style) string {
942945
esc := &strings.Builder{}
943946

944947
fg, bg, attrs := style.fg, style.bg, style.attrs
@@ -998,30 +1001,40 @@ func (s *cScreen) sendVtStyle(style Style) {
9981001
esc.WriteString(vtExitUrl)
9991002
}
10001003

1001-
s.emitVtString(esc.String())
1004+
return esc.String()
10021005
}
10031006

1004-
func (s *cScreen) writeString(x, y int, style Style, ch []uint16) {
1007+
func (s *cScreen) sendVtStyle(style Style) {
1008+
s.emitVtString(s.makeVtStyle(style))
1009+
}
1010+
1011+
func (s *cScreen) writeString(x, y int, style Style, vtBuf, ch []uint16) {
10051012
// we assume the caller has hidden the cursor
10061013
if len(ch) == 0 {
10071014
return
10081015
}
1009-
s.setCursorPos(x, y, s.vten)
10101016

10111017
if s.vten {
1012-
s.sendVtStyle(style)
1018+
vtBuf = append(vtBuf, utf16.Encode([]rune(fmt.Sprintf(vtCursorPos, y+1, x+1)))...)
1019+
styleStr := s.makeVtStyle(style)
1020+
vtBuf = append(vtBuf, utf16.Encode([]rune(styleStr))...)
1021+
vtBuf = append(vtBuf, ch...)
1022+
_ = syscall.WriteConsole(s.out, &vtBuf[0], uint32(len(vtBuf)), nil, nil)
1023+
vtBuf = vtBuf[:0]
10131024
} else {
1025+
s.setCursorPos(x, y, s.vten)
10141026
_, _, _ = procSetConsoleTextAttribute.Call(
10151027
uintptr(s.out),
10161028
uintptr(s.mapStyle(style)))
1029+
_ = syscall.WriteConsole(s.out, &ch[0], uint32(len(ch)), nil, nil)
10171030
}
1018-
_ = syscall.WriteConsole(s.out, &ch[0], uint32(len(ch)), nil, nil)
10191031
}
10201032

10211033
func (s *cScreen) draw() {
10221034
// allocate a scratch line bit enough for no combining chars.
10231035
// if you have combining characters, you may pay for extra allocations.
10241036
buf := make([]uint16, 0, s.w)
1037+
var vtBuf []uint16
10251038
wcs := buf[:]
10261039
lstyle := styleInvalid
10271040

@@ -1040,7 +1053,7 @@ func (s *cScreen) draw() {
10401053
// write out any data queued thus far
10411054
// because we are going to skip over some
10421055
// cells, or because we need to change styles
1043-
s.writeString(lx, ly, lstyle, wcs)
1056+
s.writeString(lx, ly, lstyle, vtBuf, wcs)
10441057
wcs = buf[0:0]
10451058
lstyle = StyleDefault
10461059
if !dirty {
@@ -1067,7 +1080,7 @@ func (s *cScreen) draw() {
10671080
}
10681081
x += width - 1
10691082
}
1070-
s.writeString(lx, ly, lstyle, wcs)
1083+
s.writeString(lx, ly, lstyle, vtBuf, wcs)
10711084
wcs = buf[0:0]
10721085
lstyle = styleInvalid
10731086
}

0 commit comments

Comments
 (0)