package readline

import (
	
	
	
	
	

	

	
	
	
	
	
	
)

// standardCommands returns all standard/emacs 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.
//
// Modes
// Moving
// Changing text
// Killing and Yanking
// Numeric arguments.
// Macros
// Miscellaneous.
func ( *Shell) () commands {
	 := map[string]func(){
		// Modes
		"emacs-editing-mode": .emacsEditingMode,

		// Moving
		"forward-char":         .forwardChar,
		"backward-char":        .backwardChar,
		"forward-word":         .forwardWord,
		"backward-word":        .backwardWord,
		"shell-forward-word":   .forwardShellWord,
		"shell-backward-word":  .backwardShellWord,
		"beginning-of-line":    .beginningOfLine,
		"end-of-line":          .endOfLine,
		"previous-screen-line": .upLine,
		"next-screen-line":     .downLine,
		"clear-screen":         .clearScreen,
		"clear-display":        .clearDisplay,
		"redraw-current-line":  .Display.Refresh,

		// Changing text
		"end-of-file":                  .endOfFile,
		"delete-char":                  .deleteChar,
		"backward-delete-char":         .backwardDeleteChar,
		"forward-backward-delete-char": .forwardBackwardDeleteChar,
		"quoted-insert":                .quotedInsert,
		"tab-insert":                   .tabInsert,
		"self-insert":                  .selfInsert,
		"bracketed-paste-begin":        .bracketedPasteBegin,
		"transpose-chars":              .transposeChars,
		"transpose-words":              .transposeWords,
		"shell-transpose-words":        .shellTransposeWords,
		"down-case-word":               .downCaseWord,
		"up-case-word":                 .upCaseWord,
		"capitalize-word":              .capitalizeWord,
		"overwrite-mode":               .overwriteMode,
		"delete-horizontal-whitespace": .deleteHorizontalWhitespace,

		"delete-word":      .deleteWord,
		"quote-region":     .quoteRegion,
		"quote-line":       .quoteLine,
		"keyword-increase": .keywordIncrease,
		"keyword-decrease": .keywordDecrease,

		// Killing & yanking
		"kill-line":           .killLine,
		"backward-kill-line":  .backwardKillLine,
		"unix-line-discard":   .backwardKillLine,
		"kill-whole-line":     .killWholeLine,
		"kill-word":           .killWord,
		"backward-kill-word":  .backwardKillWord,
		"unix-word-rubout":    .backwardKillWord,
		"kill-region":         .killRegion,
		"copy-region-as-kill": .copyRegionAsKill,
		"copy-backward-word":  .copyBackwardWord,
		"copy-forward-word":   .copyForwardWord,
		"yank":                .yank,
		"yank-pop":            .yankPop,

		"kill-buffer":              .killBuffer,
		"shell-kill-word":          .shellKillWord,
		"shell-backward-kill-word": .shellBackwardKillWord,
		"copy-prev-shell-word":     .copyPrevShellWord,

		// Numeric arguments
		"digit-argument": .digitArgument,

		// Macros
		"start-kbd-macro":      .startKeyboardMacro,
		"end-kbd-macro":        .endKeyboardMacro,
		"call-last-kbd-macro":  .callLastKeyboardMacro,
		"print-last-kbd-macro": .printLastKeyboardMacro,

		"macro-toggle-record": .macroToggleRecord,
		"macro-run":           .macroRun,

		// Miscellaneous
		"re-read-init-file":         .reReadInitFile,
		"abort":                     .abort,
		"do-lowercase-version":      .doLowercaseVersion,
		"prefix-meta":               .prefixMeta,
		"undo":                      .undoLast,
		"revert-line":               .revertLine,
		"set-mark":                  .setMark,
		"exchange-point-and-mark":   .exchangePointAndMark,
		"character-search":          .characterSearch,
		"character-search-backward": .characterSearchBackward,
		"insert-comment":            .insertComment,
		"dump-functions":            .dumpFunctions,
		"dump-variables":            .dumpVariables,
		"dump-macros":               .dumpMacros,
		"magic-space":               .magicSpace,
		"edit-and-execute-command":  .editAndExecuteCommand,
		"edit-command-line":         .editCommandLine,

		"redo":                .redo,
		"select-keyword-next": .selectKeywordNext,
		"select-keyword-prev": .selectKeywordPrev,
	}

	return 
}

//
// Modes ----------------------------------------------------------------
//

// When in vi command mode, this causes a switch to emacs editing mode.
func ( *Shell) () {
	// Reset any visual selection and iterations.
	.selection.Reset()
	.Iterations.Reset()
	.Buffers.Reset()

	// Cancel completions and hints if any, and reassign the
	// current line/cursor/selection for the cursor check below
	// to be effective. This is needed when in isearch mode.
	.Hint.Reset()
	.completer.Reset()
	.line, .cursor, .selection = .completer.GetBuffer()

	// Update the keymap.
	.Keymap.SetMain(keymap.Emacs)
}

//
// Movement -------------------------------------------------------------
//

// Move forward one character.
func ( *Shell) () {
	 := .cursor.Pos()

	// Only exception where we actually don't forward a character.
	if .Config.GetBool("history-autosuggest") && .cursor.Pos() >= .line.Len()-1 {
		.autosuggestAccept()
	}

	if .cursor.Pos() >  {
		return
	}

	// Else, we move forward.
	.History.SkipSave()
	 := .Iterations.Get()

	for  := 1;  <= ; ++ {
		.cursor.Inc()
	}
}

