From 574e3371320a809aa584d9d8b47fa31d3d675728 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 20 Sep 2015 11:19:10 +0100 Subject: [PATCH] Improve command completion by taking into account quoting of arguments --- src/command_manager.cc | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/command_manager.cc b/src/command_manager.cc index 08589f0a..9e08e0e3 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -48,6 +48,7 @@ struct Token enum class Type { Raw, + RawQuoted, RawEval, ShellExpand, RegisterExpand, @@ -188,7 +189,7 @@ template Token::Type token_type(StringView type_name) { if (type_name == "") - return Token::Type::Raw; + return Token::Type::RawQuoted; else if (type_name == "sh") return Token::Type::ShellExpand; else if (type_name == "reg") @@ -200,7 +201,7 @@ Token::Type token_type(StringView type_name) else if (throw_on_invalid) throw unknown_expand{type_name}; else - return Token::Type::Raw; + return Token::Type::RawQuoted; } void skip_blanks_and_comments(Reader& reader) @@ -295,7 +296,7 @@ TokenList parse(StringView line) if (throw_on_unterminated and not reader) throw parse_error{format("unterminated string {0}...{0}", c)}; result.emplace_back(c == '"' ? Token::Type::RawEval - : Token::Type::Raw, + : Token::Type::RawQuoted, start, reader.pos, coord, std::move(token)); } else if (c == '%') @@ -346,6 +347,7 @@ String expand_token(const Token& token, const Context& context, case Token::Type::RawEval: return expand(content, context, shell_params, env_vars); case Token::Type::Raw: + case Token::Type::RawQuoted: return content; default: kak_assert(false); } @@ -483,7 +485,8 @@ CommandInfo CommandManager::command_info(const Context& context, StringView comm CommandInfo res; if (cmd_idx == tokens.size() or - tokens[cmd_idx].type() != Token::Type::Raw) + (tokens[cmd_idx].type() != Token::Type::Raw and + tokens[cmd_idx].type() != Token::Type::RawQuoted)) return res; auto cmd = find_command(context, tokens[cmd_idx].content()); @@ -501,7 +504,9 @@ CommandInfo CommandManager::command_info(const Context& context, StringView comm it != tokens.end() and it->type() != Token::Type::CommandSeparator; ++it) { - if (it->type() == Token::Type::Raw or it->type() == Token::Type::RawEval) + if (it->type() == Token::Type::Raw or + it->type() == Token::Type::RawQuoted or + it->type() == Token::Type::RawEval) params.push_back(it->content()); } String helpstr = cmd->second.helper(context, params); @@ -554,7 +559,8 @@ Completions CommandManager::complete(const Context& context, // command name completion if (tokens.empty() or (tok_idx == cmd_idx and (tok_idx == tokens.size() or - tokens[tok_idx].type() == Token::Type::Raw))) + tokens[tok_idx].type() == Token::Type::Raw or + tokens[tok_idx].type() == Token::Type::RawQuoted))) { const bool is_end_token = tok_idx == tokens.size(); ByteCount cmd_start = is_end_token ? cursor_pos @@ -586,7 +592,7 @@ Completions CommandManager::complete(const Context& context, ByteCount cursor_pos_in_token = cursor_pos - start; const Token::Type type = tok_idx < tokens.size() ? - tokens[tok_idx].type() : Token::Type::Raw; + tokens[tok_idx].type() : Token::Type::Raw; switch (type) { case Token::Type::OptionExpand: @@ -599,6 +605,8 @@ Completions CommandManager::complete(const Context& context, cursor_pos_in_token), start); case Token::Type::Raw: + case Token::Type::RawQuoted: + case Token::Type::RawEval: { if (tokens[cmd_idx].type() != Token::Type::Raw) return Completions{}; @@ -615,14 +623,16 @@ Completions CommandManager::complete(const Context& context, params.push_back(it->content()); if (tok_idx == tokens.size()) params.push_back(""); - Completions completions = command_it->second.completer( + Completions completions = offset_pos(command_it->second.completer( context, flags, params, tok_idx - cmd_idx - 1, - cursor_pos_in_token); - completions.start += start; - completions.end += start; + cursor_pos_in_token), start); - for (auto& candidate : completions.candidates) - candidate = escape(candidate, " \t;", '\\'); + if (type != Token::Type::RawQuoted) + { + StringView to_escape = type == Token::Type::Raw ? "% \t;" : "%"; + for (auto& candidate : completions.candidates) + candidate = escape(candidate, to_escape, '\\'); + } return completions; }