summaryrefslogtreecommitdiff
path: root/Userland/Shell
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Shell')
-rw-r--r--Userland/Shell/AST.cpp20
-rw-r--r--Userland/Shell/Builtin.cpp14
-rw-r--r--Userland/Shell/ImmediateFunctions.cpp6
-rw-r--r--Userland/Shell/Parser.cpp4
-rw-r--r--Userland/Shell/Shell.cpp53
-rw-r--r--Userland/Shell/Shell.h10
-rw-r--r--Userland/Shell/main.cpp2
7 files changed, 59 insertions, 50 deletions
diff --git a/Userland/Shell/AST.cpp b/Userland/Shell/AST.cpp
index 8f079d10ab..095de9adbc 100644
--- a/Userland/Shell/AST.cpp
+++ b/Userland/Shell/AST.cpp
@@ -1000,7 +1000,7 @@ ErrorOr<RefPtr<Value>> DoubleQuotedString::run(RefPtr<Shell> shell)
builder.join(""sv, values);
- return make_ref_counted<StringValue>(builder.to_string().release_value_but_fixme_should_propagate_errors());
+ return make_ref_counted<StringValue>(TRY(builder.to_string()));
}
ErrorOr<void> DoubleQuotedString::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
@@ -1711,7 +1711,7 @@ ErrorOr<void> Execute::for_each_entry(RefPtr<Shell> shell, Function<ErrorOr<Iter
if (!shell)
return {};
- auto commands = shell->expand_aliases(move(unexpanded_commands));
+ auto commands = TRY(shell->expand_aliases(move(unexpanded_commands)));
if (m_capture_stdout) {
// Make sure that we're going to be running _something_.
@@ -1751,12 +1751,12 @@ ErrorOr<void> Execute::for_each_entry(RefPtr<Shell> shell, Function<ErrorOr<Iter
NothingLeft,
};
auto check_and_call = [&]() -> ErrorOr<CheckResult> {
- auto ifs = shell->local_variable_or("IFS"sv, "\n"sv);
+ auto ifs = TRY(shell->local_variable_or("IFS"sv, "\n"sv));
- if (auto offset = stream.offset_of(ifs.bytes()).release_value_but_fixme_should_propagate_errors(); offset.has_value()) {
+ if (auto offset = TRY(stream.offset_of(ifs.bytes())); offset.has_value()) {
auto line_end = offset.value();
if (line_end == 0) {
- stream.discard(ifs.length()).release_value_but_fixme_should_propagate_errors();
+ TRY(stream.discard(ifs.length()));
if (shell->options.inline_exec_keep_empty_segments)
if (TRY(callback(make_ref_counted<StringValue>(String {}))) == IterationDecision::Break) {
@@ -3741,7 +3741,7 @@ StringValue::~StringValue()
ErrorOr<String> StringValue::resolve_as_string(RefPtr<Shell> shell)
{
if (m_split.is_empty())
- return m_string;
+ return TRY(resolve_slices(shell, String { m_string }, m_slices));
return Value::resolve_as_string(shell);
}
@@ -3799,7 +3799,7 @@ ErrorOr<String> SimpleVariableValue::resolve_as_string(RefPtr<Shell> shell)
return resolve_slices(shell, String {}, m_slices);
if (auto value = TRY(resolve_without_cast(shell)); value != this)
- return value->resolve_as_string(shell);
+ return resolve_slices(shell, TRY(value->resolve_as_string(shell)), m_slices);
auto name = m_name.to_deprecated_string();
char* env_value = getenv(name.characters());
@@ -3826,7 +3826,7 @@ ErrorOr<NonnullRefPtr<Value>> SimpleVariableValue::resolve_without_cast(RefPtr<S
{
VERIFY(shell);
- if (auto value = shell->lookup_local_variable(m_name)) {
+ if (auto value = TRY(shell->lookup_local_variable(m_name))) {
auto result = value.release_nonnull();
// If a slice is applied, add it.
if (!m_slices.is_empty())
@@ -3868,11 +3868,11 @@ ErrorOr<Vector<String>> SpecialVariableValue::resolve_as_list(RefPtr<Shell> shel
case '$':
return { resolve_slices(shell, Vector { TRY(String::number(getpid())) }, m_slices) };
case '*':
- if (auto argv = shell->lookup_local_variable("ARGV"sv))
+ if (auto argv = TRY(shell->lookup_local_variable("ARGV"sv)))
return resolve_slices(shell, TRY(const_cast<Value&>(*argv).resolve_as_list(shell)), m_slices);
return resolve_slices(shell, Vector<String> {}, m_slices);
case '#':
- if (auto argv = shell->lookup_local_variable("ARGV"sv)) {
+ if (auto argv = TRY(shell->lookup_local_variable("ARGV"sv))) {
if (argv->is_list()) {
auto list_argv = static_cast<AST::ListValue const*>(argv.ptr());
return { resolve_slices(shell, Vector { TRY(String::number(list_argv->values().size())) }, m_slices) };
diff --git a/Userland/Shell/Builtin.cpp b/Userland/Shell/Builtin.cpp
index 9741ab0447..e2bb86365c 100644
--- a/Userland/Shell/Builtin.cpp
+++ b/Userland/Shell/Builtin.cpp
@@ -544,7 +544,7 @@ ErrorOr<int> Shell::builtin_export(Main::Arguments arguments)
auto parts = value.split_limit('=', 2);
if (parts.size() == 1) {
- auto value = lookup_local_variable(parts[0]);
+ auto value = TRY(lookup_local_variable(parts[0]));
if (value) {
auto values = TRY(const_cast<AST::Value&>(*value).resolve_as_list(*this));
StringBuilder builder;
@@ -932,7 +932,7 @@ ErrorOr<int> Shell::builtin_shift(Main::Arguments arguments)
if (count < 1)
return 0;
- auto argv_ = lookup_local_variable("ARGV"sv);
+ auto argv_ = TRY(lookup_local_variable("ARGV"sv));
if (!argv_) {
warnln("shift: ARGV is unset");
return 1;
@@ -965,7 +965,7 @@ ErrorOr<int> Shell::builtin_source(Main::Arguments arguments)
if (!parser.parse(arguments))
return 1;
- auto previous_argv = lookup_local_variable("ARGV"sv);
+ auto previous_argv = TRY(lookup_local_variable("ARGV"sv));
ScopeGuard guard { [&] {
if (!args.is_empty())
set_local_variable("ARGV", const_cast<AST::Value&>(*previous_argv));
@@ -1008,7 +1008,7 @@ ErrorOr<int> Shell::builtin_time(Main::Arguments arguments)
for (auto& arg : args)
command.argv.append(TRY(String::from_utf8(arg)));
- auto commands = expand_aliases({ move(command) });
+ auto commands = TRY(expand_aliases({ move(command) }));
AK::Statistics iteration_times;
@@ -1146,7 +1146,7 @@ ErrorOr<int> Shell::builtin_unset(Main::Arguments arguments)
if (!did_touch_path && value == "PATH"sv)
did_touch_path = true;
- if (lookup_local_variable(value)) {
+ if (TRY(lookup_local_variable(value)) != nullptr) {
unset_local_variable(value);
} else {
unsetenv(value.characters());
@@ -1175,7 +1175,7 @@ ErrorOr<int> Shell::builtin_not(Main::Arguments arguments)
for (auto& arg : args)
command.argv.unchecked_append(TRY(String::from_utf8(arg)));
- auto commands = expand_aliases({ move(command) });
+ auto commands = TRY(expand_aliases({ move(command) }));
int exit_code = 1;
auto found_a_job = false;
for (auto& job : run_commands(commands)) {
@@ -1351,7 +1351,7 @@ ErrorOr<int> Shell::builtin_argsparser_parse(Main::Arguments arguments)
};
auto enlist = [&](auto name, auto value) -> ErrorOr<NonnullRefPtr<AST::Value>> {
- auto variable = lookup_local_variable(name);
+ auto variable = TRY(lookup_local_variable(name));
if (variable) {
auto list = TRY(const_cast<AST::Value&>(*variable).resolve_as_list(*this));
auto new_value = TRY(value->resolve_as_string(*this));
diff --git a/Userland/Shell/ImmediateFunctions.cpp b/Userland/Shell/ImmediateFunctions.cpp
index 8d1f03d6be..7b48fbfc0d 100644
--- a/Userland/Shell/ImmediateFunctions.cpp
+++ b/Userland/Shell/ImmediateFunctions.cpp
@@ -465,7 +465,7 @@ ErrorOr<RefPtr<AST::Node>> Shell::immediate_value_or_default(AST::ImmediateExpre
}
auto name = TRY(TRY(const_cast<AST::Node&>(arguments.first()).run(*this))->resolve_as_string(*this));
- if (!local_variable_or(name, ""sv).is_empty())
+ if (!TRY(local_variable_or(name, ""sv)).is_empty())
return make_ref_counted<AST::SimpleVariable>(invoking_node.position(), name);
return arguments.last();
@@ -479,7 +479,7 @@ ErrorOr<RefPtr<AST::Node>> Shell::immediate_assign_default(AST::ImmediateExpress
}
auto name = TRY(TRY(const_cast<AST::Node&>(arguments.first()).run(*this))->resolve_as_string(*this));
- if (!local_variable_or(name, ""sv).is_empty())
+ if (!TRY(local_variable_or(name, ""sv)).is_empty())
return make_ref_counted<AST::SimpleVariable>(invoking_node.position(), name);
auto value = TRY(TRY(const_cast<AST::Node&>(arguments.last()).run(*this))->resolve_without_cast(*this));
@@ -496,7 +496,7 @@ ErrorOr<RefPtr<AST::Node>> Shell::immediate_error_if_empty(AST::ImmediateExpress
}
auto name = TRY(TRY(const_cast<AST::Node&>(arguments.first()).run(*this))->resolve_as_string(*this));
- if (!local_variable_or(name, ""sv).is_empty())
+ if (!TRY(local_variable_or(name, ""sv)).is_empty())
return make_ref_counted<AST::SimpleVariable>(invoking_node.position(), name);
auto error_value = TRY(TRY(const_cast<AST::Node&>(arguments.last()).run(*this))->resolve_as_string(*this));
diff --git a/Userland/Shell/Parser.cpp b/Userland/Shell/Parser.cpp
index ec9ec35f99..18f01a265c 100644
--- a/Userland/Shell/Parser.cpp
+++ b/Userland/Shell/Parser.cpp
@@ -1903,8 +1903,8 @@ RefPtr<AST::Node> Parser::parse_bareword()
auto first_slash_index = string.find_byte_offset('/');
if (first_slash_index.has_value()) {
- username = string.substring_from_byte_offset(1, *first_slash_index).release_value_but_fixme_should_propagate_errors();
- string = string.substring_from_byte_offset(*first_slash_index + 1).release_value_but_fixme_should_propagate_errors();
+ username = string.substring_from_byte_offset(1, *first_slash_index - 1).release_value_but_fixme_should_propagate_errors();
+ string = string.substring_from_byte_offset(*first_slash_index).release_value_but_fixme_should_propagate_errors();
} else {
username = string.substring_from_byte_offset(1).release_value_but_fixme_should_propagate_errors();
string = {};
diff --git a/Userland/Shell/Shell.cpp b/Userland/Shell/Shell.cpp
index 6d5384679e..eaa16ba24b 100644
--- a/Userland/Shell/Shell.cpp
+++ b/Userland/Shell/Shell.cpp
@@ -289,11 +289,11 @@ Vector<DeprecatedString> Shell::expand_globs(Vector<StringView> path_segments, S
}
}
-Vector<AST::Command> Shell::expand_aliases(Vector<AST::Command> initial_commands)
+ErrorOr<Vector<AST::Command>> Shell::expand_aliases(Vector<AST::Command> initial_commands)
{
Vector<AST::Command> commands;
- Function<void(AST::Command&)> resolve_aliases_and_append = [&](auto& command) {
+ Function<ErrorOr<void>(AST::Command&)> resolve_aliases_and_append = [&](auto& command) -> ErrorOr<void> {
if (!command.argv.is_empty()) {
auto alias = resolve_alias(command.argv[0]);
if (!alias.is_null()) {
@@ -308,12 +308,12 @@ Vector<AST::Command> Shell::expand_aliases(Vector<AST::Command> initial_commands
NonnullRefPtr<AST::Node> substitute = adopt_ref(*new AST::Join(subcommand_nonnull->position(),
subcommand_nonnull,
adopt_ref(*new AST::CommandLiteral(subcommand_nonnull->position(), command))));
- auto res = substitute->run(*this).release_value_but_fixme_should_propagate_errors();
- for (auto& subst_command : res->resolve_as_commands(*this).release_value_but_fixme_should_propagate_errors()) {
+ auto res = TRY(substitute->run(*this));
+ for (auto& subst_command : TRY(res->resolve_as_commands(*this))) {
if (!subst_command.argv.is_empty() && subst_command.argv.first() == argv0) // Disallow an alias resolving to itself.
commands.append(subst_command);
else
- resolve_aliases_and_append(subst_command);
+ TRY(resolve_aliases_and_append(subst_command));
}
} else {
commands.append(command);
@@ -324,10 +324,12 @@ Vector<AST::Command> Shell::expand_aliases(Vector<AST::Command> initial_commands
} else {
commands.append(command);
}
+
+ return {};
};
for (auto& command : initial_commands)
- resolve_aliases_and_append(command);
+ TRY(resolve_aliases_and_append(command));
return commands;
}
@@ -350,7 +352,7 @@ Shell::LocalFrame* Shell::find_frame_containing_local_variable(StringView name)
return nullptr;
}
-RefPtr<AST::Value const> Shell::lookup_local_variable(StringView name) const
+ErrorOr<RefPtr<AST::Value const>> Shell::lookup_local_variable(StringView name) const
{
if (auto* frame = find_frame_containing_local_variable(name))
return frame->local_variables.get(name).value();
@@ -361,13 +363,13 @@ RefPtr<AST::Value const> Shell::lookup_local_variable(StringView name) const
return nullptr;
}
-RefPtr<AST::Value const> Shell::get_argument(size_t index) const
+ErrorOr<RefPtr<AST::Value const>> Shell::get_argument(size_t index) const
{
if (index == 0)
- return adopt_ref(*new AST::StringValue(String::from_deprecated_string(current_script).release_value_but_fixme_should_propagate_errors()));
+ return adopt_ref(*new AST::StringValue(TRY(String::from_deprecated_string(current_script))));
--index;
- if (auto argv = lookup_local_variable("ARGV"sv)) {
+ if (auto argv = TRY(lookup_local_variable("ARGV"sv))) {
if (argv->is_list_without_resolution()) {
AST::ListValue const* list = static_cast<AST::ListValue const*>(argv.ptr());
if (list->values().size() <= index)
@@ -385,12 +387,12 @@ RefPtr<AST::Value const> Shell::get_argument(size_t index) const
return nullptr;
}
-DeprecatedString Shell::local_variable_or(StringView name, DeprecatedString const& replacement) const
+ErrorOr<DeprecatedString> Shell::local_variable_or(StringView name, DeprecatedString const& replacement) const
{
- auto value = lookup_local_variable(name);
+ auto value = TRY(lookup_local_variable(name));
if (value) {
StringBuilder builder;
- builder.join(' ', const_cast<AST::Value&>(*value).resolve_as_list(const_cast<Shell&>(*this)).release_value_but_fixme_should_propagate_errors());
+ builder.join(' ', TRY(const_cast<AST::Value&>(*value).resolve_as_list(const_cast<Shell&>(*this))));
return builder.to_deprecated_string();
}
return replacement;
@@ -1085,10 +1087,17 @@ bool Shell::is_allowed_to_modify_termios(const AST::Command& command) const
return false;
auto value = lookup_local_variable("PROGRAMS_ALLOWED_TO_MODIFY_DEFAULT_TERMIOS"sv);
- if (!value)
+ if (value.is_error())
+ return false;
+
+ if (!value.value())
return false;
- return const_cast<AST::Value&>(*value).resolve_as_list(const_cast<Shell&>(*this)).release_value_but_fixme_should_propagate_errors().contains_slow(command.argv[0]);
+ auto result = const_cast<AST::Value&>(*value.value()).resolve_as_list(const_cast<Shell&>(*this));
+ if (result.is_error())
+ return false;
+
+ return result.value().contains_slow(command.argv[0]);
}
void Shell::restore_ios()
@@ -1428,13 +1437,13 @@ void Shell::remove_entry_from_cache(StringView entry)
cached_path.remove(index);
}
-void Shell::highlight(Line::Editor& editor) const
+ErrorOr<void> Shell::highlight(Line::Editor& editor) const
{
auto line = editor.line();
auto ast = parse(line, m_is_interactive);
if (!ast)
- return;
- ast->highlight_in_editor(editor, const_cast<Shell&>(*this)).release_value_but_fixme_should_propagate_errors();
+ return {};
+ return ast->highlight_in_editor(editor, const_cast<Shell&>(*this));
}
Vector<Line::CompletionSuggestion> Shell::complete()
@@ -1697,15 +1706,15 @@ ErrorOr<Vector<Line::CompletionSuggestion>> Shell::complete_via_program_itself(s
AST::Command completion_command;
completion_command.argv.append(program_name_storage);
- completion_command = expand_aliases({ completion_command }).last();
+ completion_command = TRY(expand_aliases({ completion_command })).last();
- auto completion_utility_name = String::formatted("_complete_{}", completion_command.argv[0]).release_value_but_fixme_should_propagate_errors();
+ auto completion_utility_name = TRY(String::formatted("_complete_{}", completion_command.argv[0]));
if (binary_search(cached_path.span(), completion_utility_name, nullptr, RunnablePathComparator {}) != nullptr)
completion_command.argv[0] = completion_utility_name;
else if (!options.invoke_program_for_autocomplete)
return Error::from_string_literal("Refusing to use the program itself as completion source");
- completion_command.argv.extend({ String::from_utf8("--complete"sv).release_value_but_fixme_should_propagate_errors(), String::from_utf8_short_string("--"sv) });
+ completion_command.argv.extend({ TRY(String::from_utf8("--complete"sv)), String::from_utf8_short_string("--"sv) });
struct Visitor : public AST::NodeVisitor {
Visitor(Shell& shell, AST::Position position)
@@ -1874,7 +1883,7 @@ ErrorOr<Vector<Line::CompletionSuggestion>> Shell::complete_via_program_itself(s
completion_command.argv.extend(visitor.list());
- auto devnull = String::from_utf8("/dev/null"sv).release_value_but_fixme_should_propagate_errors();
+ auto devnull = TRY(String::from_utf8("/dev/null"sv));
completion_command.should_wait = true;
completion_command.redirections.append(AST::PathRedirection::create(devnull, STDERR_FILENO, AST::PathRedirection::Write));
completion_command.redirections.append(AST::PathRedirection::create(devnull, STDIN_FILENO, AST::PathRedirection::Read));
diff --git a/Userland/Shell/Shell.h b/Userland/Shell/Shell.h
index dd6a22502c..9d01900823 100644
--- a/Userland/Shell/Shell.h
+++ b/Userland/Shell/Shell.h
@@ -165,15 +165,15 @@ public:
static DeprecatedString expand_tilde(StringView expression);
static Vector<DeprecatedString> expand_globs(StringView path, StringView base);
static Vector<DeprecatedString> expand_globs(Vector<StringView> path_segments, StringView base);
- Vector<AST::Command> expand_aliases(Vector<AST::Command>);
+ ErrorOr<Vector<AST::Command>> expand_aliases(Vector<AST::Command>);
DeprecatedString resolve_path(DeprecatedString) const;
DeprecatedString resolve_alias(StringView) const;
static bool has_history_event(StringView);
- RefPtr<AST::Value const> get_argument(size_t) const;
- RefPtr<AST::Value const> lookup_local_variable(StringView) const;
- DeprecatedString local_variable_or(StringView, DeprecatedString const&) const;
+ ErrorOr<RefPtr<AST::Value const>> get_argument(size_t) const;
+ ErrorOr<RefPtr<AST::Value const>> lookup_local_variable(StringView) const;
+ ErrorOr<DeprecatedString> local_variable_or(StringView, DeprecatedString const&) const;
void set_local_variable(DeprecatedString const&, RefPtr<AST::Value>, bool only_in_current_frame = false);
void unset_local_variable(StringView, bool only_in_current_frame = false);
@@ -276,7 +276,7 @@ public:
No
};
- void highlight(Line::Editor&) const;
+ ErrorOr<void> highlight(Line::Editor&) const;
Vector<Line::CompletionSuggestion> complete();
Vector<Line::CompletionSuggestion> complete(StringView);
Vector<Line::CompletionSuggestion> complete_program_name(StringView, size_t offset, EscapeMode = EscapeMode::Bareword);
diff --git a/Userland/Shell/main.cpp b/Userland/Shell/main.cpp
index 1ed6c8803e..631178feed 100644
--- a/Userland/Shell/main.cpp
+++ b/Userland/Shell/main.cpp
@@ -83,7 +83,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
if (cursor >= 0)
editor.set_cursor(cursor);
}
- shell->highlight(editor);
+ (void)shell->highlight(editor);
};
editor->on_tab_complete = [&](const Line::Editor&) {
return shell->complete();