mirror of
https://github.com/Hilbis/Hilbish
synced 2025-03-13 18:00:41 +00:00
this does not really fix the issue of multiline input being broken completely, but prevents the prompt being reprinted on input
197 lines
4.8 KiB
Go
197 lines
4.8 KiB
Go
package readline
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"golang.org/x/text/width"
|
|
)
|
|
|
|
// updateHelpers is a key part of the whole refresh process:
|
|
// 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() {
|
|
|
|
// Load all Infos & completions before anything.
|
|
// Thus overwrites anything having been dirtily added/forced/modified, like rl.SetInfoText()
|
|
rl.getInfoText()
|
|
rl.getHintText()
|
|
if rl.modeTabCompletion && !rl.completionOpen {
|
|
rl.getTabCompletion()
|
|
} else {
|
|
if rl.completionOpen { rl.completionOpen = false }
|
|
}
|
|
|
|
// We clear everything
|
|
rl.clearHelpers()
|
|
|
|
// We are at the prompt line (with the latter
|
|
// not printed yet), then reprint everything
|
|
rl.renderHelpers()
|
|
}
|
|
|
|
const tabWidth = 4
|
|
|
|
func getWidth(x []rune) int {
|
|
var w int
|
|
for _, j := range x {
|
|
k := width.LookupRune(j).Kind()
|
|
if j == '\t' {
|
|
w += tabWidth
|
|
} else if k == width.EastAsianWide || k == width.EastAsianFullwidth {
|
|
w += 2
|
|
} else {
|
|
w++
|
|
}
|
|
}
|
|
return w
|
|
}
|
|
|
|
// Update reference should be called only once in a "loop" (not Readline(), but key control loop)
|
|
func (rl *Instance) updateReferences() {
|
|
|
|
// We always need to work with clean data,
|
|
// since we will have incrementers all around
|
|
rl.posX = 0
|
|
rl.fullX = 0
|
|
rl.posY = 0
|
|
rl.fullY = 0
|
|
|
|
var curLine []rune
|
|
if len(rl.currentComp) > 0 {
|
|
curLine = rl.lineComp
|
|
} else {
|
|
curLine = rl.line
|
|
}
|
|
fullLine := getWidth(curLine)
|
|
cPosLine := getWidth(curLine[:rl.pos])
|
|
|
|
// We need the X offset of the whole line
|
|
toEndLine := rl.promptLen + fullLine
|
|
fullOffset := toEndLine / GetTermWidth()
|
|
rl.fullY = fullOffset + strings.Count(string(curLine), "\n")
|
|
fullRest := toEndLine % GetTermWidth()
|
|
rl.fullX = fullRest
|
|
|
|
if fullRest == 0 && fullOffset > 0 {
|
|
print("\n")
|
|
}
|
|
|
|
// Use rl.pos value to get the offset to go TO/FROM the CURRENT POSITION
|
|
lineToCursorPos := rl.promptLen + cPosLine
|
|
offsetToCursor := lineToCursorPos / GetTermWidth()
|
|
cPosRest := lineToCursorPos % GetTermWidth()
|
|
|
|
// If we are at the end of line
|
|
if fullLine == rl.pos {
|
|
rl.posY = fullOffset
|
|
|
|
if fullRest == 0 {
|
|
rl.posX = 0
|
|
} else if fullRest > 0 {
|
|
rl.posX = fullRest
|
|
}
|
|
} else if rl.pos < fullLine {
|
|
// If we are somewhere in the middle of the line
|
|
rl.posY = offsetToCursor
|
|
|
|
if cPosRest == 0 {
|
|
} else if cPosRest > 0 {
|
|
rl.posX = cPosRest
|
|
}
|
|
}
|
|
}
|
|
|
|
func (rl *Instance) resetHelpers() {
|
|
rl.modeAutoFind = false
|
|
|
|
// Now reset all below-input helpers
|
|
rl.resetInfoText()
|
|
rl.resetTabCompletion()
|
|
}
|
|
|
|
// clearHelpers - Clears everything: prompt, input, Infos & comps,
|
|
// and comes back at the prompt.
|
|
func (rl *Instance) clearHelpers() {
|
|
|
|
// Now go down to the last line of input
|
|
moveCursorDown(rl.fullY - rl.posY)
|
|
moveCursorBackwards(rl.posX)
|
|
moveCursorForwards(rl.fullX)
|
|
|
|
// Clear everything below
|
|
print(seqClearScreenBelow)
|
|
|
|
// Go back to current cursor position
|
|
moveCursorBackwards(GetTermWidth())
|
|
moveCursorUp(rl.fullY - rl.posY)
|
|
moveCursorForwards(rl.posX)
|
|
}
|
|
|
|
// renderHelpers - pritns all components (prompt, line, Infos & comps)
|
|
// and replaces the cursor to its current position. This function never
|
|
// computes or refreshes any value, except from inside the echo function.
|
|
func (rl *Instance) renderHelpers() {
|
|
|
|
// when the instance is in this state we want it to be "below" the user's
|
|
// input for it to be aligned properly
|
|
if !rl.compConfirmWait {
|
|
rl.writeHintText()
|
|
}
|
|
rl.echo()
|
|
if rl.modeTabCompletion {
|
|
// in tab complete mode we want it to update
|
|
// when something has been selected
|
|
// (dynamic!!)
|
|
rl.getHintText()
|
|
rl.writeHintText()
|
|
} else if !rl.compConfirmWait {
|
|
// for the same reason above of wanting it below user input, do nothing here
|
|
} else {
|
|
rl.writeHintText()
|
|
}
|
|
|
|
rl.echoRightPrompt()
|
|
|
|
// Go at beginning of first line after input remainder
|
|
moveCursorDown(rl.fullY - rl.posY)
|
|
moveCursorBackwards(GetTermWidth())
|
|
|
|
// Print Infos, check for any confirmation Info current.
|
|
// (do not overwrite the confirmation question Info)
|
|
if !rl.compConfirmWait {
|
|
if len(rl.infoText) > 0 {
|
|
print("\n")
|
|
}
|
|
rl.writeInfoText()
|
|
moveCursorBackwards(GetTermWidth())
|
|
|
|
// Print completions and go back to beginning of this line
|
|
print("\n")
|
|
rl.writeTabCompletion()
|
|
moveCursorBackwards(GetTermWidth())
|
|
moveCursorUp(rl.tcUsedY)
|
|
}
|
|
|
|
// If we are still waiting for the user to confirm too long completions
|
|
// Immediately refresh the Infos
|
|
if rl.compConfirmWait {
|
|
print("\n")
|
|
rl.writeInfoText()
|
|
rl.getInfoText()
|
|
moveCursorBackwards(GetTermWidth())
|
|
}
|
|
|
|
// Anyway, compensate for Info printout
|
|
if len(rl.infoText) > 0 {
|
|
moveCursorUp(rl.infoY)
|
|
} else if !rl.compConfirmWait {
|
|
moveCursorUp(1)
|
|
} else if rl.compConfirmWait {
|
|
moveCursorUp(1)
|
|
}
|
|
|
|
// Go back to current cursor position
|
|
moveCursorUp(rl.fullY - rl.posY)
|
|
moveCursorForwards(rl.posX)
|
|
}
|