package keymap

import (
	

	
	
)

// Engine is used to manage the main and local keymaps for the shell.
type Engine struct {
	local        Mode
	main         Mode
	prefixed     inputrc.Bind
	active       inputrc.Bind
	pending      []inputrc.Bind
	skip         bool
	isCaller     bool
	nonIncSearch bool

	keys       *core.Keys
	iterations *core.Iterations
	config     *inputrc.Config
	commands   map[string]func()
}

// NewEngine is a required constructor for the keymap modes manager.
// It initializes the keymaps to their defaults or configured values.
func ( *core.Keys,  *core.Iterations,  ...inputrc.Option) (*Engine, *inputrc.Config) {
	 := &Engine{
		main:       Emacs,
		keys:       ,
		iterations: ,
		config:     inputrc.NewDefaultConfig(),
		commands:   make(map[string]func()),
	}

	// Load the inputrc configurations and set up related things.
	.ReloadConfig(...)

	return , .config
}

// Register adds command functions to the list of available commands.
// Each key of the map should be a unique name, not yet used by any
// other builtin/user command, in order not to "overload" the builtins.
func ( *Engine) ( map[string]func()) {
	for ,  := range  {
		.commands[] = 
	}
}

// SetMain sets the main keymap of the shell.
// Valid builtin keymaps are:
// - emacs, emacs-meta, emacs-ctlx, emacs-standard.
// - vi, vi-insert, vi-command, vi-move.
func ( *Engine) ( string) {
	.main = Mode()
	.UpdateCursor()
}

// Main returns the local keymap.
func ( *Engine) () Mode {
	return .main
}

// SetLocal sets the local keymap of the shell.
// Valid builtin keymaps are:
// - vi-opp, vi-visual. (used in commands like yank, change, delete, etc.)
// - isearch, menu-select (used in search and completion).
func ( *Engine) ( string) {
	.local = Mode()
	.UpdateCursor()
}

// Local returns the local keymap.
func ( *Engine) () Mode {
	return .local
}

// ResetLocal deactivates the local keymap of the shell.
func ( *Engine) () {
	.local = ""
	.UpdateCursor()
}

// UpdateCursor reprints the cursor corresponding to the current keymaps.
func ( *Engine) () {
	switch .local {
	case ViOpp:
		.PrintCursor(ViOpp)
		return
	case Visual:
		.PrintCursor(Visual)
		return
	}

	// But if not, we check for the global keymap
	switch .main {
	case Emacs, EmacsStandard, EmacsMeta, EmacsCtrlX:
		.PrintCursor(Emacs)
	case ViInsert:
		.PrintCursor(ViInsert)
	case ViCommand, ViMove, Vi:
		.PrintCursor(ViCommand)
	}
}

// PendingCursor changes the cursor to pending mode,
// and returns a function to call once done with it.
func ( *Engine) () ( func()) {
	.PrintCursor(ViOpp)

	return func() {
		.UpdateCursor()
	}
}

// IsEmacs returns true if the main keymap is one of the emacs modes.
func ( *Engine) () bool {
	switch .main {
	case Emacs, EmacsStandard, EmacsMeta, EmacsCtrlX:
		return true
	default:
		return false
	}
}

// PrintBinds displays a list of currently bound commands (and their sequences)
// to the screen. If inputrcFormat is true, it displays it formatted such that
// the output can be reused in an .inputrc file.
func ( *Engine) ( string,  bool) {
	var  []string

	for  := range .commands {
		 = append(, )
	}

	sort.Strings()

	 := .config.Binds[]
	if  == nil {
		return
	}

	// Make a list of all sequences bound to each command.
	 := make(map[string][]string)

	for ,  := range  {
		for ,  := range  {
			if .Action !=  {
				continue
			}

			 := []
			 = append(, inputrc.Escape())
			[] = 
		}
	}

	if  {
		printBindsInputrc(, )
	} else {
		printBindsReadable(, )
	}
}

// InputIsTerminator returns true when current input keys are one of
// the configured or builtin "terminators", which can be configured
// in .inputrc with the isearch-terminators variable.
func ( *Engine) () bool {
	 := []string{
		inputrc.Unescape(`\C-G`),
		inputrc.Unescape(`\C-]`),
	}

	 := make(map[string]inputrc.Bind)

	for ,  := range  {
		[] = inputrc.Bind{Action: "abort", Macro: false}
	}

	, , ,  := .dispatchKeys()

	return .Action == "abort"
}

// Commands returns the map of all command functions available to the shell.
// This includes the builtin commands (emacs/Vim/history/completion/etc), as
// well as any functions added by the user through Keymap.Register().
// The keys of this map are the names of each corresponding command function.
func ( *Engine) () map[string]func() {
	return .commands
}

// ActiveCommand returns the sequence/command currently being ran.
func ( *Engine) () inputrc.Bind {
	return .active
}

// NonIncrementalSearchStart is used to notify the keymap dispatchers
// that are using a minibuffer, and that the set of valid commands
// should be restrained to a few ones (self-insert/abort/rubout...).
func ( *Engine) () {
	.nonIncSearch = true
}

// NonIncrementalSearchStop notifies the keymap dispatchers
// that we stopped editing a non-incremental search minibuffer.
func ( *Engine) () {
	.nonIncSearch = false
}