// Move backward one character.
func ( *Shell) () {
	.History.SkipSave()
	 := .Iterations.Get()

	for  := 1;  <= ; ++ {
		.cursor.Dec()
	}
}

// Move to the beginning of the next word. The editor’s idea
// of a word is any sequence of alphanumeric characters.
func ( *Shell) () {
	.History.SkipSave()
	 := .Iterations.Get()

	for  := 1;  <= ; ++ {
		// When we have an autosuggested history and if we are at the end
		// of the line, insert the next word from this suggested line.
		.insertAutosuggestPartial(true)

		 := .line.ForwardEnd(.line.Tokenize, .cursor.Pos())
		.cursor.Move( + 1)
	}
}

// Move to the beginning of the current or previousword. The editor’s
// idea of a word is any sequence of alphanumeric characters.
func ( *Shell) () {
	.History.SkipSave()

	 := .Iterations.Get()
	for  := 1;  <= ; ++ {
		 := .line.Backward(.line.Tokenize, .cursor.Pos())
		.cursor.Move()
	}
}

// Move forward to the beginning of the next word.
// The editor's idea of a word is defined by classic sh-style word splitting:
// any non-spaced sequence of characters, or a quoted sequence.
func ( *Shell) () {
	 := .Iterations.Get()

	for  := 1;  <= ; ++ {
		.selection.SelectAShellWord()
		, , ,  := .selection.Pop()
		.cursor.Set()
	}
}

// Move to the beginning of the current or previous word.
// The editor's idea of a word is defined by classic sh-style word splitting:
// any non-spaced sequence of characters, or a quoted sequence.
func ( *Shell) () {
	 := .Iterations.Get()

	for  := 1;  <= ; ++ {
		// First go the beginning of the blank word
		 := .cursor.Pos()
		 := .line.Backward(.line.TokenizeSpace, )
		.cursor.Move()

		// Now try to find enclosing quotes from here.
		,  := .selection.SelectAShellWord()
		.cursor.Set()
	}
}

// Move to the beginning of the line. If already at the beginning
// of the line, move to the beginning of the previous line, if any.
func ( *Shell) () {
	.History.SkipSave()

	// Handle 0 as iteration to Vim.
	if !.Keymap.IsEmacs() && .Iterations.IsSet() {
		.Iterations.Add("0")
		return
	}

	.cursor.BeginningOfLine()
}

// Move to the end of the line. If already at the end
// of the line, move to the end of the next line, if any.
func ( *Shell) () {
	.History.SkipSave()
	// If in Vim command mode, cursor
	// will be brought back once later.
	.cursor.EndOfLineAppend()
}

// Move up one line if the current buffer has more than one line.
func ( *Shell) () {
	 := .Iterations.Get()
	.cursor.LineMove( * -1)
}

// Move down one line if the current buffer has more than one line.
func ( *Shell) () {
	 := .Iterations.Get()
	.cursor.LineMove()
}

// Clear the current screen and redisplay the prompt and input line.
// This does not clear the terminal's output buffer.
func ( *Shell) () {
	.History.SkipSave()

	fmt.Print(term.CursorTopLeft)
	fmt.Print(term.ClearScreen)

	.Display.PrintPrimaryPrompt()
}

// Clear the current screen and redisplay the prompt and input line.
// This does clear the terminal's output buffer.
func ( *Shell) () {
	.History.SkipSave()

	fmt.Print(term.CursorTopLeft)
	fmt.Print(term.ClearDisplay)

	.Display.PrintPrimaryPrompt()
}

//
// Changing Text --------------------------------------------------------
//

// The character indicating end-of-file as set, for example,
// by “stty”.  If this character is read when there are no
// characters on the line, and point is at the beginning of
// the line, readline interprets it as the end of input and
// returns EOF.
func ( *Shell) () {
	switch .line.Len() {
	case 0:
		.Display.AcceptLine()
		.History.Accept(false, false, io.EOF)
	default:
		.deleteChar()
	}
}

// Delete the character under the cursor.
func ( *Shell) () {
	.History.Save()

	 := .Iterations.Get()

	// Delete the chars in the line anyway
	for  := 1;  <= ; ++ {
		.line.CutRune(.cursor.Pos())
	}
}

// Delete the character behind the cursor.
// If the character to delete is a matching character
// (quote/brackets/braces,etc) and that the character
// under the cursor is its matching counterpart, this
// character will also be deleted.
func ( *Shell) () {
	if .Keymap.Main() == keymap.ViInsert {
		.History.SkipSave()
	} else {
		.History.Save()
	}

	// We might currently have a selected candidate inserted,
	// and thus we should accept it as part of the real input
	// line before cutting any character.
	completion.UpdateInserted(.completer)

	if .cursor.Pos() == 0 {
		return
	}

	 := .Iterations.Get()

	switch  {
	case 1:
		// Handle removal of autopairs characters.
		if .Config.GetBool("autopairs") {
			completion.AutopairDelete(.line, .cursor)
		}

		// And then delete the character under cursor.
		.cursor.Dec()
		.line.CutRune(.cursor.Pos())

	default:
		for  := 1;  <= ; ++ {
			.cursor.Dec()
			.line.CutRune(.cursor.Pos())
		}
	}
}

// Delete the character under the cursor, unless the cursor is at the
// end of the line, in which case the character behind the cursor is deleted.
func ( *Shell) () {
	switch .cursor.Pos() {
	case .line.Len():
		.backwardDeleteChar()
	default:
		.deleteChar()
	}
}

// Add the next character that you type to the line verbatim.
// This is how to insert characters like C-q, for example.
func ( *Shell) () {
	.History.SkipSave()
	.completer.TrimSuffix()

	 := .Keymap.PendingCursor()
	defer ()

	,  := .Keys.ReadKey()

	,  := strutil.Quote()

	.cursor.InsertAt(...)
}

// Insert a tab character.
func ( *Shell) () {
	.History.SkipSave()

	.cursor.InsertAt('\t')
}

// Insert the character typed.
func ( *Shell) () {
	.History.SkipSave()

	// Handle suffix-autoremoval for inserted completions.
	.completer.TrimSuffix()

	 := .Keys.Caller()

	// Handle autopair insertion (for the closer only)
	, ,  := .completer.NonIncrementallySearching()
	 := .Keymap.Local() == keymap.Isearch

	if ! && ! && .Config.GetBool("autopairs") {
		if  := completion.AutopairInsertOrJump([0], .line, .cursor);  {
			return
		}
	}

	var  []rune
	var  int

	if .Config.GetBool("output-meta") && [0] != inputrc.Esc {
		 = append(, [0])
		 = uniseg.StringWidth(string())
	} else {
		,  = strutil.Quote([0])
	}

	.cursor.InsertAt(...)
	.cursor.Move(-1 * len())
	.cursor.Move()
}

func ( *Shell) () {
	// keys, _ := rl.Keys.PeekAllBytes()
	// fmt.Println(string(keys))
}

// Drag the character before point forward over the character
// at point, moving point forward as well.  If point is at the
// end of the line, then this transposes the two characters
// before point.  Negative arguments have no effect.
func ( *Shell) () {
	if .cursor.Pos() < 2 || .line.Len() < 2 {
		.History.SkipSave()
		return
	}

	.History.Save()

	switch {
	case .cursor.Pos() == .line.Len():
		 := (*.line)[.cursor.Pos()-1]
		 := (*.line)[.cursor.Pos()-2]
		(*.line)[.cursor.Pos()-2] = 
		(*.line)[.cursor.Pos()-1] = 
	default:
		 := .cursor.Char()
		 := (*.line)[.cursor.Pos()-1]
		(*.line)[.cursor.Pos()-1] = 
		.cursor.ReplaceWith()
	}
}

// Drag the word before point past the word after point,
// moving point over that word as well.  If point is at the
// end of the line, this transposes the last two words on the
// line. If a numeric argument is given, the word to transpose
// is chosen backward.
func ( *Shell) () {
	.History.Save()

	 := .cursor.Pos()
	.cursor.ToFirstNonSpace(true)
	.cursor.CheckCommand()

	// Save the current word and move the cursor to its beginning
	.viSelectInWord()
	.selection.Visual(false)
	, , ,  := .selection.Pop()

	// Then move some number of words.
	// Either use words backward (if we are at end of line) or forward.
	.cursor.Set()

	if  >= .line.Len()-1 || .Iterations.IsSet() {
		.backwardWord()
	} else {
		.viForwardWord()
	}

	// Save the word to transpose with
	.viSelectInWord()
	.selection.Visual(false)
	, , ,  := .selection.Pop()

	// We might be on the first word of the line,
	// in which case we don't do anything.
	if  == 0 {
		.cursor.Set()
		return
	}

	// If we went forward rather than backward, swap everything.
	if  >  {
		,  = , 
		,  = , 
		,  = , 
	}

	// Assemble the newline
	 := string((*.line)[:])
	 := append([]rune(), []rune()...)
	 = append(, (*.line)[:]...)
	 = append(, []rune()...)
	 = append(, (*.line)[:]...)
	.line.Set(...)

	// And replace the cursor
	.cursor.Set()
}

// Drag the shell word before point past the shell word after point,
// moving point over that shell word as well. If point is at the
// end of the line, this transposes the last two words on the line.
// If a numeric argument is given, the word to transpose is chosen backward.
func ( *Shell) () {
	.History.Save()

	 := .cursor.Pos()

	// Save the current word
	.viSelectAShellWord()
	, , ,  := .selection.Pop()

	// First move back the number of words
	.cursor.Set()
	.backwardShellWord()

	// Save the word to transpose with
	.viSelectAShellWord()
	, , ,  := .selection.Pop()

	// We might be on the first word of the line,
	// in which case we don't do anything.
	if  >  {
		.cursor.Set()
		return
	}

	// Assemble the newline
	 := string((*.line)[:])
	 := append([]rune(), []rune()...)
	 = append(, (*.line)[:]...)
	 = append(, []rune()...)
	 = append(, (*.line)[:]...)
	.line.Set(...)

	// And replace cursor
	.cursor.Set()
}

// Lowercase the current (or following) word. With a negative argument,
// lowercase the previous word, but do not move point.
func ( *Shell) () {
	.History.Save()

	 := .cursor.Pos()

	// Save the current word
	.cursor.Inc()
	 := .line.Backward(.line.Tokenize, .cursor.Pos())
	.cursor.Move()

	.selection.Mark(.cursor.Pos())
	 := .line.ForwardEnd(.line.Tokenize, .cursor.Pos())
	.cursor.Move()

	.selection.ReplaceWith(unicode.ToLower)
	.cursor.Set()
}

// Uppercase the current (or following) word.  With a negative argument,
// uppercase the previous word, but do not move point.
func ( *Shell) () {
	.History.Save()

	 := .cursor.Pos()

	// Save the current word
	.cursor.Inc()
	 := .line.Backward(.line.Tokenize, .cursor.Pos())
	.cursor.Move()

	.selection.Mark(.cursor.Pos())
	 := .line.ForwardEnd(.line.Tokenize, .cursor.Pos())
	.cursor.Move()

	.selection.ReplaceWith(unicode.ToUpper)
	.cursor.Set()
}

// Capitalize the current (or following) word.  With a negative argument,
// capitalize the previous word, but do not move point.
func ( *Shell) () {
	if .line.Len() == 0 {
		return
	}

	.History.Save()

	 := .cursor.Pos()

	.cursor.Inc()
	 := .line.Backward(.line.Tokenize, .cursor.Pos())
	.cursor.Move()

	 := .cursor.Char()
	.cursor.ReplaceWith(unicode.ToUpper())
	.cursor.Set()
}

// Toggle overwrite mode. In overwrite mode, characters bound to
// self-insert replace the text at point rather than pushing the
// text to the right.  Characters bound to backward-delete-char
// replace the character before point with a space.
func ( *Shell) () {
	// We store the current line as an undo item first, but will not
	// store any intermediate changes (in the loop below) as undo items.
	.History.Save()

	 := .Keymap.PendingCursor()
	defer ()

	// All replaced characters are stored, to be used with backspace
	 := make([]rune, 0)

	// Don't use the delete cache past the end of the line
	 := .line.Len()

	// The replace mode is quite special in that it does escape back
	// to the main readline loop: it keeps reading characters and inserts
	// them as long as the escape key is not pressed.
	for {
		// We read a character to use first.
		,  := .Keys.ReadKey()
		if  {
			break
		}

		// If the key is a backspace, we go back one character
		if string() == inputrc.Unescape(string(`\C-?`)) {
			if .cursor.Pos() >  {
				.backwardDeleteChar()
			} else if .cursor.Pos() > 0 {
				.cursor.Dec()
			}

			// And recover the last replaced character
			if len() > 0 && .cursor.Pos() <  {
				 = [len()-1]
				 = [:len()-1]

				.cursor.ReplaceWith()
			}
		} else {
			// If the cursor is at the end of the line,
			// we insert the character instead of replacing.
			if .line.Len() == .cursor.Pos() {
				.cursor.InsertAt()
			} else {
				 = append(, .cursor.Char())
				.cursor.ReplaceWith()
				.cursor.Inc()
			}
		}

		// Update the line
		.Display.Refresh()
	}
}

// Delete all spaces and tabs around point.
func ( *Shell) () {
	.History.Save()

	 := .cursor.Pos()

	.cursor.ToFirstNonSpace(false)

	if .cursor.Pos() !=  {
		.cursor.Inc()
	}

	 := .cursor.Pos()
	.cursor.ToFirstNonSpace(true)

	if .cursor.Pos() !=  {
		.cursor.Dec()
	}

	 := .cursor.Pos()
	.line.Cut(, )
	.cursor.Set()
}

// Delete the current word from the cursor point up to the end of it.
func ( *Shell) () {
	.History.Save()

	.selection.Mark(.cursor.Pos())
	 := .line.ForwardEnd(.line.Tokenize, .cursor.Pos())
	.cursor.Move()

	.selection.Cut()
}

// Quote the region from the cursor to the mark.
func ( *Shell) () {
	.History.Save()

	.selection.Surround('\'', '\'')
	.cursor.Inc()
}

// Quote the entire line buffer.
func ( *Shell) () {
	if .line.Len() == 0 {
		return
	}

	for ,  := range *.line {
		if  == '\n' {
			break
		}

		if  == '\'' {
			(*.line)[] = '"'
		}
	}

	.line.Insert(0, '\'')
	.line.Insert(.line.Len(), '\'')
}

// Modifies the current word under the cursor, increasing it.
// The following word types can be incremented/decremented:
//
//	Booleans: true|false, t|f, on|off, yes|no, y|n.
//	Operators: &&|||, ++|--, ==|!=, ===| !==, +| -, -| *, *| /, /| +, and| or.
//	Hex digits 0xDe => 0xdf, 0xdE => 0xDF, 0xde0 => 0xddf, 0xffffffffffffffff => 0x0000000000000000.
//	Binary digits: 0b1 => 0b10, 0B0 => 0B1, etc.
//	Integers.
func ( *Shell) () {
	.History.Save()
	.keywordSwitch(true)
}

// Modifies the current word under the cursor, decreasing it.
// The following word types can be incremented/decremented:
//
//	Booleans: true|false, t|f, on|off, yes|no, y|n.
//	Operators: &&|||, ++|--, ==|!=, ===| !==, +| -, -| *, *| /, /| +, and| or.
//	Hex digits 0xDe => 0xdf, 0xdE => 0xDF, 0xde0 => 0xddf, 0xffffffffffffffff => 0x0000000000000000.
//	Binary digits: 0b1 => 0b10, 0B0 => 0B1, etc.
//	Integers.
func ( *Shell) () {
	.History.Save()
	.keywordSwitch(false)
}

// Switches the current word under the cursor, increasing or decreasing it.
func ( *Shell) ( bool) {
	 := strutil.AdjustNumberOperatorPos(.cursor.Pos(), *.line)

	// Select in word and get the selection positions
	,  := .line.SelectWord()
	++

	// Move the cursor backward if needed/possible
	if  != 0 && ((*.line)[-1] == '+' || (*.line)[-1] == '-') {
		--
	}

	// Get the selection string
	 := string((*.line)[:])

	// For each of the keyword handlers, run it, which returns
	// false/none if didn't operate, then continue to next handler.
	for ,  := range strutil.KeywordSwitchers() {
		 := .Iterations.Get()

		, , ,  := (, , )
		if ! {
			continue
		}

		// We are only interested in the end position after all runs
		 =  + 
		 += 

		if  <  ||  >=  {
			continue
		}

		// Update the line and the cursor, and return
		// since we have a handler that has been ran.
		 := string((*.line)[:])
		 := string((*.line)[:])

		 := append([]rune(), []rune()...)
		 = append(, []rune()...)
		.line.Set(...)
		.cursor.Set( + len() - 1)

		return
	}
}

//
// Killing & Yanking ----------------------------------------------------------
//

// Kill from the cursor to the end of the line. If already
// on the end of the line, kill the newline character.
func ( *Shell) () {
	.Iterations.Reset()
	.History.Save()

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

	 := .cursor.Pos()
	.cursor.EndOfLineAppend()

	.selection.MarkRange(, .cursor.Pos())
	 := .selection.Cut()

	.Buffers.Write([]rune()...)
	.cursor.Set()
}

// Kill backward to the beginning of the line.
func ( *Shell) () {
	.Iterations.Reset()
	.History.Save()

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

	 := .cursor.Pos()
	.cursor.BeginningOfLine()

	.selection.MarkRange(.cursor.Pos(), )
	 := .selection.Cut()

	.Buffers.Write([]rune()...)
}

// Kill all characters on the current line, no matter where point is.
func ( *Shell) () {
	.History.Save()

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

	.Buffers.Write(*.line...)
	.line.Cut(0, .line.Len())
}

// Kill the entire buffer.
func ( *Shell) () {
	.History.Save()

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

	.Buffers.Write(*.line...)
	.line.Cut(0, .line.Len())
}

// Kill the current word from the cursor point up to the end of it.
func ( *Shell) () {
	.History.Save()

	 := .cursor.Pos()

	.cursor.ToFirstNonSpace(true)
	 := .line.Forward(.line.TokenizeSpace, .cursor.Pos())
	.cursor.Move( - 1)
	 := .cursor.Pos()

	.selection.MarkRange(, )
	.Buffers.Write([]rune(.selection.Cut())...)
	.cursor.Set()
}

// Kill the word behind point. Word boundaries
// are the same as those used by backward-word.
func ( *Shell) () {
	.History.Save()
	.History.SkipSave()

	.selection.Mark(.cursor.Pos())
	 := .line.Backward(.line.Tokenize, .cursor.Pos())
	.cursor.Move()

	.Buffers.Write([]rune(.selection.Cut())...)
}

// Kill the text between the point and mark (saved cursor
// position).  This text is referred to as the region.
func ( *Shell) () {
	.History.Save()

	if !.selection.Active() {
		return
	}

	.Buffers.Write([]rune(.selection.Cut())...)
}

// Copy the text in the region to the kill buffer.
func ( *Shell) () {
	.History.SkipSave()

	if !.selection.Active() {
		return
	}

	.Buffers.Write([]rune(.selection.Text())...)
	.selection.Reset()
}

// Copy the word before point to the kill buffer.
// The word boundaries are the same as backward-word.
func ( *Shell) () {
	.History.Save()

	.selection.Mark(.cursor.Pos())
	 := .line.Backward(.line.Tokenize, .cursor.Pos())
	.cursor.Move()

	.Buffers.Write([]rune(.selection.Text())...)
	.selection.Reset()
}

// Copy the word following point to the kill buffer.
// The word boundaries are the same as forward-word.
func ( *Shell) () {
	.History.Save()

	.selection.Mark(.cursor.Pos())
	 := .line.Forward(.line.Tokenize, .cursor.Pos())
	.cursor.Move( + 1)

	.Buffers.Write([]rune(.selection.Text())...)
	.selection.Reset()
}

// Yank the top of the kill ring into the buffer at point.
func ( *Shell) () {
	 := .Buffers.Active()

	 := .Iterations.Get()

	for  := 1;  <= ; ++ {
		.cursor.InsertAt(...)
	}
}

// Rotate the kill ring, and yank the new top.
// Only works following yank or yank-pop.
func ( *Shell) () {
	 := .Iterations.Get()

	for  := 1;  <= ; ++ {
		 := .Buffers.Pop()
		.cursor.InsertAt(...)
	}
}

// Kill the shell word behind point. Word boundaries
// are the same as those used by backward-word.
func ( *Shell) () {
	 := .cursor.Pos()

	// select the shell word, and if the cursor position
	// has changed, we delete the part after the initial one.
	.viSelectAShellWord()

	,  := .selection.Pos()

	.Buffers.Write([]rune((*.line)[:])...)
	.line.Cut(, )
	.cursor.Set()

	.selection.Reset()
}

// Kill the shell word behind point.
func ( *Shell) () {
	 := .cursor.Pos()
	if .line.Len() == 0 ||  == 0 {
		return
	}

	.History.Save()

	// Always ignore the character under cursor.
	.cursor.Dec()
	.cursor.ToFirstNonSpace(false)

	,  := strutil.GetQuotedWordStart((*.line)[:])

	if ! {
		.viSelectAShellWord()
		, _ = .selection.Pos()
	}

	.cursor.Set()
	.cursor.ToFirstNonSpace(true)
	 = .cursor.Pos()

	.Buffers.Write([]rune((*.line)[:])...)
	.line.Cut(, )
	.selection.Reset()
}

// Like copy-prev-word, but the word is found by using shell parsing,
// whereas copy-prev-word looks for blanks. This makes a difference
// when the word is quoted and contains spaces.
func ( *Shell) () {
	.History.Save()

	 := .cursor.Pos()

	// First go back to the beginning of the current word,
	// then go back again to the beginning of the previous.
	.backwardShellWord()
	.backwardShellWord()

	// Select the current shell word
	.viSelectAShellWord()

	 := .selection.Text()

	// Replace the cursor before reassembling the line.
	.cursor.Set()
	.selection.InsertAt(.cursor.Pos(), -1)
	.cursor.Move(len())
}

//
// Numeric Arguments -----------------------------------------------------------
//

// digitArgument is used both in Emacs and Vim modes,
// but strips the Alt modifier used in Emacs mode.
func ( *Shell) () {
	.History.SkipSave()
	 := .Keys.Caller()

	// Strip the Alt modifier.
	if len() > 1 && [0] == inputrc.Esc {
		 = [1:]
	}

	.Iterations.Add(string())
}

//
// Macros ----------------------------------------------------------------------
//

// Begin saving the characters typed into the current keyboard macro.
func ( *Shell) () {
	.Macros.StartRecord(rune(0))
}

// Stop saving the characters typed into the current
// keyboard macro and store the definition.
func ( *Shell) () {
	.Macros.StopRecord()
}

// Re-execute the last keyboard macro defined, by making the
// characters in the macro appear as if typed at the keyboard.
func ( *Shell) () {
	.Macros.RunLastMacro()
}

// Print the last keyboard macro defined in a format suitable for the inputrc file.
func ( *Shell) () {
	.Display.ClearHelpers()

	.Macros.PrintLastMacro()

	.Prompt.PrimaryPrint()
	.Display.Refresh()
}

// Either starts recording a macro (if not yet recording), or stops it.
// If the command is about to start recording a macro, it will read an
// additional argument key (must be a letter), to be used as the macro
// "name", just like macro recording and use work in Vim.
// This command thus works "Vim-style", and should probably be used only
// when using Vim editing mode.
func ( *Shell) () {
	if .Macros.Recording() {
		.Macros.StopRecord()

		return
	}

	 := .Keymap.PendingCursor()
	defer ()

	.Hint.SetTemporary(color.Dim + "REC (macro arg)")
	.Display.Refresh()

	,  := .Keys.ReadKey()
	if  {
		return
	}

	.Macros.StartRecord()
}

// Reads a key from the keyboard, and runs the macro stored for this key identitier.
// This mimics the Vim-style or running macros. If no macro is recorded for this key,
// or if the key is invalid, nothing happens.
func ( *Shell) () {
	 := .Keymap.PendingCursor()
	defer ()

	.Hint.SetTemporary(color.Dim + "Run (macro arg)")
	.Display.Refresh()

	,  := .Keys.ReadKey()
	if  {
		return
	}

	.Macros.RunMacro()
}

//
// Miscellaneous ---------------------------------------------------------------
//

// Read in the contents of the inputrc file, and incorporate
// any bindings or variable assignments found there.
func ( *Shell) () {
	 := .Keymap.Main()

	 := .Keymap.ReloadConfig(.Opts...)
	if  != nil {
		.Hint.SetTemporary(color.FgRed + "Inputrc reload error: " + .Error())
		return
	}

	defer .Keymap.UpdateCursor()

	// Reload keymap settings and cursor
	 := .Keymap.Main()

	if  !=  {
		switch  {
		case keymap.Emacs, keymap.EmacsStandard, keymap.EmacsMeta, keymap.EmacsCtrlX:
			.emacsEditingMode()
		case keymap.Vi, keymap.ViCommand, keymap.ViMove:
			.viCommandMode()
		case keymap.ViInsert:
			.viInsertMode()
		}
	}

	// Notify successfully reloaded
	.Hint.SetTemporary(color.FgGreen + "Inputrc reloaded")
}

// Abort the current editing command.
// If one of the completion or non/incremental-search modes
// are active, only cancel them and nothing else.
func ( *Shell) () {
	// Reset any visual selection and iterations.
	.Iterations.Reset()
	.selection.Reset()

	// Cancel active completion insertion and/or incremental search.
	if .completer.AutoCompleting() || .completer.IsInserting() {
		.Hint.Reset()
		.completer.ResetForce()

		return
	}

	// Cancel non-incremental search modes.
	, ,  := .completer.NonIncrementallySearching()
	if  {
		.completer.NonIsearchStop()
		return
	}

	// And only return to the caller if the abort was
	// called by one of the builtin/config terminators.
	// All others should generally be OS signals.
	if !.Keymap.InputIsTerminator() {
		return
	}

	if .Config.GetBool("echo-control-characters") {
		 := .Keys.Caller()
		if [0] == rune(inputrc.Unescape(`\C-C`)[0]) {
			,  := strutil.Quote([0])
			fmt.Print(string())
		}
	}

	// If no line was active,
	.Display.AcceptLine()
	.History.Accept(false, false, ErrInterrupt)
}

