mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:38:12 +00:00
Shell: Fix completing barewords with escapes
e.g. completing `foo\ bar` now works as expected.
This commit is contained in:
parent
7059ca9b15
commit
9523bcbfe1
3 changed files with 43 additions and 21 deletions
|
@ -232,8 +232,8 @@ Vector<Line::CompletionSuggestion> Node::complete_for_editor(Shell& shell, size_
|
||||||
auto matching_node = hit_test_result.matching_node;
|
auto matching_node = hit_test_result.matching_node;
|
||||||
if (matching_node) {
|
if (matching_node) {
|
||||||
if (matching_node->is_bareword()) {
|
if (matching_node->is_bareword()) {
|
||||||
auto corrected_offset = offset - matching_node->position().start_offset;
|
|
||||||
auto* node = static_cast<BarewordLiteral*>(matching_node.ptr());
|
auto* node = static_cast<BarewordLiteral*>(matching_node.ptr());
|
||||||
|
auto corrected_offset = find_offset_into_node(node->text(), offset - matching_node->position().start_offset);
|
||||||
|
|
||||||
if (corrected_offset > node->text().length())
|
if (corrected_offset > node->text().length())
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -1114,30 +1114,35 @@ String Shell::escape_token_for_single_quotes(const String& token)
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Shell::is_special(char c)
|
||||||
|
{
|
||||||
|
switch (c) {
|
||||||
|
case '\'':
|
||||||
|
case '"':
|
||||||
|
case '$':
|
||||||
|
case '|':
|
||||||
|
case '>':
|
||||||
|
case '<':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case '&':
|
||||||
|
case '\\':
|
||||||
|
case ' ':
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String Shell::escape_token(const String& token)
|
String Shell::escape_token(const String& token)
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
|
||||||
for (auto c : token) {
|
for (auto c : token) {
|
||||||
switch (c) {
|
if (is_special(c))
|
||||||
case '\'':
|
|
||||||
case '"':
|
|
||||||
case '$':
|
|
||||||
case '|':
|
|
||||||
case '>':
|
|
||||||
case '<':
|
|
||||||
case '(':
|
|
||||||
case ')':
|
|
||||||
case '{':
|
|
||||||
case '}':
|
|
||||||
case '&':
|
|
||||||
case '\\':
|
|
||||||
case ' ':
|
|
||||||
builder.append('\\');
|
builder.append('\\');
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
builder.append(c);
|
builder.append(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1256,7 +1261,6 @@ Vector<Line::CompletionSuggestion> Shell::complete()
|
||||||
Vector<Line::CompletionSuggestion> Shell::complete_path(const String& base, const String& part, size_t offset)
|
Vector<Line::CompletionSuggestion> Shell::complete_path(const String& base, const String& part, size_t offset)
|
||||||
{
|
{
|
||||||
auto token = offset ? part.substring_view(0, offset) : "";
|
auto token = offset ? part.substring_view(0, offset) : "";
|
||||||
StringView original_token = token;
|
|
||||||
String path;
|
String path;
|
||||||
|
|
||||||
ssize_t last_slash = token.length() - 1;
|
ssize_t last_slash = token.length() - 1;
|
||||||
|
@ -1294,7 +1298,7 @@ Vector<Line::CompletionSuggestion> Shell::complete_path(const String& base, cons
|
||||||
// `/foo/', but rather just `bar...'
|
// `/foo/', but rather just `bar...'
|
||||||
auto token_length = escape_token(token).length();
|
auto token_length = escape_token(token).length();
|
||||||
if (m_editor)
|
if (m_editor)
|
||||||
m_editor->suggest(token_length, original_token.length() - token_length);
|
m_editor->suggest(token_length, last_slash + 1);
|
||||||
|
|
||||||
// only suggest dot-files if path starts with a dot
|
// only suggest dot-files if path starts with a dot
|
||||||
Core::DirIterator files(path,
|
Core::DirIterator files(path,
|
||||||
|
|
|
@ -156,6 +156,7 @@ public:
|
||||||
static String escape_token_for_single_quotes(const String& token);
|
static String escape_token_for_single_quotes(const String& token);
|
||||||
static String escape_token(const String& token);
|
static String escape_token(const String& token);
|
||||||
static String unescape_token(const String& token);
|
static String unescape_token(const String& token);
|
||||||
|
static bool is_special(char c);
|
||||||
|
|
||||||
static bool is_glob(const StringView&);
|
static bool is_glob(const StringView&);
|
||||||
static Vector<StringView> split_path(const StringView&);
|
static Vector<StringView> split_path(const StringView&);
|
||||||
|
@ -330,4 +331,21 @@ static constexpr bool is_word_character(char c)
|
||||||
return c == '_' || (c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a');
|
return c == '_' || (c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline size_t find_offset_into_node(const String& unescaped_text, size_t escaped_offset)
|
||||||
|
{
|
||||||
|
size_t unescaped_offset = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
for (auto& c : unescaped_text) {
|
||||||
|
if (offset == escaped_offset)
|
||||||
|
return unescaped_offset;
|
||||||
|
|
||||||
|
if (Shell::is_special(c))
|
||||||
|
++offset;
|
||||||
|
++offset;
|
||||||
|
++unescaped_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return unescaped_offset;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue