mirror of https://github.com/Hilbis/Hilbish
Compare commits
2 Commits
577f00dfef
...
2fb481c4cb
Author | SHA1 | Date |
---|---|---|
TorchedSammy | 2fb481c4cb | |
TorchedSammy | 6ea25a22b3 |
14
api.go
14
api.go
|
@ -28,6 +28,7 @@ var exports = map[string]lua.LGFunction {
|
||||||
"exec": hlexec,
|
"exec": hlexec,
|
||||||
"runnerMode": hlrunnerMode,
|
"runnerMode": hlrunnerMode,
|
||||||
"goro": hlgoro,
|
"goro": hlgoro,
|
||||||
|
"hinter": hlhinter,
|
||||||
"multiprompt": hlmlprompt,
|
"multiprompt": hlmlprompt,
|
||||||
"prependPath": hlprependPath,
|
"prependPath": hlprependPath,
|
||||||
"prompt": hlprompt,
|
"prompt": hlprompt,
|
||||||
|
@ -503,3 +504,16 @@ func hlrunnerMode(L *lua.LState) int {
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hinter(cb)
|
||||||
|
// Sets the hinter function. This will be called on every key insert to determine
|
||||||
|
// what text to use as an inline hint. The callback is passed 2 arguments:
|
||||||
|
// the current line and the position. It is expected to return a string
|
||||||
|
// which will be used for the hint.
|
||||||
|
// --- @param cb function
|
||||||
|
func hlhinter(L *lua.LState) int {
|
||||||
|
hinterCb := L.CheckFunction(1)
|
||||||
|
hinter = hinterCb
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,11 @@ exec(cmd) > Replaces running hilbish with `cmd`
|
||||||
|
|
||||||
goro(fn) > Puts `fn` in a goroutine
|
goro(fn) > Puts `fn` in a goroutine
|
||||||
|
|
||||||
|
hinter(cb) > Sets the hinter function. This will be called on every key insert to determine
|
||||||
|
what text to use as an inline hint. The callback is passed 2 arguments:
|
||||||
|
the current line and the position. It is expected to return a string
|
||||||
|
which will be used for the hint.
|
||||||
|
|
||||||
inputMode(mode) > Sets the input mode for Hilbish's line reader. Accepts either emacs for vim
|
inputMode(mode) > Sets the input mode for Hilbish's line reader. Accepts either emacs for vim
|
||||||
|
|
||||||
interval(cb, time) > Runs the `cb` function every `time` milliseconds
|
interval(cb, time) > Runs the `cb` function every `time` milliseconds
|
||||||
|
|
|
@ -33,6 +33,13 @@ function hilbish.exec(cmd) end
|
||||||
--- @param fn function
|
--- @param fn function
|
||||||
function hilbish.goro(fn) end
|
function hilbish.goro(fn) end
|
||||||
|
|
||||||
|
--- Sets the hinter function. This will be called on every key insert to determine
|
||||||
|
--- what text to use as an inline hint. The callback is passed 2 arguments:
|
||||||
|
--- the current line and the position. It is expected to return a string
|
||||||
|
--- which will be used for the hint.
|
||||||
|
--- @param cb function
|
||||||
|
function hilbish.hinter(cb) end
|
||||||
|
|
||||||
--- Sets the input mode for Hilbish's line reader. Accepts either emacs for vim
|
--- Sets the input mode for Hilbish's line reader. Accepts either emacs for vim
|
||||||
--- @param mode string
|
--- @param mode string
|
||||||
function hilbish.inputMode(mode) end
|
function hilbish.inputMode(mode) end
|
||||||
|
|
|
@ -7,7 +7,7 @@ type EventReturn struct {
|
||||||
ForwardKey bool
|
ForwardKey bool
|
||||||
ClearHelpers bool
|
ClearHelpers bool
|
||||||
CloseReadline bool
|
CloseReadline bool
|
||||||
HintText []rune
|
InfoText []rune
|
||||||
NewLine []rune
|
NewLine []rune
|
||||||
NewPos int
|
NewPos int
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,12 @@ import "regexp"
|
||||||
|
|
||||||
// SetHintText - a nasty function to force writing a new hint text. It does not update helpers, it just renders
|
// SetHintText - a nasty function to force writing a new hint text. It does not update helpers, it just renders
|
||||||
// them, so the hint will survive until the helpers (thus including the hint) will be updated/recomputed.
|
// them, so the hint will survive until the helpers (thus including the hint) will be updated/recomputed.
|
||||||
|
/*
|
||||||
func (rl *Instance) SetHintText(s string) {
|
func (rl *Instance) SetHintText(s string) {
|
||||||
rl.hintText = []rune(s)
|
rl.hintText = []rune(s)
|
||||||
rl.renderHelpers()
|
rl.renderHelpers()
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (rl *Instance) getHintText() {
|
func (rl *Instance) getHintText() {
|
||||||
|
|
||||||
|
@ -27,7 +29,7 @@ func (rl *Instance) getHintText() {
|
||||||
// writeHintText - only writes the hint text and computes its offsets.
|
// writeHintText - only writes the hint text and computes its offsets.
|
||||||
func (rl *Instance) writeHintText() {
|
func (rl *Instance) writeHintText() {
|
||||||
if len(rl.hintText) == 0 {
|
if len(rl.hintText) == 0 {
|
||||||
rl.hintY = 0
|
//rl.hintY = 0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,16 +43,16 @@ func (rl *Instance) writeHintText() {
|
||||||
|
|
||||||
wrapped, hintLen := WrapText(string(rl.hintText), width)
|
wrapped, hintLen := WrapText(string(rl.hintText), width)
|
||||||
offset += hintLen
|
offset += hintLen
|
||||||
rl.hintY = offset
|
// rl.hintY = offset
|
||||||
|
|
||||||
hintText := string(wrapped)
|
hintText := string(wrapped)
|
||||||
|
|
||||||
if len(hintText) > 0 {
|
if len(hintText) > 0 {
|
||||||
print("\r" + rl.HintFormatting + string(hintText) + seqReset)
|
print(rl.HintFormatting + string(hintText) + seqReset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rl *Instance) resetHintText() {
|
func (rl *Instance) resetHintText() {
|
||||||
rl.hintY = 0
|
//rl.hintY = 0
|
||||||
rl.hintText = []rune{}
|
rl.hintText = []rune{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,13 +183,13 @@ func (rl *Instance) completeHistory() (hist []*CompletionGroup) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
history = rl.altHistory
|
history = rl.altHistory
|
||||||
rl.histHint = []rune(rl.altHistName + ": ")
|
rl.histInfo = []rune(rl.altHistName + ": ")
|
||||||
} else {
|
} else {
|
||||||
if rl.mainHistory == nil {
|
if rl.mainHistory == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
history = rl.mainHistory
|
history = rl.mainHistory
|
||||||
rl.histHint = []rune(rl.mainHistName + ": ")
|
rl.histInfo = []rune(rl.mainHistName + ": ")
|
||||||
}
|
}
|
||||||
|
|
||||||
hist[0].init(rl)
|
hist[0].init(rl)
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package readline
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
// SetInfoText - a nasty function to force writing a new info text. It does not update helpers, it just renders
|
||||||
|
// them, so the info will survive until the helpers (thus including the info) will be updated/recomputed.
|
||||||
|
func (rl *Instance) SetInfoText(s string) {
|
||||||
|
rl.infoText = []rune(s)
|
||||||
|
rl.renderHelpers()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *Instance) getInfoText() {
|
||||||
|
|
||||||
|
if !rl.modeAutoFind && !rl.modeTabFind {
|
||||||
|
// Return if no infos provided by the user/engine
|
||||||
|
if rl.InfoText == nil {
|
||||||
|
rl.resetInfoText()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// The info text also works with the virtual completion line system.
|
||||||
|
// This way, the info is also refreshed depending on what we are pointing
|
||||||
|
// at with our cursor.
|
||||||
|
rl.infoText = rl.InfoText(rl.getCompletionLine())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeInfoText - only writes the info text and computes its offsets.
|
||||||
|
func (rl *Instance) writeInfoText() {
|
||||||
|
if len(rl.infoText) == 0 {
|
||||||
|
rl.infoY = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
width := GetTermWidth()
|
||||||
|
|
||||||
|
// Wraps the line, and counts the number of newlines in the string,
|
||||||
|
// adjusting the offset as well.
|
||||||
|
re := regexp.MustCompile(`\r?\n`)
|
||||||
|
newlines := re.Split(string(rl.infoText), -1)
|
||||||
|
offset := len(newlines)
|
||||||
|
|
||||||
|
wrapped, infoLen := WrapText(string(rl.infoText), width)
|
||||||
|
offset += infoLen
|
||||||
|
rl.infoY = offset
|
||||||
|
|
||||||
|
infoText := string(wrapped)
|
||||||
|
|
||||||
|
if len(infoText) > 0 {
|
||||||
|
print("\r" + rl.InfoFormatting + string(infoText) + seqReset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *Instance) resetInfoText() {
|
||||||
|
rl.infoY = 0
|
||||||
|
rl.infoText = []rune{}
|
||||||
|
}
|
|
@ -110,7 +110,7 @@ type Instance struct {
|
||||||
searchMode FindMode // Used for varying hints, and underlying functions called
|
searchMode FindMode // Used for varying hints, and underlying functions called
|
||||||
regexSearch *regexp.Regexp // Holds the current search regex match
|
regexSearch *regexp.Regexp // Holds the current search regex match
|
||||||
mainHist bool // Which history stdin do we want
|
mainHist bool // Which history stdin do we want
|
||||||
histHint []rune // We store a hist hint, for dual history sources
|
histInfo []rune // We store a piece of hist info, for dual history sources
|
||||||
|
|
||||||
//
|
//
|
||||||
// History -----------------------------------------------------------------------------------
|
// History -----------------------------------------------------------------------------------
|
||||||
|
@ -134,19 +134,33 @@ type Instance struct {
|
||||||
histNavIdx int // Used for quick history navigation.
|
histNavIdx int // Used for quick history navigation.
|
||||||
|
|
||||||
//
|
//
|
||||||
// Hints -------------------------------------------------------------------------------------
|
// Info -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// HintText is a helper function which displays hint text the prompt.
|
// InfoText is a helper function which displays infio text below the prompt.
|
||||||
// HintText takes the line input from the promt and the cursor position.
|
// InfoText takes the line input from the prompt and the cursor position.
|
||||||
|
// It returns the info text to display.
|
||||||
|
InfoText func([]rune, int) []rune
|
||||||
|
|
||||||
|
// InfoColor is any ANSI escape codes you wish to use for info formatting. By
|
||||||
|
// default this will just be blue.
|
||||||
|
InfoFormatting string
|
||||||
|
|
||||||
|
infoText []rune // The actual info text
|
||||||
|
infoY int // Offset to info, if it spans multiple lines
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hints -----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// HintText is a helper function which displays hint text right after the user's input.
|
||||||
|
// It takes the line input and cursor position.
|
||||||
// It returns the hint text to display.
|
// It returns the hint text to display.
|
||||||
HintText func([]rune, int) []rune
|
HintText func([]rune, int) []rune
|
||||||
|
|
||||||
// HintColor any ANSI escape codes you wish to use for hint formatting. By
|
// HintFormatting is just a string to use as the formatting for the hint. By default
|
||||||
// default this will just be blue.
|
// this will be a grey color.
|
||||||
HintFormatting string
|
HintFormatting string
|
||||||
|
|
||||||
hintText []rune // The actual hint text
|
hintText []rune
|
||||||
hintY int // Offset to hints, if it spans multiple lines
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Vim Operatng Parameters -------------------------------------------------------------------
|
// Vim Operatng Parameters -------------------------------------------------------------------
|
||||||
|
@ -205,7 +219,8 @@ func NewInstance() *Instance {
|
||||||
rl.HistoryAutoWrite = true
|
rl.HistoryAutoWrite = true
|
||||||
|
|
||||||
// Others
|
// Others
|
||||||
rl.HintFormatting = seqFgBlue
|
rl.InfoFormatting = seqFgBlue
|
||||||
|
rl.HintFormatting = "\x1b[2m"
|
||||||
rl.evtKeyPress = make(map[string]func(string, []rune, int) *EventReturn)
|
rl.evtKeyPress = make(map[string]func(string, []rune, int) *EventReturn)
|
||||||
rl.TempDirectory = os.TempDir()
|
rl.TempDirectory = os.TempDir()
|
||||||
|
|
||||||
|
|
|
@ -57,9 +57,9 @@ func (rl *Instance) echo() {
|
||||||
|
|
||||||
// Print the input line with optional syntax highlighting
|
// Print the input line with optional syntax highlighting
|
||||||
if rl.SyntaxHighlighter != nil {
|
if rl.SyntaxHighlighter != nil {
|
||||||
print(rl.SyntaxHighlighter(line) + " ")
|
print(rl.SyntaxHighlighter(line))
|
||||||
} else {
|
} else {
|
||||||
print(string(line) + " ")
|
print(string(line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ func (rl *Instance) RefreshPromptLog(log string) (err error) {
|
||||||
// We adjust cursor movement, depending on which mode we're currently in.
|
// We adjust cursor movement, depending on which mode we're currently in.
|
||||||
if !rl.modeTabCompletion {
|
if !rl.modeTabCompletion {
|
||||||
rl.tcUsedY = 1
|
rl.tcUsedY = 1
|
||||||
// Account for the hint line
|
// Account for the info line
|
||||||
} else if rl.modeTabCompletion && rl.modeAutoFind {
|
} else if rl.modeTabCompletion && rl.modeAutoFind {
|
||||||
rl.tcUsedY = 0
|
rl.tcUsedY = 0
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,7 +40,7 @@ func (rl *Instance) RefreshPromptLog(log string) (err error) {
|
||||||
moveCursorUp(1)
|
moveCursorUp(1)
|
||||||
}
|
}
|
||||||
rl.stillOnRefresh = true
|
rl.stillOnRefresh = true
|
||||||
moveCursorUp(rl.hintY + rl.tcUsedY)
|
moveCursorUp(rl.infoY + rl.tcUsedY)
|
||||||
moveCursorBackwards(GetTermWidth())
|
moveCursorBackwards(GetTermWidth())
|
||||||
print("\r\n" + seqClearScreenBelow)
|
print("\r\n" + seqClearScreenBelow)
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) {
|
||||||
// Prompt data intependent
|
// Prompt data intependent
|
||||||
if !rl.modeTabCompletion {
|
if !rl.modeTabCompletion {
|
||||||
rl.tcUsedY = 1
|
rl.tcUsedY = 1
|
||||||
// Account for the hint line
|
// Account for the info line
|
||||||
} else if rl.modeTabCompletion && rl.modeAutoFind {
|
} else if rl.modeTabCompletion && rl.modeAutoFind {
|
||||||
rl.tcUsedY = 0
|
rl.tcUsedY = 0
|
||||||
} else {
|
} else {
|
||||||
|
@ -91,7 +91,7 @@ func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) {
|
||||||
|
|
||||||
// Clear the input line and everything below
|
// Clear the input line and everything below
|
||||||
print(seqClearLine)
|
print(seqClearLine)
|
||||||
moveCursorUp(rl.hintY + rl.tcUsedY)
|
moveCursorUp(rl.infoY + rl.tcUsedY)
|
||||||
moveCursorBackwards(GetTermWidth())
|
moveCursorBackwards(GetTermWidth())
|
||||||
print("\r\n" + seqClearScreenBelow)
|
print("\r\n" + seqClearScreenBelow)
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ func (rl *Instance) RefreshPromptCustom(prompt string, offset int, clearLine boo
|
||||||
// We adjust cursor movement, depending on which mode we're currently in.
|
// We adjust cursor movement, depending on which mode we're currently in.
|
||||||
if !rl.modeTabCompletion {
|
if !rl.modeTabCompletion {
|
||||||
rl.tcUsedY = 1
|
rl.tcUsedY = 1
|
||||||
} else if rl.modeTabCompletion && rl.modeAutoFind { // Account for the hint line
|
} else if rl.modeTabCompletion && rl.modeAutoFind { // Account for the info line
|
||||||
rl.tcUsedY = 0
|
rl.tcUsedY = 0
|
||||||
} else {
|
} else {
|
||||||
rl.tcUsedY = 1
|
rl.tcUsedY = 1
|
||||||
|
|
|
@ -40,10 +40,10 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
rl.posY = 0
|
rl.posY = 0
|
||||||
rl.tcPrefix = ""
|
rl.tcPrefix = ""
|
||||||
|
|
||||||
// Completion && hints init
|
// Completion && infos init
|
||||||
rl.resetHintText()
|
rl.resetInfoText()
|
||||||
rl.resetTabCompletion()
|
rl.resetTabCompletion()
|
||||||
rl.getHintText()
|
rl.getInfoText()
|
||||||
|
|
||||||
// History Init
|
// History Init
|
||||||
// We need this set to the last command, so that we can access it quickly
|
// We need this set to the last command, so that we can access it quickly
|
||||||
|
@ -63,7 +63,7 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
return string(rl.line), nil
|
return string(rl.line), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, print any hints or completions
|
// Finally, print any info or completions
|
||||||
// if the TabCompletion engines so desires
|
// if the TabCompletion engines so desires
|
||||||
rl.renderHelpers()
|
rl.renderHelpers()
|
||||||
|
|
||||||
|
@ -128,8 +128,8 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
rl.updateHelpers()
|
rl.updateHelpers()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ret.HintText) > 0 {
|
if len(ret.InfoText) > 0 {
|
||||||
rl.hintText = ret.HintText
|
rl.infoText = ret.InfoText
|
||||||
rl.clearHelpers()
|
rl.clearHelpers()
|
||||||
rl.renderHelpers()
|
rl.renderHelpers()
|
||||||
}
|
}
|
||||||
|
@ -174,8 +174,8 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
}
|
}
|
||||||
print(seqClearScreenBelow)
|
print(seqClearScreenBelow)
|
||||||
|
|
||||||
rl.resetHintText()
|
rl.resetInfoText()
|
||||||
rl.getHintText()
|
rl.getInfoText()
|
||||||
rl.renderHelpers()
|
rl.renderHelpers()
|
||||||
|
|
||||||
// Line Editing ------------------------------------------------------------------------------------
|
// Line Editing ------------------------------------------------------------------------------------
|
||||||
|
@ -533,6 +533,7 @@ func (rl *Instance) editorInput(r []rune) {
|
||||||
// We don't need it when inserting text.
|
// We don't need it when inserting text.
|
||||||
rl.histNavIdx = 0
|
rl.histNavIdx = 0
|
||||||
rl.insert(r)
|
rl.insert(r)
|
||||||
|
rl.writeHintText()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rl.multisplit) == 0 {
|
if len(rl.multisplit) == 0 {
|
||||||
|
@ -696,6 +697,7 @@ func (rl *Instance) escapeSeq(r []rune) {
|
||||||
rl.updateHelpers()
|
rl.updateHelpers()
|
||||||
return
|
return
|
||||||
case seqCtrlRightArrow:
|
case seqCtrlRightArrow:
|
||||||
|
rl.insert(rl.hintText)
|
||||||
rl.moveCursorByAdjust(rl.viJumpW(tokeniseLine))
|
rl.moveCursorByAdjust(rl.viJumpW(tokeniseLine))
|
||||||
rl.updateHelpers()
|
rl.updateHelpers()
|
||||||
return
|
return
|
||||||
|
|
|
@ -259,9 +259,9 @@ func (r *registers) resetRegister() {
|
||||||
// The user can show registers completions and insert, no matter the cursor position.
|
// The user can show registers completions and insert, no matter the cursor position.
|
||||||
func (rl *Instance) completeRegisters() (groups []*CompletionGroup) {
|
func (rl *Instance) completeRegisters() (groups []*CompletionGroup) {
|
||||||
|
|
||||||
// We set the hint exceptionally
|
// We set the info exceptionally
|
||||||
hint := BLUE + "-- registers --" + RESET
|
info := BLUE + "-- registers --" + RESET
|
||||||
rl.hintText = []rune(hint)
|
rl.infoText = []rune(info)
|
||||||
|
|
||||||
// Make the groups
|
// Make the groups
|
||||||
anonRegs := &CompletionGroup{
|
anonRegs := &CompletionGroup{
|
||||||
|
|
|
@ -93,16 +93,16 @@ func (rl *Instance) getTabSearchCompletion() {
|
||||||
}
|
}
|
||||||
rl.getCurrentGroup()
|
rl.getCurrentGroup()
|
||||||
|
|
||||||
// Set the hint for this completion mode
|
// Set the info for this completion mode
|
||||||
rl.hintText = append([]rune("Completion search: "), rl.tfLine...)
|
rl.infoText = append([]rune("Completion search: "), rl.tfLine...)
|
||||||
|
|
||||||
for _, g := range rl.tcGroups {
|
for _, g := range rl.tcGroups {
|
||||||
g.updateTabFind(rl)
|
g.updateTabFind(rl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If total number of matches is zero, we directly change the hint, and return
|
// If total number of matches is zero, we directly change the info, and return
|
||||||
if comps, _, _ := rl.getCompletionCount(); comps == 0 {
|
if comps, _, _ := rl.getCompletionCount(); comps == 0 {
|
||||||
rl.hintText = append(rl.hintText, []rune(DIM+RED+" ! no matches (Ctrl-G/Esc to cancel)"+RESET)...)
|
rl.infoText = append(rl.infoText, []rune(DIM+RED+" ! no matches (Ctrl-G/Esc to cancel)"+RESET)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,25 +117,25 @@ func (rl *Instance) getHistorySearchCompletion() {
|
||||||
rl.tcGroups = checkNilItems(rl.tcGroups) // Avoid nil maps in groups
|
rl.tcGroups = checkNilItems(rl.tcGroups) // Avoid nil maps in groups
|
||||||
rl.getCurrentGroup() // Make sure there is a current group
|
rl.getCurrentGroup() // Make sure there is a current group
|
||||||
|
|
||||||
// The history hint is already set, but overwrite it if we don't have completions
|
// The history info is already set, but overwrite it if we don't have completions
|
||||||
if len(rl.tcGroups[0].Suggestions) == 0 {
|
if len(rl.tcGroups[0].Suggestions) == 0 {
|
||||||
rl.histHint = []rune(fmt.Sprintf("%s%s%s %s", DIM, RED,
|
rl.histInfo = []rune(fmt.Sprintf("%s%s%s %s", DIM, RED,
|
||||||
"No command history source, or empty (Ctrl-G/Esc to cancel)", RESET))
|
"No command history source, or empty (Ctrl-G/Esc to cancel)", RESET))
|
||||||
rl.hintText = rl.histHint
|
rl.infoText = rl.histInfo
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the hint line with everything
|
// Set the info line with everything
|
||||||
rl.histHint = append([]rune("\033[38;5;183m"+string(rl.histHint)+RESET), rl.tfLine...)
|
rl.histInfo = append([]rune("\033[38;5;183m"+string(rl.histInfo)+RESET), rl.tfLine...)
|
||||||
rl.histHint = append(rl.histHint, []rune(RESET)...)
|
rl.histInfo = append(rl.histInfo, []rune(RESET)...)
|
||||||
rl.hintText = rl.histHint
|
rl.infoText = rl.histInfo
|
||||||
|
|
||||||
// Refresh filtered candidates
|
// Refresh filtered candidates
|
||||||
rl.tcGroups[0].updateTabFind(rl)
|
rl.tcGroups[0].updateTabFind(rl)
|
||||||
|
|
||||||
// If no items matched history, add hint text that we failed to search
|
// If no items matched history, add info text that we failed to search
|
||||||
if len(rl.tcGroups[0].Suggestions) == 0 {
|
if len(rl.tcGroups[0].Suggestions) == 0 {
|
||||||
rl.hintText = append(rl.histHint, []rune(DIM+RED+" ! no matches (Ctrl-G/Esc to cancel)"+RESET)...)
|
rl.infoText = append(rl.histInfo, []rune(DIM+RED+" ! no matches (Ctrl-G/Esc to cancel)"+RESET)...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,15 +298,15 @@ func (rl *Instance) cropCompletions(comps string) (cropped string, usedY int) {
|
||||||
// Else we go on, but we have more comps than what allowed:
|
// Else we go on, but we have more comps than what allowed:
|
||||||
// we will add a line to the end of the comps, giving the actualized
|
// we will add a line to the end of the comps, giving the actualized
|
||||||
// number of completions remaining and not printed
|
// number of completions remaining and not printed
|
||||||
var moreComps = func(cropped string, offset int) (hinted string, noHint bool) {
|
var moreComps = func(cropped string, offset int) (infoed string, noInfo bool) {
|
||||||
_, _, adjusted := rl.getCompletionCount()
|
_, _, adjusted := rl.getCompletionCount()
|
||||||
remain := adjusted - offset
|
remain := adjusted - offset
|
||||||
if remain == 0 {
|
if remain == 0 {
|
||||||
return cropped, true
|
return cropped, true
|
||||||
}
|
}
|
||||||
hint := fmt.Sprintf(DIM+YELLOW+" %d more completions... (scroll down to show)"+RESET+"\n", remain)
|
info := fmt.Sprintf(DIM+YELLOW+" %d more completions... (scroll down to show)"+RESET+"\n", remain)
|
||||||
hinted = cropped + hint
|
infoed = cropped + info
|
||||||
return hinted, false
|
return infoed, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current absolute candidate position (prev groups x suggestions + curGroup.tcPosY)
|
// Get the current absolute candidate position (prev groups x suggestions + curGroup.tcPosY)
|
||||||
|
@ -509,7 +509,7 @@ func (rl *Instance) hasOneCandidate() bool {
|
||||||
// - The terminal lengh
|
// - The terminal lengh
|
||||||
// we use this function to prompt for confirmation before printing comps.
|
// we use this function to prompt for confirmation before printing comps.
|
||||||
func (rl *Instance) promptCompletionConfirm(sentence string) {
|
func (rl *Instance) promptCompletionConfirm(sentence string) {
|
||||||
rl.hintText = []rune(sentence)
|
rl.infoText = []rune(sentence)
|
||||||
|
|
||||||
rl.compConfirmWait = true
|
rl.compConfirmWait = true
|
||||||
rl.viUndoSkipAppend = true
|
rl.viUndoSkipAppend = true
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (rl *Instance) updateTabFind(r []rune) {
|
||||||
var err error
|
var err error
|
||||||
rl.regexSearch, err = regexp.Compile("(?i)" + string(rl.tfLine))
|
rl.regexSearch, err = regexp.Compile("(?i)" + string(rl.tfLine))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rl.hintText = []rune(Red("Failed to match search regexp"))
|
rl.infoText = []rune(Red("Failed to match search regexp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// We update and print
|
// We update and print
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package readline
|
package readline
|
||||||
|
|
||||||
// updateHelpers is a key part of the whole refresh process:
|
// updateHelpers is a key part of the whole refresh process:
|
||||||
// it should coordinate reprinting the input line, any hints and completions
|
// it should coordinate reprinting the input line, any Infos and completions
|
||||||
// and manage to get back to the current (computed) cursor coordinates
|
// and manage to get back to the current (computed) cursor coordinates
|
||||||
func (rl *Instance) updateHelpers() {
|
func (rl *Instance) updateHelpers() {
|
||||||
|
|
||||||
// Load all hints & completions before anything.
|
// Load all Infos & completions before anything.
|
||||||
// Thus overwrites anything having been dirtily added/forced/modified, like rl.SetHintText()
|
// Thus overwrites anything having been dirtily added/forced/modified, like rl.SetInfoText()
|
||||||
|
rl.getInfoText()
|
||||||
rl.getHintText()
|
rl.getHintText()
|
||||||
if rl.modeTabCompletion {
|
if rl.modeTabCompletion {
|
||||||
rl.getTabCompletion()
|
rl.getTabCompletion()
|
||||||
|
@ -75,11 +76,11 @@ func (rl *Instance) resetHelpers() {
|
||||||
rl.modeAutoFind = false
|
rl.modeAutoFind = false
|
||||||
|
|
||||||
// Now reset all below-input helpers
|
// Now reset all below-input helpers
|
||||||
rl.resetHintText()
|
rl.resetInfoText()
|
||||||
rl.resetTabCompletion()
|
rl.resetTabCompletion()
|
||||||
}
|
}
|
||||||
|
|
||||||
// clearHelpers - Clears everything: prompt, input, hints & comps,
|
// clearHelpers - Clears everything: prompt, input, Infos & comps,
|
||||||
// and comes back at the prompt.
|
// and comes back at the prompt.
|
||||||
func (rl *Instance) clearHelpers() {
|
func (rl *Instance) clearHelpers() {
|
||||||
|
|
||||||
|
@ -97,25 +98,40 @@ func (rl *Instance) clearHelpers() {
|
||||||
moveCursorForwards(rl.posX)
|
moveCursorForwards(rl.posX)
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderHelpers - pritns all components (prompt, line, hints & comps)
|
// renderHelpers - pritns all components (prompt, line, Infos & comps)
|
||||||
// and replaces the cursor to its current position. This function never
|
// and replaces the cursor to its current position. This function never
|
||||||
// computes or refreshes any value, except from inside the echo function.
|
// computes or refreshes any value, except from inside the echo function.
|
||||||
func (rl *Instance) renderHelpers() {
|
func (rl *Instance) renderHelpers() {
|
||||||
|
|
||||||
// Optional, because neutral on placement
|
// 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()
|
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, do nothing here
|
||||||
|
} else {
|
||||||
|
rl.writeHintText()
|
||||||
|
}
|
||||||
|
|
||||||
// Go at beginning of first line after input remainder
|
// Go at beginning of first line after input remainder
|
||||||
moveCursorDown(rl.fullY - rl.posY)
|
moveCursorDown(rl.fullY - rl.posY)
|
||||||
moveCursorBackwards(GetTermWidth())
|
moveCursorBackwards(GetTermWidth())
|
||||||
|
|
||||||
// Print hints, check for any confirmation hint current.
|
// Print Infos, check for any confirmation Info current.
|
||||||
// (do not overwrite the confirmation question hint)
|
// (do not overwrite the confirmation question Info)
|
||||||
if !rl.compConfirmWait {
|
if !rl.compConfirmWait {
|
||||||
if len(rl.hintText) > 0 {
|
if len(rl.infoText) > 0 {
|
||||||
print("\n")
|
print("\n")
|
||||||
}
|
}
|
||||||
rl.writeHintText()
|
rl.writeInfoText()
|
||||||
moveCursorBackwards(GetTermWidth())
|
moveCursorBackwards(GetTermWidth())
|
||||||
|
|
||||||
// Print completions and go back to beginning of this line
|
// Print completions and go back to beginning of this line
|
||||||
|
@ -126,17 +142,17 @@ func (rl *Instance) renderHelpers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are still waiting for the user to confirm too long completions
|
// If we are still waiting for the user to confirm too long completions
|
||||||
// Immediately refresh the hints
|
// Immediately refresh the Infos
|
||||||
if rl.compConfirmWait {
|
if rl.compConfirmWait {
|
||||||
print("\n")
|
print("\n")
|
||||||
rl.writeHintText()
|
rl.writeInfoText()
|
||||||
rl.getHintText()
|
rl.getInfoText()
|
||||||
moveCursorBackwards(GetTermWidth())
|
moveCursorBackwards(GetTermWidth())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anyway, compensate for hint printout
|
// Anyway, compensate for Info printout
|
||||||
if len(rl.hintText) > 0 {
|
if len(rl.infoText) > 0 {
|
||||||
moveCursorUp(rl.hintY)
|
moveCursorUp(rl.infoY)
|
||||||
} else if !rl.compConfirmWait {
|
} else if !rl.compConfirmWait {
|
||||||
moveCursorUp(1)
|
moveCursorUp(1)
|
||||||
} else if rl.compConfirmWait {
|
} else if rl.compConfirmWait {
|
||||||
|
|
|
@ -399,22 +399,22 @@ func (rl *Instance) refreshVimStatus() {
|
||||||
rl.updateHelpers()
|
rl.updateHelpers()
|
||||||
}
|
}
|
||||||
|
|
||||||
// viHintMessage - lmorg's way of showing Vim status is to overwrite the hint.
|
// viInfoMessage - lmorg's way of showing Vim status is to overwrite the info.
|
||||||
// Currently not used, as there is a possibility to show the current Vim mode in the prompt.
|
// Currently not used, as there is a possibility to show the current Vim mode in the prompt.
|
||||||
func (rl *Instance) viHintMessage() {
|
func (rl *Instance) viInfoMessage() {
|
||||||
switch rl.modeViMode {
|
switch rl.modeViMode {
|
||||||
case VimKeys:
|
case VimKeys:
|
||||||
rl.hintText = []rune("-- VIM KEYS -- (press `i` to return to normal editing mode)")
|
rl.infoText = []rune("-- VIM KEYS -- (press `i` to return to normal editing mode)")
|
||||||
case VimInsert:
|
case VimInsert:
|
||||||
rl.hintText = []rune("-- INSERT --")
|
rl.infoText = []rune("-- INSERT --")
|
||||||
case VimReplaceOnce:
|
case VimReplaceOnce:
|
||||||
rl.hintText = []rune("-- REPLACE CHARACTER --")
|
rl.infoText = []rune("-- REPLACE CHARACTER --")
|
||||||
case VimReplaceMany:
|
case VimReplaceMany:
|
||||||
rl.hintText = []rune("-- REPLACE --")
|
rl.infoText = []rune("-- REPLACE --")
|
||||||
case VimDelete:
|
case VimDelete:
|
||||||
rl.hintText = []rune("-- DELETE --")
|
rl.infoText = []rune("-- DELETE --")
|
||||||
default:
|
default:
|
||||||
rl.getHintText()
|
rl.getInfoText()
|
||||||
}
|
}
|
||||||
|
|
||||||
rl.clearHelpers()
|
rl.clearHelpers()
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (rl *Instance) viDelete(r rune) {
|
||||||
rl.saveBufToRegister(rl.line)
|
rl.saveBufToRegister(rl.line)
|
||||||
rl.clearLine()
|
rl.clearLine()
|
||||||
rl.resetHelpers()
|
rl.resetHelpers()
|
||||||
rl.getHintText()
|
rl.getInfoText()
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
vii := rl.getViIterations()
|
vii := rl.getViIterations()
|
||||||
|
|
24
rl.go
24
rl.go
|
@ -13,6 +13,7 @@ type lineReader struct {
|
||||||
rl *readline.Instance
|
rl *readline.Instance
|
||||||
}
|
}
|
||||||
var fileHist *fileHistory
|
var fileHist *fileHistory
|
||||||
|
var hinter lua.LValue
|
||||||
|
|
||||||
// other gophers might hate this naming but this is local, shut up
|
// other gophers might hate this naming but this is local, shut up
|
||||||
func newLineReader(prompt string, noHist bool) *lineReader {
|
func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
|
@ -44,6 +45,25 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
}
|
}
|
||||||
hooks.Em.Emit("hilbish.vimAction", actionStr, args)
|
hooks.Em.Emit("hilbish.vimAction", actionStr, args)
|
||||||
}
|
}
|
||||||
|
rl.HintText = func(line []rune, pos int) []rune {
|
||||||
|
err := l.CallByParam(lua.P{
|
||||||
|
Fn: hinter,
|
||||||
|
NRet: 1,
|
||||||
|
Protect: true,
|
||||||
|
}, lua.LString(string(line)), lua.LNumber(pos))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return []rune{}
|
||||||
|
}
|
||||||
|
|
||||||
|
retVal := l.Get(-1)
|
||||||
|
hintText := ""
|
||||||
|
if luaStr, ok := retVal.(lua.LString); retVal != lua.LNil && ok {
|
||||||
|
hintText = luaStr.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return []rune(hintText)
|
||||||
|
}
|
||||||
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) {
|
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) {
|
||||||
ctx := string(line)
|
ctx := string(line)
|
||||||
var completions []string
|
var completions []string
|
||||||
|
@ -253,7 +273,7 @@ func (lr *lineReader) luaGetHistory(L *lua.LState) int {
|
||||||
cmd, _ := fileHist.GetLine(idx)
|
cmd, _ := fileHist.GetLine(idx)
|
||||||
L.Push(lua.LString(cmd))
|
L.Push(lua.LString(cmd))
|
||||||
|
|
||||||
return 0
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaAllHistory(L *lua.LState) int {
|
func (lr *lineReader) luaAllHistory(L *lua.LState) int {
|
||||||
|
@ -267,7 +287,7 @@ func (lr *lineReader) luaAllHistory(L *lua.LState) int {
|
||||||
|
|
||||||
L.Push(tbl)
|
L.Push(tbl)
|
||||||
|
|
||||||
return 0
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaClearHistory(l *lua.LState) int {
|
func (lr *lineReader) luaClearHistory(l *lua.LState) int {
|
||||||
|
|
Loading…
Reference in New Issue