package display
import (
"fmt"
"github.com/reeflective/readline/inputrc"
"github.com/reeflective/readline/internal/color"
"github.com/reeflective/readline/internal/completion"
"github.com/reeflective/readline/internal/core"
"github.com/reeflective/readline/internal/history"
"github.com/reeflective/readline/internal/strutil"
"github.com/reeflective/readline/internal/term"
"github.com/reeflective/readline/internal/ui"
)
var (
oneThirdTerminalHeight = 3
halfTerminalHeight = 2
)
type Engine struct {
highlighter func (line []rune ) string
startCols int
startRows int
lineCol int
lineRows int
cursorRow int
cursorCol int
hintRows int
compRows int
primaryPrinted bool
keys *core .Keys
line *core .Line
suggested core .Line
cursor *core .Cursor
selection *core .Selection
histories *history .Sources
prompt *ui .Prompt
hint *ui .Hint
completer *completion .Engine
opts *inputrc .Config
}
func NewEngine (k *core .Keys , s *core .Selection , h *history .Sources , p *ui .Prompt , i *ui .Hint , c *completion .Engine , opts *inputrc .Config ) *Engine {
return &Engine {
keys : k ,
selection : s ,
histories : h ,
prompt : p ,
hint : i ,
completer : c ,
opts : opts ,
}
}
func Init (e *Engine , highlighter func ([]rune ) string ) {
e .highlighter = highlighter
}
func (e *Engine ) Refresh () {
fmt .Print (term .HideCursor )
term .MoveCursorBackwards (term .GetWidth ())
if !e .primaryPrinted {
term .MoveCursorUp (e .cursorRow )
}
e .prompt .LastPrint ()
e .computeCoordinates (true )
e .displayLine ()
e .displayMultilinePrompts ()
e .displayHelpers ()
e .cursorHintToLineStart ()
e .lineStartToCursorPos ()
fmt .Print (term .ShowCursor )
}
func (e *Engine ) PrintPrimaryPrompt () {
e .prompt .PrimaryPrint ()
e .primaryPrinted = true
}
func (e *Engine ) ClearHelpers () {
e .CursorBelowLine ()
fmt .Print (term .ClearScreenBelow )
term .MoveCursorUp (1 )
term .MoveCursorUp (e .lineRows )
term .MoveCursorDown (e .cursorRow )
term .MoveCursorForwards (e .cursorCol )
}
func (e *Engine ) ResetHelpers () {
e .hint .Reset ()
e .completer .ClearMenu (true )
}
func (e *Engine ) AcceptLine () {
e .CursorToLineStart ()
e .computeCoordinates (false )
term .MoveCursorBackwards (term .GetWidth ())
term .MoveCursorDown (e .lineRows )
term .MoveCursorForwards (e .lineCol )
fmt .Print (term .ClearScreenBelow )
e .prompt .RightPrint (e .lineCol , false )
term .MoveCursorBackwards (term .GetWidth ())
fmt .Print (term .NewlineReturn )
}
func (e *Engine ) RefreshTransient () {
if !e .opts .GetBool ("prompt-transient" ) {
return
}
e .CursorToLineStart ()
term .MoveCursorUp (e .prompt .PrimaryUsed ())
e .prompt .TransientPrint ()
e .displayLine ()
fmt .Print (term .NewlineReturn )
}
func (e *Engine ) CursorToLineStart () {
term .MoveCursorBackwards (e .cursorCol )
term .MoveCursorUp (e .cursorRow )
term .MoveCursorForwards (e .startCols )
}
func (e *Engine ) CursorBelowLine () {
term .MoveCursorUp (e .cursorRow )
term .MoveCursorDown (e .lineRows )
fmt .Print (term .NewlineReturn )
}
func (e *Engine ) lineStartToCursorPos () {
term .MoveCursorDown (e .cursorRow )
term .MoveCursorBackwards (term .GetWidth ())
term .MoveCursorForwards (e .cursorCol )
}
func (e *Engine ) cursorHintToLineStart () {
term .MoveCursorUp (1 )
term .MoveCursorUp (e .lineRows - e .cursorRow )
e .CursorToLineStart ()
}
func (e *Engine ) computeCoordinates (suggested bool ) {
e .line , e .cursor = e .completer .Line ()
if e .completer .IsInserting () {
e .suggested = *e .line
} else {
e .suggested = e .histories .Suggest (e .line )
}
e .startCols , e .startRows = e .keys .GetCursorPos ()
if e .startCols > 0 {
e .startCols --
}
if e .startCols == -1 {
e .startCols = e .prompt .LastUsed ()
}
e .cursorCol , e .cursorRow = core .CoordinatesCursor (e .cursor , e .startCols )
if e .opts .GetBool ("history-autosuggest" ) && suggested {
e .lineCol , e .lineRows = core .CoordinatesLine (&e .suggested , e .startCols )
} else {
e .lineCol , e .lineRows = core .CoordinatesLine (e .line , e .startCols )
}
e .primaryPrinted = false
}
func (e *Engine ) displayLine () {
var line string
if e .highlighter != nil {
line = e .highlighter (*e .line )
} else {
line = string (*e .line )
}
if e .opts .GetBool ("blink-matching-paren" ) {
core .HighlightMatchers (e .selection )
defer core .ResetMatchers (e .selection )
}
line = e .highlightLine ([]rune (line ), *e .selection )
if len (e .suggested ) > e .line .Len () && e .opts .GetBool ("history-autosuggest" ) {
line += color .Dim + color .Fmt (color .Fg +"242" ) + string (e .suggested [e .line .Len ():]) + color .Reset
}
line = strutil .FormatTabs (line ) + term .ClearLineAfter
e .suggested .Set ([]rune (line )...)
core .DisplayLine (&e .suggested , e .startCols )
if e .lineCol == 0 {
fmt .Print (term .NewlineReturn )
fmt .Print (term .ClearLineAfter )
}
}
func (e *Engine ) displayMultilinePrompts () {
if e .line .Lines () > 1 {
term .MoveCursorUp (e .lineRows )
term .MoveCursorBackwards (term .GetWidth ())
e .prompt .MultilineColumnPrint ()
}
if e .line .Lines () > 0 {
term .MoveCursorBackwards (term .GetWidth ())
e .prompt .SecondaryPrint ()
term .MoveCursorBackwards (term .GetWidth ())
term .MoveCursorForwards (e .lineCol )
}
e .prompt .RightPrint (e .lineCol , true )
}
func (e *Engine ) displayHelpers () {
fmt .Print (term .NewlineReturn )
e .completer .Autocomplete ()
ui .DisplayHint (e .hint )
e .hintRows = ui .CoordinatesHint (e .hint )
completion .Display (e .completer , e .AvailableHelperLines ())
e .compRows = completion .Coordinates (e .completer )
term .MoveCursorBackwards (term .GetWidth ())
term .MoveCursorUp (e .compRows )
term .MoveCursorUp (ui .CoordinatesHint (e .hint ))
}
func (e *Engine ) AvailableHelperLines () int {
termHeight := term .GetLength ()
compLines := termHeight - e .startRows - e .lineRows - e .hintRows
if compLines < (termHeight / oneThirdTerminalHeight ) {
compLines = (termHeight / halfTerminalHeight )
}
return compLines
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .