diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 510e9dfc9..ed2282321 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -5746,7 +5746,7 @@ static void test_highlighting() { do_test(expected_colors.size() == text.size()); std::vector colors(text.size()); - highlight_shell(text, colors, operation_context_t{vars}, true /* io_ok */); + highlight_shell(text, colors, operation_context_t{vars}, true /* io_ok */, text.size()); if (expected_colors.size() != colors.size()) { err(L"Color vector has wrong size! Expected %lu, actual %lu", expected_colors.size(), diff --git a/src/highlight.cpp b/src/highlight.cpp index b13f3834e..5fc9c0823 100644 --- a/src/highlight.cpp +++ b/src/highlight.cpp @@ -773,6 +773,8 @@ class highlighter_t { // The string we're highlighting. Note this is a reference memmber variable (to avoid copying)! // We must not outlive this! const wcstring &buff; + // The position of the cursor within the string. + const maybe_t cursor; // The operation context. Again, a reference member variable! const operation_context_t &ctx; // Whether it's OK to do I/O. @@ -830,8 +832,10 @@ class highlighter_t { void visit(const ast::node_t &node) { visit_children(node); } // Constructor - highlighter_t(const wcstring &str, const operation_context_t &ctx, wcstring wd, bool can_do_io) + highlighter_t(const wcstring &str, maybe_t cursor, const operation_context_t &ctx, + wcstring wd, bool can_do_io) : buff(str), + cursor(cursor), ctx(ctx), io_ok(can_do_io), working_directory(std::move(wd)), @@ -907,8 +911,12 @@ void highlighter_t::color_as_argument(const ast::node_t &node, bool options_allo this->color_array.at(arg_subcmd_end) = highlight_role_t::operat; // Highlight it recursively. - highlighter_t cmdsub_highlighter(cmdsub_contents, this->ctx, this->working_directory, - this->io_still_ok()); + maybe_t arg_cursor; + if (cursor.has_value()) { + arg_cursor = *cursor - arg_subcmd_start; + } + highlighter_t cmdsub_highlighter(cmdsub_contents, arg_cursor, this->ctx, + this->working_directory, this->io_still_ok()); color_array_t subcolors = cmdsub_highlighter.highlight(); // Copy out the subcolors back into our array. @@ -1351,8 +1359,8 @@ std::string colorize(const wcstring &text, const std::vector & } void highlight_shell(const wcstring &buff, std::vector &color, - const operation_context_t &ctx, bool io_ok) { + const operation_context_t &ctx, bool io_ok, maybe_t cursor) { const wcstring working_directory = ctx.vars.get_pwd_slash(); - highlighter_t highlighter(buff, ctx, working_directory, io_ok); + highlighter_t highlighter(buff, cursor, ctx, working_directory, io_ok); color = highlighter.highlight(); } diff --git a/src/highlight.h b/src/highlight.h index 0b9e66c62..23d470aea 100644 --- a/src/highlight.h +++ b/src/highlight.h @@ -105,8 +105,10 @@ std::string colorize(const wcstring &text, const std::vector & /// \param ctx The variables and cancellation check for this operation. /// \param io_ok If set, allow IO which may block. This means that e.g. invalid commands may be /// detected. +/// \param cursor The position of the cursor in the commandline. void highlight_shell(const wcstring &buffstr, std::vector &color, - const operation_context_t &ctx, bool io_ok = false); + const operation_context_t &ctx, bool io_ok = false, + maybe_t cursor = {}); /// highlight_color_resolver_t resolves highlight specs (like "a command") to actual RGB colors. /// It maintains a cache with no invalidation mechanism. The lifetime of these should typically be diff --git a/src/reader.cpp b/src/reader.cpp index 8a317d07a..43132abee 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2696,16 +2696,16 @@ void reader_data_t::highlight_complete(highlight_result_t result) { // Given text and whether IO is allowed, return a function that performs highlighting. The function // may be invoked on a background thread. static std::function get_highlight_performer(parser_t &parser, - const wcstring &text, + const editable_line_t &el, bool io_ok) { auto vars = parser.vars().snapshot(); uint32_t generation_count = read_generation_count(); return [=]() -> highlight_result_t { - if (text.empty()) return {}; + if (el.text().empty()) return {}; operation_context_t ctx = get_bg_context(vars, generation_count); - std::vector colors(text.size(), highlight_spec_t{}); - highlight_shell(text, colors, ctx, io_ok); - return highlight_result_t{std::move(colors), text}; + std::vector colors(el.text().size(), highlight_spec_t{}); + highlight_shell(el.text(), colors, ctx, io_ok, el.position()); + return highlight_result_t{std::move(colors), el.text()}; }; } @@ -2719,7 +2719,7 @@ void reader_data_t::super_highlight_me_plenty() { in_flight_highlight_request = el->text(); FLOG(reader_render, L"Highlighting"); - auto highlight_performer = get_highlight_performer(parser(), el->text(), true /* io_ok */); + auto highlight_performer = get_highlight_performer(parser(), *el, true /* io_ok */); auto shared_this = this->shared_from_this(); debounce_highlighting().perform(highlight_performer, [shared_this](highlight_result_t result) { shared_this->highlight_complete(std::move(result)); @@ -2762,7 +2762,7 @@ void reader_data_t::finish_highlighting_before_exec() { if (!current_highlight_ok) { // We need to do a quick highlight without I/O. auto highlight_no_io = - get_highlight_performer(parser(), command_line.text(), false /* io not ok */); + get_highlight_performer(parser(), command_line, false /* io not ok */); this->highlight_complete(highlight_no_io()); } }