// If the metafied character x is uppercase, run the command
// that is bound to the corresponding metafied lowercase character.
// The behavior is undefined if x is already lowercase.
func ( *Shell) () {
	.History.SkipSave()

	 := .Keys.Caller()

	 := false

	// Get rid of the escape if it's a prefix
	if len() > 1 && [0] == inputrc.Esc {
		 = true
		 = [1:]
	} else if len() == 1 && inputrc.IsMeta([0]) {
		 = []rune{inputrc.Demeta([0])}
	}

	// Undefined behavior if the key is already lowercase.
	if unicode.IsLower([0]) {
		return
	}

	[0] = unicode.ToLower([0])

	// Feed back the keys with meta prefix or encoding
	if  {
		 := append([]rune{inputrc.Esc}, ...)
		.Keys.Feed(false, ...)
	} else {
		.Keys.Feed(false, inputrc.Enmeta([0]))
	}
}

// Metafy the next character typed.  ESC f is equivalent to Meta-f.
func ( *Shell) () {
	.History.SkipSave()

	 := .Keymap.PendingCursor()
	defer ()

	,  := .Keys.ReadKey()
	if  {
		return
	}

	// And feed them back to be used on the next loop.
	 := append([]rune{inputrc.Esc}, )
	.Keys.Feed(false, ...)
}

// Incrementally undo the last text modification.
// Note that when invoked from vi command mode, the full
// prior change made in insert mode is reverted, the changes
// having been merged when command mode was selected.
func ( *Shell) () {
	.History.Undo()
}

// Undo all changes made to this line.
// This is like executing the undo command enough
// times to return the line to its initial state.
func ( *Shell) () {
	.History.Revert()
}

// Set the mark to the point. If a numeric argument is
// supplied, the mark is set to that position.
func ( *Shell) () {
	switch {
	case .Iterations.IsSet():
		.cursor.SetMark()
	default:
		 := .cursor.Pos()
		 := .Iterations.Get()

		if  > .line.Len()-1 {
			return
		}

		.cursor.Set()
		.cursor.SetMark()
		.cursor.Set()
	}
}

// Swap the point with the mark.  The current cursor position
// is set to the saved position, and the old cursor position
// is saved as the mark.
func ( *Shell) () {
	// Deactivate mark if out of bound
	if .cursor.Mark() > .line.Len() {
		.cursor.ResetMark()
	}

	// And set it to start if negative.
	if .cursor.Mark() < 0 {
		 := .cursor.Pos()
		.cursor.Set(0)
		.cursor.SetMark()
		.cursor.Set()
	} else {
		 := .cursor.Mark()

		.cursor.SetMark()
		.cursor.Set()

		.selection.MarkRange(.cursor.Mark(), .cursor.Pos())
		.selection.Visual(false)
	}
}

// A character is read and point is moved to the next
// occurrence of that character.  A negative argument
// searches for previous occurrences.
func ( *Shell) () {
	if .Iterations.Get() < 0 {
		.viFindChar(false, false)
	} else {
		.viFindChar(true, false)
	}
}

// A character is read and point is moved to the previous
// occurrence of that character.  A negative argument
// searches for subsequent occurrences.
func ( *Shell) () {
	if .Iterations.Get() < 0 {
		.viFindChar(true, false)
	} else {
		.viFindChar(false, false)
	}
}

// Without a numeric argument, the value of the readline
// comment-begin variable is inserted at the beginning of the
// current line.  If a numeric argument is supplied, this
// command acts as a toggle: if the characters at the
// beginning of the line do not match the value of
// comment-begin, the value is inserted, otherwise the
// characters in comment-begin are deleted from the beginning
// of the line.  In either case, the line is accepted as if a
// newline had been typed.  The default value of
// comment-begin makes the current line a shell comment.
// If a numeric argument causes the comment character to be
// removed, the line will be executed by the shell.
func ( *Shell) () {
	 := strings.Trim(.Config.GetString("comment-begin"), "\"")

	switch {
	case !.Iterations.IsSet():
		// Without numeric argument, insert comment at the beginning of the line.
		 := .cursor.Pos()
		.cursor.BeginningOfLine()
		.cursor.InsertAt([]rune()...)
		.cursor.Set()

	default:
		// Or with one, toggle the current line commenting.
		 := .cursor.Pos()
		.cursor.BeginningOfLine()

		 := .cursor.Pos()
		 :=  + len()

		.cursor.Set()

		 :=  < .line.Len()

		if  && string((*.line)[:]) ==  {
			.line.Cut(, )
			.cursor.Move(-1 * len())
		} else {
			.line.Insert(, []rune()...)
			.cursor.Move(1 * len())
		}
	}

	// Either case, accept the line as it is.
	.acceptLineWith(false, false)
}

