1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 16:17:34 +00:00

Shell: Escape program-provided completions unless they're marked as code

This makes it so program-provided completions don't have to worry about
escaping, making the Shell the only authority on escaping.
This commit is contained in:
Ali Mohammad Pur 2023-11-16 23:56:05 +03:30 committed by Ali Mohammad Pur
parent 2dba79bc6b
commit ad4470bc39

View file

@ -16,8 +16,10 @@
#include <AK/QuickSort.h> #include <AK/QuickSort.h>
#include <AK/ScopeGuard.h> #include <AK/ScopeGuard.h>
#include <AK/ScopedValueRollback.h> #include <AK/ScopedValueRollback.h>
#include <AK/StdLibExtras.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <AK/TemporaryChange.h> #include <AK/TemporaryChange.h>
#include <AK/Tuple.h>
#include <AK/URL.h> #include <AK/URL.h>
#include <LibCore/DateTime.h> #include <LibCore/DateTime.h>
#include <LibCore/DirIterator.h> #include <LibCore/DirIterator.h>
@ -1341,11 +1343,35 @@ Shell::SpecialCharacterEscapeMode Shell::special_character_escape_mode(u32 code_
} }
} }
static DeprecatedString do_escape(Shell::EscapeMode escape_mode, auto& token) template<typename... Offsets>
static DeprecatedString do_escape(Shell::EscapeMode escape_mode, auto& token, Offsets&... offsets)
{ {
StringBuilder builder; StringBuilder builder;
size_t offset_from_original = 0;
auto set_offset = [&](auto& offset) {
offset.value() = builder.length();
offset.clear();
return true;
};
auto check_offset = [&](auto& offset) {
if (offset == offset_from_original)
set_offset(offset);
};
auto maybe_offsets = Tuple { Optional<Offsets&> { offsets }... };
auto check_offsets = [&] {
maybe_offsets.apply_as_args([&]<typename... Args>(Args&... args) {
(check_offset(args), ...);
});
};
for (auto c : token) { for (auto c : token) {
static_assert(sizeof(c) == sizeof(u32) || sizeof(c) == sizeof(u8)); static_assert(sizeof(c) == sizeof(u32) || sizeof(c) == sizeof(u8));
check_offsets();
offset_from_original++;
switch (Shell::special_character_escape_mode(c, escape_mode)) { switch (Shell::special_character_escape_mode(c, escape_mode)) {
case Shell::SpecialCharacterEscapeMode::Untouched: case Shell::SpecialCharacterEscapeMode::Untouched:
if constexpr (sizeof(c) == sizeof(u8)) if constexpr (sizeof(c) == sizeof(u8))
@ -1402,7 +1428,7 @@ static DeprecatedString do_escape(Shell::EscapeMode escape_mode, auto& token)
break; break;
} }
} }
check_offsets();
return builder.to_deprecated_string(); return builder.to_deprecated_string();
} }
@ -2019,13 +2045,20 @@ ErrorOr<Vector<Line::CompletionSuggestion>> Shell::complete_via_program_itself(s
dbgln("Proxy completion for {}", argv); dbgln("Proxy completion for {}", argv);
suggestions.extend(complete(argv)); suggestions.extend(complete(argv));
} else if (kind == "plain") { } else if (kind == "plain") {
Line::CompletionSuggestion suggestion { auto completion_text = object.get_deprecated_string("completion"sv).value_or("");
object.get_deprecated_string("completion"sv).value_or(""), auto trailing_text = object.get_deprecated_string("trailing_trivia"sv).value_or("");
object.get_deprecated_string("trailing_trivia"sv).value_or(""), auto display_text = object.get_deprecated_string("display_trivia"sv).value_or("");
object.get_deprecated_string("display_trivia"sv).value_or(""), auto static_offset = object.get_u64("static_offset"sv).value_or(0);
}; auto invariant_offset = object.get_u64("invariant_offset"sv).value_or(0);
suggestion.static_offset = object.get_u64("static_offset"sv).value_or(0); if (!object.get_bool("treat_as_code"sv).value_or(false)) {
suggestion.invariant_offset = object.get_u64("invariant_offset"sv).value_or(0); completion_text = do_escape(EscapeMode::Bareword, completion_text, static_offset, invariant_offset);
trailing_text = escape_token(trailing_text, EscapeMode::Bareword);
display_text = escape_token(display_text, EscapeMode::Bareword);
}
Line::CompletionSuggestion suggestion { move(completion_text), move(trailing_text), move(display_text) };
suggestion.static_offset = static_offset;
suggestion.invariant_offset = invariant_offset;
suggestion.allow_commit_without_listing = object.get_bool("allow_commit_without_listing"sv).value_or(true); suggestion.allow_commit_without_listing = object.get_bool("allow_commit_without_listing"sv).value_or(true);
suggestions.append(move(suggestion)); suggestions.append(move(suggestion));
} else { } else {