package completion

import (
	

	
	
	
)

// UpdateInserted should be called only once in between the two shell keymaps
// (local/main) in the main readline loop, to either drop or confirm a virtually
// inserted candidate.
func ( *Engine) {
	// If the user currently has a completion selected, any change
	// in the input line will drop the current completion list, in
	// effect deactivating the completion engine.
	// This is so that when a user asks for the list of choices, but
	// then deletes or types something in the input line, the list
	// is still displayed to the user, otherwise it's removed.
	// This does not apply when autocomplete is on.
	 := len(.selected.Value) != 0
	if !.auto {
		defer .ClearMenu()
	}

	// If autocomplete is on, we also drop the list of generated
	// completions, because it will be recomputed shortly after.
	// Do the same when using incremental search, except if the
	// last key typed is an escape, in which case the user wants
	// to quit incremental search but keeping any selected comp.
	 := .mustRemoveInserted()
	 := .keymap.Local() != keymap.Isearch && !.autoForce

	.Cancel(, )

	if  && .autoForce && len(.selected.Value) == 0 {
		.Reset()
	}
}

// TrimSuffix removes the last inserted completion's suffix if the required constraints
// are satisfied (among which the index position, the suffix matching patterns, etc).
func ( *Engine) () {
	if .line.Len() == 0 || .cursor.Pos() == 0 || len(.selected.Value) > 0 {
		return
	}

	// If our suffix matcher was registered at a different
	// place in our line, then it's an orphan.
	if .sm.pos != .cursor.Pos()-1 || .sm.string == "" {
		.sm = SuffixMatcher{}
		return
	}

	 := (*.line)[.cursor.Pos()-1]
	 := .keys.Caller()
	 := [0]

	// Special case when completing paths: if the comp is ended
	// by a slash, only remove this slash if the inserted key is
	// one of the suffix matchers, otherwise keep it.
	if  == '/' &&  != inputrc.Space && notMatcher(, .sm.string) {
		return
	}

	// If the key is a space or matches the suffix matcher, cut the suffix.
	if .sm.Matches(string()) || unicode.IsSpace() {
		.cursor.Dec()
		.line.CutRune(.cursor.Pos())
	}

	// But when the key is a space, we also drop the suffix matcher,
	// because the user is done with this precise completion (or group of).
	if unicode.IsSpace() {
		.sm = SuffixMatcher{}
	}
}

// refreshLine - Either insert the only candidate in the real line
// and drop the current completion list, prefix, keymaps, etc, or
// swap the formerly selected candidate with the new one.
func ( *Engine) () {
	if .noCompletions() {
		.Cancel(true, true)
		return
	}

	if .currentGroup() == nil {
		return
	}

	// Incremental search is a special case, because the user may
	// want to keep searching for another match, so we don't drop
	// the completion list and exit the incremental search mode.
	if .hasUniqueCandidate() && .keymap.Local() != keymap.Isearch {
		.acceptCandidate()
		.ResetForce()
	} else {
		.insertCandidate()
	}
}

// acceptCandidate inserts the currently selected candidate into the real input line.
func ( *Engine) () {
	 := .currentGroup()
	if  == nil {
		return
	}

	.selected = .selected()

	// Prepare the completion candidate, remove the
	// prefix part and save its sufffixes for later.
	 := .prepareSuffix()
	.inserted = []rune()

	// Remove the line prefix and insert the candidate.
	.cursor.Move(-1 * len(.prefix))
	.line.Cut(.cursor.Pos(), .cursor.Pos()+len(.prefix))
	.cursor.InsertAt(.inserted...)

	// And forget about this inserted completion.
	.inserted = make([]rune, 0)
	.prefix = ""
	.suffix = ""
}

// insertCandidate inserts a completion candidate into the virtual (completed) line.
func ( *Engine) () {
	 := .currentGroup()
	if  == nil {
		return
	}

	.selected = .selected()

	if len(.selected.Value) < len(.prefix) {
		return
	}

	// Prepare the completion candidate, remove the
	// prefix part and save its sufffixes for later.
	 := .prepareSuffix()
	.inserted = []rune()

	// Copy the current (uncompleted) line/cursor.
	 := core.Line(string(*.line))
	.compLine = &

	.compCursor = core.NewCursor(.compLine)
	.compCursor.Set(.cursor.Pos())

	// Remove the line prefix and insert the candidate.
	.compCursor.Move(-1 * len(.prefix))
	.compLine.Cut(.compCursor.Pos(), .compCursor.Pos()+len(.prefix))
	.compCursor.InsertAt(.inserted...)
}

// prepareSuffix caches any suffix matcher associated with the completion candidate
// to be inserted/accepted into the input line, and trims it if required at this point.
func ( *Engine) () ( string) {
	 := .currentGroup()
	if  == nil {
		return
	}

	 = .selected.Value
	 := len(.prefix)

	// When the completion has a size of 1, don't remove anything:
	// stacked flags, for example, will never be inserted otherwise.
	if len() > 0 && len([:]) <= 1 {
		return
	}

	// If we are to even consider removing a suffix, we keep the suffix
	// matcher for later: whatever the decision we take here will be identical
	// to the one we take while removing suffix in "non-virtual comp" mode.
	.sm = .noSpace
	.sm.pos = .cursor.Pos() + len() -  - 1

	return 
}

func ( *Engine) () {
	// The completed line includes any currently selected
	// candidate, just overwrite it with the normal line.
	.compLine.Set(*.line...)
	.compCursor.Set(.cursor.Pos())

	// And no virtual candidate anymore.
	.selected = Candidate{}
}

func ( *Engine) () bool {
	// All other completion modes do not want
	// the candidate to be removed from the line.
	if .keymap.Local() != keymap.Isearch {
		return false
	}

	// Normally, we should have a key.
	,  := core.PeekKey(.keys)
	if  {
		return false
	}

	// Some keys trigger behavior different from the normal one:
	// Ex: if the key is a letter, the isearch buffer is updated
	// and the line-inserted match might be different, so remove.
	// If the key is 'Enter', the line will likely be accepted
	// with the currently inserted candidate.
	switch rune() {
	case inputrc.Esc, inputrc.Return:
		return false
	default:
		return true
	}
}

func notMatcher( rune,  string) bool {
	for ,  := range  {
		if  ==  {
			return false
		}
	}

	return true
}