// Print all of the functions and their key bindings to the
// readline output stream.  If a numeric argument is
// supplied, the output is formatted in such a way that it
// can be made part of an inputrc file.
func ( *Shell) () {
	.Display.ClearHelpers()
	fmt.Println()

	defer func() {
		.Prompt.PrimaryPrint()
		.Display.Refresh()
	}()

	 := .Iterations.IsSet()
	.Keymap.PrintBinds(string(.Keymap.Main()), )
}

// Print all of the settable variables and their values to
// the readline output stream.  If a numeric argument is
// supplied, the output is formatted in such a way that it
// can be made part of an inputrc file.
func ( *Shell) () {
	.Display.ClearHelpers()
	fmt.Println()

	defer func() {
		.Prompt.PrimaryPrint()
		.Display.Refresh()
	}()

	// Get all variables and their values, alphabetically sorted.
	var  []string

	for  := range .Config.Vars {
		 = append(, )
	}

	sort.Strings()

	// Either print in inputrc format, or wordly one.
	if .Iterations.IsSet() {
		for ,  := range  {
			 := .Config.Vars[]
			fmt.Printf("set %s %v\n", , )
		}
	} else {
		for ,  := range  {
			 := .Config.Vars[]
			fmt.Printf("%s is set to `%v'\n", , )
		}
	}
}

// Print all of the readline key sequences bound to macros
// and the strings they output.  If a numeric argument is
// supplied, the output is formatted in such a way that it
// can be made part of an inputrc file.
func ( *Shell) () {
	.Display.ClearHelpers()
	fmt.Println()

	defer func() {
		.Prompt.PrimaryPrint()
		.Display.Refresh()
	}()

	// We print the macros bound to the current keymap only.
	 := .Config.Binds[string(.Keymap.Main())]
	if len() == 0 {
		return
	}

	var  []string

	for ,  := range  {
		if .Macro {
			 = append(, inputrc.Escape())
		}
	}

	sort.Strings()

	if .Iterations.IsSet() {
		for ,  := range  {
			 := inputrc.Escape([inputrc.Unescape()].Action)
			fmt.Printf("\"%s\": \"%s\"\n", , )
		}
	} else {
		for ,  := range  {
			 := inputrc.Escape([inputrc.Unescape()].Action)
			fmt.Printf("%s outputs %s\n", , )
		}
	}
}

// Invoke an editor on the current command line, and execute the result as shell commands.
// Readline attempts to invoke $VISUAL, $EDITOR, and emacs as the editor, in that order.
func ( *Shell) () {
	 := *.line

	// Edit in editor
	,  := .Buffers.EditBuffer(, "", "", .Keymap.IsEmacs())
	if  != nil || (len() == 0 && len() != 0) {
		.History.SkipSave()

		 := strings.ReplaceAll(.Error(), "\n", "")
		 := fmt.Sprintf(color.FgRed+"Editor error: %s", )
		.Hint.SetTemporary()

		return
	}

	// Update our line and return it the caller.
	.line.Set(...)
	.Display.AcceptLine()
	.History.Accept(false, false, nil)
}

func ( *Shell) () {
	 := *.line
	 := .Keymap.Main()

	// Edit in editor
	,  := .Buffers.EditBuffer(, "", "", .Keymap.IsEmacs())
	if  != nil || (len() == 0 && len() != 0) {
		.History.SkipSave()

		 := strings.ReplaceAll(.Error(), "\n", "")
		 := fmt.Sprintf(color.FgRed+"Editor error: %s", )
		.Hint.SetTemporary()

		return
	}

	// Update our line
	.line.Set(...)

	// We're done with visual mode when we were in.
	switch  {
	case keymap.Emacs, keymap.EmacsStandard, keymap.EmacsMeta, keymap.EmacsCtrlX:
		.emacsEditingMode()
	}
}

// Incrementally redo undone text modifications.
func ( *Shell) () {
	.History.Redo()
}

// Considers the blank word under cursor, and tries a series of regular expressions on it
// to match various patterns: URL and their various subcomponents (host/path/params, etc).
//
// When one of the regular expressions succeeds, the match is visually selected,
// otherwise nothing is selected (if selection was active, it will stay the same)
//
// When repeatedly calling this function while in visual selection mode, the shell will
// cycle through either the current matcher's capturing subgroups (such as the parts of a URL),
// or cycle through the next matcher (for instance, attempting to grap an IP after trying URL).
func ( *Shell) () {
	.History.SkipSave()

	// Always try to find a match within the blank word under cursor.
	,  := .line.SelectBlankWord(.cursor.Pos())

	// Run the regexp matchers.
	, ,  := .selection.SelectKeyword(, , true)
	if ! {
		return
	}

	// The matchers succeeded, we now have a selection active,
	// but the cursor should be moved to the end of it.
	.cursor.Set()
	.selection.Visual(false)
}

// Identical to select-keyword-prev, except that the matcher/subgroup cycling occurs backward.
func ( *Shell) () {
	.History.SkipSave()

	// Always try to find a match within the blank word under cursor.
	,  := .line.SelectBlankWord(.cursor.Pos())

	// Run the regexp matchers.
	, ,  := .selection.SelectKeyword(, , false)
	if ! {
		return
	}

	// The matchers succeeded, we now have a selection active,
	// but the cursor should be moved to the end of it.
	.cursor.Set()
	.selection.Visual(false)
}