package readline

import (
	

	
	
	
)

//
// API ----------------------------------------------------------------
//

// History is an interface to allow you to write your own history logging tools.
// By default readline will just use an in-memory history satisfying this interface,
// which only logs the history to memory ([]string to be precise).
// Users who want an easy to use, file-based history should use NewHistoryFromFile().
type History = history.Source

// NewHistoryFromFile creates a new command history source writing to and reading
// from a file. The caller should bind the history source returned from this call
// to the readline instance, with shell.History.Add().
var NewHistoryFromFile = history.NewSourceFromFile

// NewInMemoryHistory creates a new in-memory command history source.
// The caller should bind the history source returned from this call
// to the readline instance, with shell.History.Add().
var NewInMemoryHistory = history.NewInMemoryHistory

// historyCommands returns all history commands.
// Under each comment are gathered all commands related to the comment's
// subject. When there are two subgroups separated by an empty line, the
// second one comprises commands that are not legacy readline commands.
func ( *Shell) () commands {
	 := map[string]func(){
		"accept-line":                            .acceptLine,
		"next-history":                           .downHistory,
		"previous-history":                       .upHistory,
		"beginning-of-history":                   .beginningOfHistory,
		"end-of-history":                         .endOfHistory,
		"operate-and-get-next":                   .acceptLineAndDownHistory,
		"fetch-history":                          .fetchHistory,
		"forward-search-history":                 .forwardSearchHistory,
		"reverse-search-history":                 .reverseSearchHistory,
		"non-incremental-forward-search-history": .nonIncrementalForwardSearchHistory,
		"non-incremental-reverse-search-history": .nonIncrementalReverseSearchHistory,
		"history-search-forward":                 .historySearchForward,
		"history-search-backward":                .historySearchBackward,
		"history-substring-search-forward":       .historySubstringSearchForward,
		"history-substring-search-backward":      .historySubstringSearchBackward,
		"yank-last-arg":                          .yankLastArg,
		"insert-last-argument":                   .yankLastArg,
		"yank-nth-arg":                           .yankNthArg,
		"magic-space":                            .magicSpace,

		"accept-and-hold":                    .acceptAndHold,
		"accept-and-infer-next-history":      .acceptAndInferNextHistory,
		"down-line-or-history":               .downLineOrHistory,
		"vi-down-line-or-history":            .viDownLineOrHistory,
		"up-line-or-history":                 .upLineOrHistory,
		"up-line-or-search":                  .upLineOrSearch,
		"down-line-or-select":                .downLineOrSelect,
		"infer-next-history":                 .inferNextHistory,
		"beginning-of-buffer-or-history":     .beginningOfBufferOrHistory,
		"end-of-buffer-or-history":           .endOfBufferOrHistory,
		"beginning-of-line-hist":             .beginningOfLineHist,
		"end-of-line-hist":                   .endOfLineHist,
		"incremental-forward-search-history": .incrementalForwardSearchHistory,
		"incremental-reverse-search-history": .incrementalReverseSearchHistory,
		"save-line":                          .saveLine,
		"history-source-next":                .historySourceNext,
		"history-source-prev":                .historySourcePrev,
		"autosuggest-accept":                 .autosuggestAccept,
		"autosuggest-execute":                .autosuggestExecute,
		"autosuggest-enable":                 .autosuggestEnable,
		"autosuggest-disable":                .autosuggestDisable,
		"autosuggest-toggle":                 .autosuggestToggle,
	}

	return 
}

//
// Standard ----------------------------------------------------------------
//

// Finish editing the buffer. Normally this causes the buffer to be executed as a shell command.
func ( *Shell) () {
	.acceptLineWith(false, false)
}

// Move to the next event in the history list.
func ( *Shell) () {
	.History.Save()
	.History.Walk(-1)
}

// Move to the previous event in the history list.
func ( *Shell) () {
	.History.Save()
	.History.Walk(1)
}

// Move to the first event in the history list.
func ( *Shell) () {
	.History.SkipSave()

	 := .History.Current()
	if  == nil {
		return
	}

	.History.Walk(.Len())
}

// Move to the last event in the history list.
func ( *Shell) () {
	 := .History.Current()

	if  == nil {
		return
	}

	.History.Walk(-.Len() + 1)
}

// Execute the current line, and push the next history event on the buffer stack.
func ( *Shell) () {
	.acceptLineWith(true, false)
}

// With a numeric argument, fetch that entry from the history
// list and make it the current line.  Without an argument,
// move back to the first entry in the history list.
func ( *Shell) () {
	if .Iterations.IsSet() {
		.History.Fetch(.Iterations.Get())
	} else {
		.History.Fetch(0)
	}
}

// Search forward starting at the current line and moving `down' through
// the history as necessary.  This is an incremental search, opening and
// showing matching completions.
func ( *Shell) () {
	.History.SkipSave()

	 := true
	 := false
	 := true

	.historyCompletion(, , )
}

// Search backward starting at the current line and moving `up' through
// the history as necessary.  This is an incremental search, opening and
// showing matching completions.
func ( *Shell) () {
	.History.SkipSave()

	 := false
	 := false
	 := true

	.historyCompletion(, , )
}

// Search forward through the history starting at the current line
// using a non-incremental search for a string supplied by the user.
func ( *Shell) () {
	 := false
	 := true
	 := true

	.completer.NonIsearchStart(.History.Name(), , , )
}

// Search backward through the history starting at the current line
// using a non-incremental search for a string supplied by the user.
func ( *Shell) () {
	 := false
	 := false
	 := true

	.completer.NonIsearchStart(.History.Name(), , , )
}

// Search forward through the history for the string of characters
// between the start of the current line and the point.  The search
// string must match at the beginning of a history line.
func ( *Shell) () {
	.History.Save()

	 := true
	 := true
	 := false

	.History.InsertMatch(nil, nil, , , )
}

// Search backward through the history for the string of characters
// between the start of the current line and the point.  The search
// string must match at the beginning of a history line.
func ( *Shell) () {
	.History.Save()

	 := true
	 := false
	 := false

	.History.InsertMatch(nil, nil, , , )
}

// Search forward through the history for the string of characters
// between the start of the current line and the current cursor position.
// The search string may match anywhere in a history line.
// This is a non-incremental search.
func ( *Shell) () {
	 := true
	 := true
	 := true

	.History.InsertMatch(.line, .cursor, , , )
}

// Search backward through the history for the string of characters
// between the start of the current line and the current cursor position.
// The search string may match anywhere in a history line.
// This is a non-incremental search.
func ( *Shell) () {
	 := true
	 := false
	 := true

	.History.InsertMatch(.line, .cursor, , , )
}

// Insert the last argument to the previous command (the last
// word of the previous history entry).  With a numeric
// argument, behave exactly like yank-nth-arg.  Successive
// calls to yank-last-arg move back through the history list,
// inserting the last word (or the word specified by the
// argument to the first call) of each line in turn.
// Any numeric argument supplied to these successive calls
// determines the direction to move through the history.
// A negative argument switches the direction through the
// history (back or forward).  The history expansion
// facilities are used to extract the last argument, as if
// the "!$" history expansion had been specified.
func ( *Shell) () {
	// Get the last history line.
	 := .History.GetLast()
	if  == "" {
		return
	}

	// Split it into words, and get the last one.
	,  := strutil.Split()
	if  != nil || len() == 0 {
		return
	}

	// Get the last word, and quote it if it contains spaces.
	 := [len()-1]
	if strings.ContainsAny(, " \t") {
		if strings.Contains(, "\"") {
			 = "'" +  + "'"
		} else {
			 = "\"" +  + "\""
		}
	}

	// And append it to the end of the line.
	.line.Insert(.cursor.Pos(), []rune()...)
	.cursor.Move(len())
}

// Insert the first argument to the previous command (usually
// the second word on the previous line) at point.  With an
// argument n, insert the nth word from the previous command
// (the words in the previous command begin with word 0).
// A negative argument inserts the nth word from the end of the
// previous command.  Once the argument n is computed, the argument
// is extracted as if the "!n" history expansion had been specified.
func ( *Shell) () {
	// Get the last history line.
	 := .History.GetLast()
	if  == "" {
		return
	}

	// Split it into words, and get the last one.
	,  := strutil.Split()
	if  != nil || len() == 0 {
		return
	}

	var  string

	// Abort if the required position is out of bounds.
	 := .Iterations.Get()
	if len() <  {
		return
	}

	 = [-1]

	// Quote if required.
	if strings.ContainsAny(, " \t") {
		if strings.Contains(, "\"") {
			 = "'" +  + "'"
		} else {
			 = "\"" +  + "\""
		}
	}

	// And append it to the end of the line.
	.line.Insert(.line.Len(), []rune()...)
	.cursor.Move(len())
}

