From c4593828f40bd2a6d2c1e9ebe1e7ab820d2c4076 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 14 Aug 2021 11:29:22 +0200 Subject: [PATCH] commandline: Add --is-valid option (#8142) * commandline: Add --is-valid option to query whether it's syntactically complete This means querying when the commandline is in a state that it could be executed. Because our `execute` bind function also inserts a newline if it isn't. One case that's not handled right now: `execute` also expands abbreviations, those can technically make the commandline invalid again. Unfortunately we have no real way to *check* without doing the replacement. Also since abbreviations are only available in command position when you _execute_ them the commandline will most likely be valid. This is enough to make transient prompts work: ```fish function reset-transient --on-event fish_postexec set -g TRANSIENT 0 end function maybe_execute if commandline --is-valid set -g TRANSIENT 1 commandline -f repaint else set -g TRANSIENT 0 end commandline -f execute end bind \r maybe_execute ``` and then in `fish_prompt` react to $TRANSIENT being set to 1. --- doc_src/cmds/commandline.rst | 1 + src/builtin_commandline.cpp | 18 ++++++++++++++++++ tests/checks/commandline.fish | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 tests/checks/commandline.fish diff --git a/doc_src/cmds/commandline.rst b/doc_src/cmds/commandline.rst index 55ec37a33..e8e118017 100644 --- a/doc_src/cmds/commandline.rst +++ b/doc_src/cmds/commandline.rst @@ -61,6 +61,7 @@ The following options output metadata about the commandline state: - ``-P`` or ``--paging-mode`` evaluates to true if the commandline is showing pager contents, such as tab completions +- ``--is-valid`` returns true when the commandline is syntactically valid and complete. If it is, it would be executed when the ``execute`` bind function is called. If the commandline is incomplete, it returns 2, if it is erroneus, it returns 1. Example ------- diff --git a/src/builtin_commandline.cpp b/src/builtin_commandline.cpp index e3ac981f6..637ee0f1b 100644 --- a/src/builtin_commandline.cpp +++ b/src/builtin_commandline.cpp @@ -142,6 +142,7 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const bool line_mode = false; bool search_mode = false; bool paging_mode = false; + bool is_valid = false; const wchar_t *begin = nullptr, *end = nullptr; const wchar_t *override_buffer = nullptr; @@ -165,6 +166,7 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const {L"line", no_argument, nullptr, 'L'}, {L"search-mode", no_argument, nullptr, 'S'}, {L"paging-mode", no_argument, nullptr, 'P'}, + {L"is-valid", no_argument, nullptr, 1}, {nullptr, 0, nullptr, 0}}; int opt; @@ -236,6 +238,10 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const paging_mode = true; break; } + case 1: { + is_valid = true; + break; + } case 'h': { builtin_print_help(parser, streams, cmd); return STATUS_CMD_OK; @@ -387,6 +393,18 @@ maybe_t builtin_commandline(parser_t &parser, io_streams_t &streams, const return STATUS_CMD_ERROR; } + if (is_valid) { + if (!*current_buffer) return 1; + parser_test_error_bits_t res = + parse_util_detect_errors(current_buffer, + NULL, + true /* accept incomplete so we can tell the difference */); + if (res & PARSER_TEST_INCOMPLETE) { + return 2; + } + return res & PARSER_TEST_ERROR ? STATUS_CMD_ERROR : STATUS_CMD_OK; + } + switch (buffer_part) { case STRING_MODE: { begin = current_buffer; diff --git a/tests/checks/commandline.fish b/tests/checks/commandline.fish new file mode 100644 index 000000000..3ce76c1cc --- /dev/null +++ b/tests/checks/commandline.fish @@ -0,0 +1,19 @@ +#RUN: %fish %s + +commandline --input "echo foo | bar" --is-valid +and echo Valid +# CHECK: Valid + +commandline --input "echo foo | " --is-valid +or echo Invalid $status +# CHECK: Invalid 2 + +# TODO: This seems a bit awkward? +# The empty commandline is an error, not incomplete? +commandline --input '' --is-valid +or echo Invalid $status +# CHECK: Invalid 1 + +commandline --input 'echo $$' --is-valid +or echo Invalid $status +# CHECK: Invalid 1