package console

import (
	
	
	
	

	
	
)

var (
	splitChars        = " \n\t"
	singleChar        = '\''
	doubleChar        = '"'
	escapeChar        = '\\'
	doubleEscapeChars = "$`\"\n\\"
)

var (
	errUnterminatedSingleQuote = errors.New("unterminated single-quoted string")
	errUnterminatedDoubleQuote = errors.New("unterminated double-quoted string")
	errUnterminatedEscape      = errors.New("unterminated backslash-escape")
)

// parse is in charge of removing all comments from the input line
// before execution, and if successfully parsed, split into words.
func ( *Console) ( string) ( []string,  error) {
	 := strings.NewReader()
	 := syntax.NewParser(syntax.KeepComments(false))

	// Parse the shell string a syntax, removing all comments.
	,  := .Parse(, "")
	if  != nil {
		return nil, 
	}

	var  bytes.Buffer

	 = syntax.NewPrinter().Print(&, )
	if  != nil {
		return nil, 
	}

	// Split the line into shell words.
	return shellquote.Split(.String())
}

// acceptMultiline determines if the line just accepted is complete (in which case
// we should execute it), or incomplete (in which case we must read in multiline).
func ( *Console) ( []rune) ( bool) {
	// Errors are either: unterminated quotes, or unterminated escapes.
	, ,  := split(string(), false)
	if  == nil {
		return true
	}

	// Currently, unterminated quotes are obvious to treat: keep reading.
	switch  {
	case errUnterminatedDoubleQuote, errUnterminatedSingleQuote:
		return false
	case errUnterminatedEscape:
		if len() > 0 && [len()-1] == '\\' {
			return false
		}

		return true
	}

	return true
}

// split has been copied from go-shellquote and slightly modified so as to also
// return the remainder when the parsing failed because of an unterminated quote.
func split( string,  bool) ( []string,  string,  error) {
	var  bytes.Buffer
	 = make([]string, 0)

	for len() > 0 {
		// skip any splitChars at the start
		,  := utf8.DecodeRuneInString()
		if strings.ContainsRune(splitChars, ) {
			// Keep these characters in the result when higlighting the line.
			if  {
				if len() == 0 {
					 = append(, string())
				} else {
					[len()-1] += string()
				}
			}

			 = [:]

			continue
		} else if  == escapeChar {
			// Look ahead for escaped newline so we can skip over it
			 := [:]
			if len() == 0 {
				if  {
					 = string(escapeChar)
				}

				 = errUnterminatedEscape

				return , , 
			}

			,  := utf8.DecodeRuneInString()
			if  == '\n' {
				if  {
					if len() == 0 {
						 = append(, string()+string())
					} else {
						[len()-1] += string() + string()
					}
				}

				 = [:]

				continue
			}
		}

		var  string

		, ,  = splitWord(, &, )
		if  != nil {
			 = 
			return , , 
		}

		 = append(, )
	}

	return , , 
}

// splitWord has been modified to return the remainder of the input (the part that has not been
// added to the buffer) even when an error is returned.
func splitWord( string,  *bytes.Buffer,  bool) ( string,  string,  error) {
	.Reset()

:
	{
		 := 
		for len() > 0 {
			,  := utf8.DecodeRuneInString()
			 = [:]
			if  == singleChar {
				.WriteString([0 : len()-len()-])
				 = 
				goto 
			} else if  == doubleChar {
				.WriteString([0 : len()-len()-])
				 = 
				goto 
			} else if  == escapeChar {
				.WriteString([0 : len()-len()-])
				if  {
					.WriteRune()
				}
				 = 
				goto 
			} else if strings.ContainsRune(splitChars, ) {
				.WriteString([0 : len()-len()-])
				if  {
					.WriteRune()
				}

				return .String(), , nil
			}
		}
		if len() > 0 {
			.WriteString()
			 = ""
		}
		goto 
	}

:
	{
		if len() == 0 {
			if  {
				 = .String() + 
			}
			return "", , errUnterminatedEscape
		}
		,  := utf8.DecodeRuneInString()
		if  == '\n' {
			// a backslash-escaped newline is elided from the output entirely
		} else {
			.WriteString([:])
		}
		 = [:]
	}

	goto 

:
	{
		 := strings.IndexRune(, singleChar)
		if  == -1 {
			if  {
				 = .String() + seqFgYellow + string(singleChar) + 
			}
			return "", , errUnterminatedSingleQuote
		}
		// Catch up opening quote
		if  {
			.WriteString(seqFgYellow)
			.WriteRune(singleChar)
		}

		.WriteString([0:])
		 = [+1:]

		if  {
			.WriteRune(singleChar)
			.WriteString(seqFgReset)
		}
		goto 
	}

:
	{
		 := 
		for len() > 0 {
			,  := utf8.DecodeRuneInString()
			 = [:]
			if  == doubleChar {
				// Catch up opening quote
				if  {
					.WriteString(seqFgYellow)
					.WriteRune()
				}

				.WriteString([0 : len()-len()-])

				if  {
					.WriteRune()
					.WriteString(seqFgReset)
				}
				 = 
				goto 
			} else if  == escapeChar && ! {
				// bash only supports certain escapes in double-quoted strings
				,  := utf8.DecodeRuneInString()
				 = [:]
				if strings.ContainsRune(doubleEscapeChars, ) {
					.WriteString([0 : len()-len()--])
					if  == '\n' {
						// newline is special, skip the backslash entirely
					} else {
						.WriteRune()
					}
					 = 
				}
			}
		}

		if  {
			 = .String() + seqFgYellow + string(doubleChar) + 
		}

		return "", , errUnterminatedDoubleQuote
	}

:
	return .String(), , nil
}

func trimSpacesMatch( []string) ( []string) {
	for ,  := range  {
		 = append(, strings.TrimSpace())
	}

	return
}

func ( *Console) ( string) bool {
	 := true

	for ,  := range  {
		if !strings.ContainsRune(string(.EmptyChars), ) {
			 = false
			break
		}
	}

	return 
}