// Perform history expansion on the current line and insert a space.
// If the current blank word under cursor starts with an exclamation
// mark, the word up to the cursor is matched as a prefix against
// the history lines, and the first match is inserted in place of it.
func ( *Shell) () {
	 := .cursor.Pos()
	 := .line.Len()

	// If no line, or the cursor is on a space, we can't perform.
	if  == 0 || ( ==  && (*.line)[-1] == inputrc.Space) {
		.selfInsert()
		return
	}

	// Select the word around cursor.
	.viSelectInBlankWord()
	, , ,  := .selection.Pop()
	.cursor.Set()

	// Fail if empty or not prefixed expandable.
	if len(strings.TrimSpace()) == 0 {
		.selfInsert()
		return
	}

	if !strings.HasPrefix(, "!") ||  == "!" {
		.selfInsert()
		return
	}

	// Else, perform expansion on the remainder.
	 := (*.line)[+1:]
	 := .History.Suggest(&)

	if string() == string() {
		.selfInsert()
		return
	}

	.History.Save()
	.line.Cut(, )
	.line.Insert(, ...)
	.cursor.Set( + .Len())
}

//
// Added -------------------------------------------------------------------
//

// Accept the current input line (execute it) and
// keep it as the buffer on the next readline loop.
func ( *Shell) () {
	.acceptLineWith(false, true)
}

// Execute the contents of the buffer. Then search the history list for a line
// matching the current one and push the event following onto the buffer stack.
func ( *Shell) () {
	.acceptLineWith(true, false)
}

// Move down a line in the buffer, or if already at the
// bottom line, move to the next event in the history list.
func ( *Shell) () {
	 := .Iterations.Get()
	 := .line.Lines() - .cursor.LinePos()

	// If we can go down some lines out of
	// the available iterations, use them.
	if  > 0 {
		.cursor.LineMove()
		 -= 
	}

	if  > 0 {
		.History.Walk( * -1)
	}
}

// Move down a line in the buffer, or if already at the
// bottom line, move to the next event in the history list.
// Then move to the first non-blank character on the line.
func ( *Shell) () {
	.downLineOrHistory()
	.viFirstPrint()
}

// Move up a line in the buffer, or if already at the top
// line, move to the previous event in the history list.
func ( *Shell) () {
	 := .Iterations.Get()
	 := .cursor.LinePos()

	// If we can go down some lines out of
	// the available iterations, use them.
	if  > 0 {
		.cursor.LineMove( * -1)
		 -= 
	}

	if  > 0 {
		.History.Walk()
	}
}

// If the cursor is on the first line of the buffer, start an incremental
// search backward on the history lines. Otherwise, move up a line in the buffer.
func ( *Shell) () {
	.History.SkipSave()

	switch {
	case .cursor.LinePos() > 0:
		.cursor.LineMove(-1)
	default:
		.historySearchBackward()
	}
}

// If the cursor is on the last line of the buffer, start an incremental
// search forward on the history lines. Otherwise, move up a line in the buffer.
func ( *Shell) () {
	.History.SkipSave()

	switch {
	case .cursor.LinePos() < .line.Lines():
		.cursor.LineMove(1)
	default:
		.menuComplete()
	}
}

// Attempt to find a line in history matching the current line buffer as a prefix,
// and if one is found, fetch the next history event and make it the current buffer.
func ( *Shell) () {
	.History.SkipSave()
	.History.InferNext()
}

// If the cursor is not at the beginning of the buffer, go to it.
// Otherwise, go to the beginning of history.
func ( *Shell) () {
	if .cursor.Pos() > 0 {
		.History.SkipSave()
		.cursor.Set(0)

		return
	}

	.History.Save()
	.beginningOfHistory()
}

// If the cursor is not at the end of the buffer, go to it.
// Otherwise, go to the end of history.
func ( *Shell) () {
	if .cursor.Pos() < .line.Len()-1 {
		.History.SkipSave()
		.cursor.Set(.line.Len())

		return
	}

	.History.Save()
	.endOfHistory()
}

// Go to the beginning of the current line, if the cursor is not yet.
// If at the beginning of the line, attempt to move one line up.
// If at the beginning of the buffer, move up one history line.
func ( *Shell) () {
	switch {
	case .cursor.Pos() > 0:
		.History.SkipSave()

		if .cursor.AtBeginningOfLine() {
			.cursor.Dec()
		}

		.beginningOfLine()
	default:
		.History.Save()
		.History.Walk(1)
	}
}

