From e6bd1f880704f78eb2f3905f94ae5893bc811d5d Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Wed, 23 Feb 2022 09:16:31 +0330 Subject: [PATCH] Shell: Add the 'join' and 'filter_glob' immediate functions 'split' was missing its other half, and to avoid globbing the filesystem, let's keep the globbing to shell-internal state. --- Userland/Shell/ImmediateFunctions.cpp | 70 +++++++++++++++++++++++++++ Userland/Shell/Shell.h | 4 +- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/Userland/Shell/ImmediateFunctions.cpp b/Userland/Shell/ImmediateFunctions.cpp index d95deb972c..4dea2f10e9 100644 --- a/Userland/Shell/ImmediateFunctions.cpp +++ b/Userland/Shell/ImmediateFunctions.cpp @@ -383,6 +383,76 @@ RefPtr Shell::immediate_concat_lists(AST::ImmediateExpression& invoki return AST::make_ref_counted(invoking_node.position(), move(result)); } +RefPtr Shell::immediate_filter_glob(AST::ImmediateExpression& invoking_node, const NonnullRefPtrVector& arguments) +{ + // filter_glob string list + if (arguments.size() != 2) { + raise_error(ShellError::EvaluatedSyntaxError, "Expected exactly two arguments to filter_glob ( )", invoking_node.position()); + return nullptr; + } + + auto glob_list = const_cast(arguments[0]).run(*this)->resolve_as_list(*this); + if (glob_list.size() != 1) { + raise_error(ShellError::EvaluatedSyntaxError, "Expected the argument to filter_glob to be a single string", arguments[0].position()); + return nullptr; + } + auto& glob = glob_list.first(); + auto& list_node = arguments[1]; + + NonnullRefPtrVector result; + + const_cast(list_node).for_each_entry(*this, [&](NonnullRefPtr entry) { + auto value = entry->resolve_as_list(*this); + if (value.size() == 0) + return IterationDecision::Continue; + if (value.size() == 1) { + if (!value.first().matches(glob)) + return IterationDecision::Continue; + result.append(AST::make_ref_counted(arguments[1].position(), value.first())); + return IterationDecision::Continue; + } + + for (auto& entry : value) { + if (entry.matches(glob)) { + NonnullRefPtrVector nodes; + for (auto& string : value) + nodes.append(AST::make_ref_counted(arguments[1].position(), string)); + result.append(AST::make_ref_counted(arguments[1].position(), move(nodes))); + return IterationDecision::Continue; + } + } + return IterationDecision::Continue; + }); + + return AST::make_ref_counted(invoking_node.position(), move(result)); +} + +RefPtr Shell::immediate_join(AST::ImmediateExpression& invoking_node, const NonnullRefPtrVector& arguments) +{ + if (arguments.size() != 2) { + raise_error(ShellError::EvaluatedSyntaxError, "Expected exactly 2 arguments to join", invoking_node.position()); + return nullptr; + } + + auto delimiter = const_cast(arguments[0]).run(this); + if (!delimiter->is_string()) { + raise_error(ShellError::EvaluatedSyntaxError, "Expected the join delimiter string to be a string", arguments[0].position()); + return nullptr; + } + + auto value = const_cast(arguments[1]).run(this)->resolve_without_cast(this); + if (!value->is_list()) { + raise_error(ShellError::EvaluatedSyntaxError, "Expected the joined list to be a list", arguments[1].position()); + return nullptr; + } + + auto delimiter_str = delimiter->resolve_as_list(this)[0]; + StringBuilder builder; + builder.join(delimiter_str, value->resolve_as_list(*this)); + + return AST::make_ref_counted(invoking_node.position(), builder.to_string()); +} + RefPtr Shell::run_immediate_function(StringView str, AST::ImmediateExpression& invoking_node, const NonnullRefPtrVector& arguments) { #define __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(name) \ diff --git a/Userland/Shell/Shell.h b/Userland/Shell/Shell.h index 79a984c779..43b44a2148 100644 --- a/Userland/Shell/Shell.h +++ b/Userland/Shell/Shell.h @@ -64,7 +64,9 @@ __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(remove_suffix) \ __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(remove_prefix) \ __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(regex_replace) \ - __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(split) + __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(filter_glob) \ + __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(split) \ + __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(join) namespace Shell {