Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(readline): flickering on line refresh #288

Merged
merged 4 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased
### Fixed
- Line refresh fixes (less flicker)
- Do more checks for a TTY
- Panic if ENOTTY is thrown from readline
- use `x/term` function to check if a terminal
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module hilbish

go 1.17
go 1.18

require (
github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86
Expand Down
2 changes: 2 additions & 0 deletions readline/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ const (
seqCursorTopLeft = "\x1b[H" // Clears screen and places cursor on top-left

seqGetCursorPos = "\x1b6n" // response: "\x1b{Line};{Column}R"
seqHideCursor = "\x1b[?25l"
seqUnhideCursor = "\x1b[?25h"

seqCtrlLeftArrow = "\x1b[1;5D"
seqCtrlRightArrow = "\x1b[1;5C"
Expand Down
43 changes: 43 additions & 0 deletions readline/cursor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package readline

import (
// "fmt"
"os"
"regexp"
"strconv"
Expand Down Expand Up @@ -68,6 +69,40 @@ func (rl *Instance) getCursorPos() (x int, y int) {
// This means that they are not used to keep any reference point when
// when we internally move around clearning and printing things

/*
func moveCursorUpBuffered(i int) {
if i < 1 {
return
}

fmt.Fprintf(rl.bufferedOut, "\x1b[%dA", i)
}

func moveCursorDownBuffered(i int) {
if i < 1 {
return
}

fmt.Fprintf(rl.bufferedOut, "\x1b[%dB", i)
}

func moveCursorForwardsBuffered(i int) {
if i < 1 {
return
}

fmt.Fprintf(rl.bufferedOut, "\x1b[%dC", i)
}

func moveCursorUpBuffered(i int) {
if i < 1 {
return
}

fmt.Fprintf(rl.bufferedOut, "\x1b[%dD", i)
}
*/

func moveCursorUp(i int) {
if i < 1 {
return
Expand Down Expand Up @@ -100,6 +135,14 @@ func moveCursorBackwards(i int) {
printf("\x1b[%dD", i)
}

func hideCursor() {
print(seqHideCursor)
}

func unhideCursor() {
print(seqUnhideCursor)
}

func (rl *Instance) backspace(forward bool) {
if len(rl.line) == 0 || rl.pos == 0 {
return
Expand Down
2 changes: 1 addition & 1 deletion readline/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/maxlandon/readline

go 1.16
go 1.18

require (
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
Expand Down
5 changes: 5 additions & 0 deletions readline/instance.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package readline

import (
"bufio"
"os"
"regexp"
"sync"
Expand Down Expand Up @@ -203,6 +204,8 @@ type Instance struct {
ViActionCallback func(ViAction, []string)

RawInputCallback func([]rune) // called on all input

bufferedOut *bufio.Writer
}

// NewInstance is used to create a readline instance and initialise it with sane defaults.
Expand Down Expand Up @@ -251,6 +254,8 @@ func NewInstance() *Instance {
return suggs
}

rl.bufferedOut = bufio.NewWriter(os.Stdout)

// Registers
rl.initRegisters()

Expand Down
17 changes: 11 additions & 6 deletions readline/line.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,20 @@ func (rl *Instance) GetLine() []rune {
func (rl *Instance) echo() {

// Then we print the prompt, and the line,
hideCursor()
switch {
case rl.PasswordMask != 0:
case rl.PasswordMask > 0:
print(strings.Repeat(string(rl.PasswordMask), len(rl.line)) + " ")
rl.bufprint(strings.Repeat(string(rl.PasswordMask), len(rl.line)) + " ")

default:

// Go back to prompt position, and clear everything below
moveCursorBackwards(GetTermWidth())
moveCursorUp(rl.posY)
print(seqClearScreenBelow)

// Print the prompt
print(string(rl.realPrompt))
rl.bufprint(string(rl.realPrompt))

// Assemble the line, taking virtual completions into account
var line []rune
Expand All @@ -57,11 +58,14 @@ func (rl *Instance) echo() {

// Print the input line with optional syntax highlighting
if rl.SyntaxHighlighter != nil {
print(rl.SyntaxHighlighter(line))
rl.bufprint(rl.SyntaxHighlighter(line))
} else {
print(string(line))
rl.bufprint(string(line))
}
rl.bufprint(seqClearScreenBelow)

}
rl.bufflush()

// Update references with new coordinates only now, because
// the new line may be longer/shorter than the previous one.
Expand All @@ -72,6 +76,7 @@ func (rl *Instance) echo() {
moveCursorUp(rl.fullY)
moveCursorDown(rl.posY)
moveCursorForwards(rl.posX)
unhideCursor()
}

func (rl *Instance) insert(r []rune) {
Expand Down Expand Up @@ -159,7 +164,7 @@ func (rl *Instance) clearLine() {
moveCursorForwards(rl.promptLen)

// Clear everything after & below the cursor
print(seqClearScreenBelow)
//print(seqClearScreenBelow)

// Real input line
rl.line = []rune{}
Expand Down
6 changes: 3 additions & 3 deletions readline/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (rl *Instance) RefreshPromptLog(log string) (err error) {
rl.stillOnRefresh = true
moveCursorUp(rl.infoY + rl.tcUsedY)
moveCursorBackwards(GetTermWidth())
print("\r\n" + seqClearScreenBelow)
//print("\r\n" + seqClearScreenBelow)

// Print the log
fmt.Printf(log)
Expand Down Expand Up @@ -97,7 +97,7 @@ func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) {
print(seqClearLine)
moveCursorUp(rl.infoY + rl.tcUsedY)
moveCursorBackwards(GetTermWidth())
print("\r\n" + seqClearScreenBelow)
//print("\r\n" + seqClearScreenBelow)

// Add a new line if needed
if rl.Multiline {
Expand Down Expand Up @@ -137,7 +137,7 @@ func (rl *Instance) RefreshPromptCustom(prompt string, offset int, clearLine boo
moveCursorUp(offset)

// Then clear everything below our new position
print(seqClearScreenBelow)
//print(seqClearScreenBelow)

// Update the prompt if a special has been passed.
if prompt != "" {
Expand Down
5 changes: 3 additions & 2 deletions readline/tab.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,14 @@ func (rl *Instance) writeTabCompletion() {
// than what their MaxLength allows them to, cycling sometimes occur,
// but does not fully clears itself: some descriptions are messed up with.
// We always clear the screen as a result, between writings.
print(seqClearScreenBelow)
//rl.bufprint(seqClearScreenBelow)

// Crop the completions so that it fits within our MaxTabCompleterRows
completions, rl.tcUsedY = rl.cropCompletions(completions)

// Then we print all of them.
fmt.Printf(completions)
rl.bufprintF(completions)
rl.bufflush()
}

// cropCompletions - When the user cycles through a completion list longer
Expand Down
18 changes: 16 additions & 2 deletions readline/update.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package readline

import (
"fmt"
"strings"

"golang.org/x/text/width"
Expand All @@ -10,7 +11,7 @@ import (
// it should coordinate reprinting the input line, any Infos and completions
// and manage to get back to the current (computed) cursor coordinates
func (rl *Instance) updateHelpers() {

print(seqHideCursor)
// Load all Infos & completions before anything.
// Thus overwrites anything having been dirtily added/forced/modified, like rl.SetInfoText()
rl.getInfoText()
Expand All @@ -27,6 +28,7 @@ func (rl *Instance) updateHelpers() {
// We are at the prompt line (with the latter
// not printed yet), then reprint everything
rl.renderHelpers()
print(seqUnhideCursor)
}

const tabWidth = 4
Expand Down Expand Up @@ -119,7 +121,7 @@ func (rl *Instance) clearHelpers() {
moveCursorForwards(rl.fullX)

// Clear everything below
print(seqClearScreenBelow)
//print(seqClearScreenBelow)

// Go back to current cursor position
moveCursorBackwards(GetTermWidth())
Expand Down Expand Up @@ -194,3 +196,15 @@ func (rl *Instance) renderHelpers() {
moveCursorUp(rl.fullY - rl.posY)
moveCursorForwards(rl.posX)
}

func (rl *Instance) bufprintF(format string, a ...any) {
fmt.Fprintf(rl.bufferedOut, format, a...)
}

func (rl *Instance) bufprint(text string) {
fmt.Fprint(rl.bufferedOut, text)
}

func (rl *Instance) bufflush() {
rl.bufferedOut.Flush()
}
Loading