// Go to the end of the current line, if the cursor is not yet.
// If at the end of the line, attempt to move one line down.
// If at the end of the buffer, move up one history line.
func ( *Shell) () {
	.History.SkipSave()

	switch {
	case .cursor.Pos() < .line.Len()-1:
		.History.SkipSave()

		if .cursor.AtEndOfLine() {
			.cursor.Inc()
		}

		.endOfLine()

	default:
		.History.Save()
		.History.Walk(-1)
	}
}

// Start an forward history autocompletion mode, starting at the
// current line and moving `down' through the history as necessary.
func ( *Shell) () {
	.History.SkipSave()

	 := true
	 := true
	 := false

	.historyCompletion(, , )
}

// Start an backward history autocompletion mode, starting at the
// current line and moving `down' through the history as necessary.
func ( *Shell) () {
	.History.SkipSave()

	 := false
	 := true
	 := false

	.historyCompletion(, , )
}

// Write the current line to the history if it is not empty
// (without executing it), and clear the line buffer.
func ( *Shell) () {
	.History.Write(false)
	.History.Revert()
}

// If more than one source of command history is bound to the shell,
// cycle to the next one and use it for all history search operations,
// movements across lines, their respective undo histories, etc.
func ( *Shell) () {
	.History.Cycle(true)
}

// If more than one source of command history is bound to the shell,
// cycle to the previous one and use it for all history search operations,
// movements across lines, their respective undo histories, etc.
func ( *Shell) () {
	.History.Cycle(false)
}

// If a line is currently auto-suggested, make it the buffer.
func ( *Shell) () {
	 := .History.Suggest(.line)

	if .Len() <= .line.Len() {
		return
	}

	.line.Set(...)
	.cursor.Set(len())
}

// If a line is currently auto-suggested, make it the buffer and execute it.
func ( *Shell) () {
	 := .History.Suggest(.line)

	if .Len() <= .line.Len() {
		return
	}

	.line.Set(...)
	.cursor.Set(len())

	.acceptLine()
}

// Toggle line history autosuggestions on/off.
func ( *Shell) () {
	if .Config.GetBool("history-autosuggest") {
		.autosuggestDisable()
	} else {
		.autosuggestEnable()
	}
}

// Enable history line autosuggestions.
// When enabled and if a line is suggested, forward-word commands, will
// take the first word of the non-inserted part of this suggestion and
// will insert it in the real input line.
// The forward-char* commands, if at the end of the line, will accept it.
func ( *Shell) () {
	.History.SkipSave()
	.Config.Vars["history-autosuggest"] = true
}

// Disable history line autosuggestions.
func ( *Shell) () {
	.History.SkipSave()
	.Config.Vars["history-autosuggest"] = false
}

//
// Utils -------------------------------------------------------------------
//

func ( *Shell) (,  bool) {
	// If we are currently using the incremental-search buffer,
	// we should cancel this mode so as to run the rest of this
	// function on (with) the input line itself, not the minibuffer.
	.completer.Reset()

	// Non-incremental search modes are the only mode not cancelled
	// by the completion engine. If it's active, match the line result
	// and return without returning the line to the readline caller.
	, ,  := .completer.NonIncrementallySearching()
	if  {
		defer .completer.NonIsearchStop()

		, ,  := .completer.GetBuffer()
		.History.InsertMatch(, , true, , )

		return
	}

	// Use the correct buffer for the rest of the function.
	.line, .cursor, .selection = .completer.GetBuffer()

	// Without multiline support, we always return the line.
	if .AcceptMultiline == nil {
		.Macros.StopRecord(.Keys.Caller()...)

		.Display.AcceptLine()
		.History.Accept(, , nil)

		return
	}

	// Ask the caller if the line should be accepted
	// as is, save the command line and accept it.
	if .AcceptMultiline(*.line) {
		.Macros.StopRecord(.Keys.Caller()...)

		.Display.AcceptLine()
		.History.Accept(, , nil)

		return
	}

	// If not, we should start editing another line,
	// and insert a newline where our cursor value is.
	// This has the nice advantage of being able to work
	// in multiline mode even in the middle of the buffer.
	.line.Insert(.cursor.Pos(), '\n')
	.cursor.Inc()
}

func ( *Shell) ( bool) {
	 := .cursor.Pos()
	if  < .line.Len()-1 {
		return
	}

	if !.Config.GetBool("history-autosuggest") {
		return
	}

	 := .History.Suggest(.line)

	if .Len() > .line.Len() {
		var  int

		if  {
			 = .ForwardEnd(.Tokenize, )
		} else {
			 = .Forward(.Tokenize, )
		}

		if +1+ > .Len() {
			 = .Len() -  - 1
		}

		.line.Insert(+1, [+1:++1]...)
	}
}