package readline

import (
	

	
	
	
	
	
	
	
	
	
	
)

// Shell is the main readline shell instance. It contains all the readline state
// and methods to run the line editor, manage the inputrc configuration, keymaps
// and commands.
// Although each instance contains everything needed to run a line editor, it is
// recommended to use a single instance per application, and to share it between
// all the goroutines that need to read user input.
// Please refer to the README and documentation for more details about the shell
// and its components, and how to use them.
type Shell struct {
	// Core editor
	line       *core.Line       // The input line buffer and its management methods.
	cursor     *core.Cursor     // The cursor and its methods.
	selection  *core.Selection  // The selection manages various visual/pending selections.
	Iterations *core.Iterations // Digit arguments for repeating commands.
	Buffers    *editor.Buffers  // buffers (Vim registers) and methods use/manage/query them.
	Keys       *core.Keys       // Keys is in charge of reading and managing buffered user input.
	Keymap     *keymap.Engine   // Manages main/local keymaps, binds, stores command functions, etc.
	History    *history.Sources // History manages all history types/sources (past commands and undo)
	Macros     *macro.Engine    // Record, use and display macros.

	// User interface
	Config    *inputrc.Config    // Contains all keymaps, binds and per-application settings.
	Opts      []inputrc.Option   // Inputrc file parsing options (app/term/values, etc).
	Prompt    *ui.Prompt         // The prompt engine computes and renders prompt strings.
	Hint      *ui.Hint           // Usage/hints for completion/isearch below the input line.
	completer *completion.Engine // Completions generation and display.
	Display   *display.Engine    // Manages display refresh/update/clearing.

	// User-provided functions

	// AcceptMultiline enables the caller to decide if the shell should keep reading
	// for user input on a new line (therefore, with the secondary prompt), or if it
	// should return the current line at the end of the `rl.Readline()` call.
	// This function should return true if the line is deemed complete (thus asking
	// the shell to return from its Readline() loop), or false if the shell should
	// keep reading input on a newline (thus, insert a newline and read).
	AcceptMultiline func(line []rune) (accept bool)

	// SyntaxHighlighter is a helper function to provide syntax highlighting.
	// Once enabled, set to nil to disable again.
	SyntaxHighlighter func(line []rune) string

	// Completer is a function that produces completions.
	// It takes the readline line ([]rune) and cursor pos as parameters,
	// and returns completions with their associated metadata/settings.
	Completer func(line []rune, cursor int) Completions
}

// NewShell returns a readline shell instance initialized with a default
// inputrc configuration and binds, and with an in-memory command history.
// The constructor accepts an optional list of inputrc configuration options,
// which are used when parsing/loading and applying any inputrc configuration.
func ( ...inputrc.Option) *Shell {
	 := new(Shell)

	// Core editor
	 := new(core.Keys)
	 := new(core.Line)
	 := core.NewCursor()
	 := core.NewSelection(, )
	 := new(core.Iterations)

	.Keys = 
	.line = 
	.cursor = 
	.selection = 
	.Buffers = editor.NewBuffers()
	.Iterations = 

	// Keymaps and commands
	,  := keymap.NewEngine(, , ...)
	.Register(.standardCommands())
	.Register(.viCommands())
	.Register(.historyCommands())
	.Register(.completionCommands())

	.Keymap = 
	.Config = 
	.Opts = 

	// User interface
	 := new(ui.Hint)
	 := ui.NewPrompt(, , , )
	 := macro.NewEngine(, )
	 := history.NewSources(, , , )
	 := completion.NewEngine(, , )
	completion.Init(, , , , , .commandCompletion)

	 := display.NewEngine(, , , , , , )

	.Config = 
	.Hint = 
	.Prompt = 
	.completer = 
	.Macros = 
	.History = 
	.Display = 

	return 
}

// Line is the shell input line buffer.
// Contains methods to search and modify its contents,
// split itself with tokenizers, and displaying itself.
//
// When the shell is in incremental-search mode, this line is the minibuffer.
// The line returned here is thus the input buffer of interest at call time.
func ( *Shell) () *core.Line { return .line }

// Cursor is the cursor position in the current line buffer.
// Contains methods to set, move, describe and check itself.
//
// When the shell is in incremental-search mode, this cursor is the minibuffer's one.
// The cursor returned here is thus the input buffer cursor of interest at call time.
func ( *Shell) () *core.Cursor { return .cursor }

// Selection contains all regions of an input line that are currently selected/marked
// with either a begin and/or end position. The main selection is the visual one, used
// with the default cursor mark and position, and contains a list of additional surround
// selections used to change/select multiple parts of the line at once.
func ( *Shell) () *core.Selection { return .selection }

// Printf prints a formatted string below the current line and redisplays the prompt
// and input line (and possibly completions/hints if active) below the logged string.
// A newline is added to the message so that the prompt is correctly refreshed below.
func ( *Shell) ( string,  ...any) ( int,  error) {
	// First go back to the last line of the input line,
	// and clear everything below (hints and completions).
	.Display.CursorBelowLine()
	term.MoveCursorBackwards(term.GetWidth())
	fmt.Print(term.ClearScreenBelow)

	// Skip a line, and print the formatted message.
	,  = fmt.Printf(+"\n", ...)

	// Redisplay the prompt, input line and active helpers.
	.Prompt.PrimaryPrint()
	.Display.Refresh()

	return
}

// PrintTransientf prints a formatted string in place of the current prompt and input
// line, and then refreshes, or "pushes" the prompt/line below this printed message.
func ( *Shell) ( string,  ...any) ( int,  error) {
	// First go back to the beginning of the line/prompt, and
	// clear everything below (prompt/line/hints/completions).
	.Display.CursorToLineStart()
	term.MoveCursorBackwards(term.GetWidth())
	term.MoveCursorUp(.Prompt.PrimaryUsed())
	fmt.Print(term.ClearScreenBelow)

	// Print the logged message.
	,  = fmt.Printf(+"\n", ...)

	// Redisplay the prompt, input line and active helpers.
	.Prompt.PrimaryPrint()
	.Display.Refresh()

	return
}