diff options
author | Tim Schumacher <timschumi@gmx.de> | 2023-01-13 12:29:46 +0100 |
---|---|---|
committer | Sam Atkins <atkinssj@gmail.com> | 2023-01-16 21:04:48 +0000 |
commit | 40cb41a16cf0cb6b2711eb5be6facddd2540e13a (patch) | |
tree | 6d44889cb65ae06dcac44ddab0ef2cdf5f5f70a6 | |
parent | f9f1e1dd4956c92ca33f8562739f224d6e80c323 (diff) | |
download | serenity-40cb41a16cf0cb6b2711eb5be6facddd2540e13a.zip |
LibLine: Do a whole bunch of internal error propagation
-rw-r--r-- | Userland/Libraries/LibLine/Editor.cpp | 261 | ||||
-rw-r--r-- | Userland/Libraries/LibLine/Editor.h | 22 | ||||
-rw-r--r-- | Userland/Libraries/LibLine/InternalFunctions.cpp | 24 | ||||
-rw-r--r-- | Userland/Libraries/LibLine/SuggestionDisplay.h | 16 | ||||
-rw-r--r-- | Userland/Libraries/LibLine/SuggestionManager.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibLine/SuggestionManager.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibLine/VT.h | 14 | ||||
-rw-r--r-- | Userland/Libraries/LibLine/XtermSuggestionDisplay.cpp | 56 |
8 files changed, 212 insertions, 187 deletions
diff --git a/Userland/Libraries/LibLine/Editor.cpp b/Userland/Libraries/LibLine/Editor.cpp index 0fe1a6c9ae..c108f170de 100644 --- a/Userland/Libraries/LibLine/Editor.cpp +++ b/Userland/Libraries/LibLine/Editor.cpp @@ -566,11 +566,11 @@ void Editor::initialize() if (m_configuration.m_signal_mode == Configuration::WithSignalHandlers) { m_signal_handlers.append(Core::EventLoop::register_signal(SIGINT, [this](int) { - interrupted(); + interrupted().release_value_but_fixme_should_propagate_errors(); })); m_signal_handlers.append(Core::EventLoop::register_signal(SIGWINCH, [this](int) { - resized(); + resized().release_value_but_fixme_should_propagate_errors(); })); } @@ -587,26 +587,26 @@ void Editor::refetch_default_termios() m_termios = termios; } -void Editor::interrupted() +ErrorOr<void> Editor::interrupted() { if (m_is_searching) return m_search_editor->interrupted(); if (!m_is_editing) - return; + return {}; m_was_interrupted = true; handle_interrupt_event(); if (!m_finish || !m_previous_interrupt_was_handled_as_interrupt) - return; + return {}; m_finish = false; { - auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); - reposition_cursor(*stderr_stream, true); - if (m_suggestion_display->cleanup()) - reposition_cursor(*stderr_stream, true); - stderr_stream->write_entire_buffer("\n"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + auto stderr_stream = TRY(Core::Stream::File::standard_error()); + TRY(reposition_cursor(*stderr_stream, true)); + if (TRY(m_suggestion_display->cleanup())) + TRY(reposition_cursor(*stderr_stream, true)); + TRY(stderr_stream->write_entire_buffer("\n"sv.bytes())); } m_buffer.clear(); m_chars_touched_in_the_middle = buffer().size(); @@ -615,9 +615,10 @@ void Editor::interrupted() m_notifier->set_enabled(false); m_notifier = nullptr; Core::EventLoop::current().quit(Retry); + return {}; } -void Editor::resized() +ErrorOr<void> Editor::resized() { m_was_resized = true; m_previous_num_columns = m_num_columns; @@ -626,42 +627,47 @@ void Editor::resized() if (!m_has_origin_reset_scheduled) { // Reset the origin, but make sure it doesn't blow up if we can't read it if (set_origin(false)) { - handle_resize_event(false); + TRY(handle_resize_event(false)); } else { - deferred_invoke([this] { handle_resize_event(true); }); + deferred_invoke([this] { handle_resize_event(true).release_value_but_fixme_should_propagate_errors(); }); m_has_origin_reset_scheduled = true; } } + + return {}; } -void Editor::handle_resize_event(bool reset_origin) +ErrorOr<void> Editor::handle_resize_event(bool reset_origin) { m_has_origin_reset_scheduled = false; if (reset_origin && !set_origin(false)) { m_has_origin_reset_scheduled = true; - return deferred_invoke([this] { handle_resize_event(true); }); + deferred_invoke([this] { handle_resize_event(true).release_value_but_fixme_should_propagate_errors(); }); + return {}; } set_origin(m_origin_row, 1); - auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); + auto stderr_stream = TRY(Core::Stream::File::standard_error()); - reposition_cursor(*stderr_stream, true); - m_suggestion_display->redisplay(m_suggestion_manager, m_num_lines, m_num_columns); + TRY(reposition_cursor(*stderr_stream, true)); + TRY(m_suggestion_display->redisplay(m_suggestion_manager, m_num_lines, m_num_columns)); m_origin_row = m_suggestion_display->origin_row(); - reposition_cursor(*stderr_stream); + TRY(reposition_cursor(*stderr_stream)); if (m_is_searching) - m_search_editor->resized(); + TRY(m_search_editor->resized()); + + return {}; } -void Editor::really_quit_event_loop() +ErrorOr<void> Editor::really_quit_event_loop() { m_finish = false; { - auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); - reposition_cursor(*stderr_stream, true); - stderr_stream->write_entire_buffer("\n"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + auto stderr_stream = TRY(Core::Stream::File::standard_error()); + TRY(reposition_cursor(*stderr_stream, true)); + TRY(stderr_stream->write_entire_buffer("\n"sv.bytes())); } auto string = line(); m_buffer.clear(); @@ -675,6 +681,7 @@ void Editor::really_quit_event_loop() m_notifier->set_enabled(false); m_notifier = nullptr; Core::EventLoop::current().quit(Exit); + return {}; } auto Editor::get_line(DeprecatedString const& prompt) -> Result<DeprecatedString, Editor::Error> @@ -729,22 +736,22 @@ auto Editor::get_line(DeprecatedString const& prompt) -> Result<DeprecatedString for (size_t i = 0; i < prompt_lines; ++i) stderr_stream->write_entire_buffer("\n"sv.bytes()).release_value_but_fixme_should_propagate_errors(); - VT::move_relative(-static_cast<int>(prompt_lines), 0, *stderr_stream); + VT::move_relative(-static_cast<int>(prompt_lines), 0, *stderr_stream).release_value_but_fixme_should_propagate_errors(); } set_origin(); m_history_cursor = m_history.size(); - refresh_display(); + refresh_display().release_value_but_fixme_should_propagate_errors(); Core::EventLoop loop; m_notifier = Core::Notifier::construct(STDIN_FILENO, Core::Notifier::Read); - m_notifier->on_ready_to_read = [&] { try_update_once(); }; + m_notifier->on_ready_to_read = [&] { try_update_once().release_value_but_fixme_should_propagate_errors(); }; if (!m_incomplete_data.is_empty()) - deferred_invoke([&] { try_update_once(); }); + deferred_invoke([&] { try_update_once().release_value_but_fixme_should_propagate_errors(); }); if (loop.exec() == Retry) return get_line(prompt); @@ -770,21 +777,23 @@ void Editor::save_to(JsonObject& object) object.set("used_display_area", move(display_area)); } -void Editor::try_update_once() +ErrorOr<void> Editor::try_update_once() { if (m_was_interrupted) { handle_interrupt_event(); } - handle_read_event(); + TRY(handle_read_event()); if (m_always_refresh) m_refresh_needed = true; - refresh_display(); + TRY(refresh_display()); if (m_finish) - really_quit_event_loop(); + TRY(really_quit_event_loop()); + + return {}; } void Editor::handle_interrupt_event() @@ -811,11 +820,11 @@ void Editor::handle_interrupt_event() finish(); } -void Editor::handle_read_event() +ErrorOr<void> Editor::handle_read_event() { if (m_prohibit_input_processing) { m_have_unprocessed_read_event = true; - return; + return {}; } auto prohibit_scope = prohibit_input(); @@ -830,14 +839,14 @@ void Editor::handle_read_event() if (errno == EINTR) { if (!m_was_interrupted) { if (m_was_resized) - return; + return {}; finish(); - return; + return {}; } handle_interrupt_event(); - return; + return {}; } ScopedValueRollback errno_restorer(errno); @@ -845,7 +854,7 @@ void Editor::handle_read_event() m_input_error = Error::ReadFailure; finish(); - return; + return {}; } m_incomplete_data.append(keybuf, nread); @@ -854,7 +863,7 @@ void Editor::handle_read_event() if (available_bytes == 0) { m_input_error = Error::Empty; finish(); - return; + return {}; } auto reverse_tab = false; @@ -900,7 +909,7 @@ void Editor::handle_read_event() default: { m_callback_machine.key_pressed(*this, { code_point, Key::Alt }); m_state = InputState::Free; - cleanup_suggestions(); + TRY(cleanup_suggestions()); continue; } } @@ -958,7 +967,7 @@ void Editor::handle_read_event() reverse_tab = true; break; } - cleanup_suggestions(); + TRY(cleanup_suggestions()); switch (csi_final) { case 'A': // ^[[A: arrow up @@ -1064,7 +1073,7 @@ void Editor::handle_read_event() } // There are no sequences past this point, so short of 'tab', we will want to cleanup the suggestions. - ArmedScopeGuard suggestion_cleanup { [this] { cleanup_suggestions(); } }; + ArmedScopeGuard suggestion_cleanup { [this] { cleanup_suggestions().release_value_but_fixme_should_propagate_errors(); } }; // Normally ^D. `stty eof \^n` can change it to ^N (or something else), but Serenity doesn't have `stty` yet. // Process this here since the keybinds might override its behavior. @@ -1156,8 +1165,8 @@ void Editor::handle_read_event() for (auto& view : completion_result.insert) insert(view); - auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); - reposition_cursor(*stderr_stream); + auto stderr_stream = TRY(Core::Stream::File::standard_error()); + TRY(reposition_cursor(*stderr_stream)); if (completion_result.style_to_apply.has_value()) { // Apply the style of the last suggestion. @@ -1178,12 +1187,12 @@ void Editor::handle_read_event() } if (m_times_tab_pressed > 1 && m_suggestion_manager.count() > 0) { - if (m_suggestion_display->cleanup()) - reposition_cursor(*stderr_stream); + if (TRY(m_suggestion_display->cleanup())) + TRY(reposition_cursor(*stderr_stream)); m_suggestion_display->set_initial_prompt_lines(m_prompt_lines_at_suggestion_initiation); - m_suggestion_display->display(m_suggestion_manager); + TRY(m_suggestion_display->display(m_suggestion_manager)); m_origin_row = m_suggestion_display->origin_row(); } @@ -1199,8 +1208,8 @@ void Editor::handle_read_event() // We have none, or just one suggestion, // we should just commit that and continue // after it, as if it were auto-completed. - reposition_cursor(*stderr_stream, true); - cleanup_suggestions(); + TRY(reposition_cursor(*stderr_stream, true)); + TRY(cleanup_suggestions()); m_remembered_suggestion_static_data.clear_with_capacity(); } continue; @@ -1209,7 +1218,7 @@ void Editor::handle_read_event() // If we got here, manually cleanup the suggestions and then insert the new code point. m_remembered_suggestion_static_data.clear_with_capacity(); suggestion_cleanup.disarm(); - cleanup_suggestions(); + TRY(cleanup_suggestions()); insert(code_point); } @@ -1221,10 +1230,12 @@ void Editor::handle_read_event() } if (!m_incomplete_data.is_empty() && !m_finish) - deferred_invoke([&] { try_update_once(); }); + deferred_invoke([&] { try_update_once().release_value_but_fixme_should_propagate_errors(); }); + + return {}; } -void Editor::cleanup_suggestions() +ErrorOr<void> Editor::cleanup_suggestions() { if (m_times_tab_pressed != 0) { // Apply the style of the last suggestion. @@ -1232,15 +1243,16 @@ void Editor::cleanup_suggestions() stylize({ m_suggestion_manager.current_suggestion().start_index, m_cursor, Span::Mode::CodepointOriented }, m_suggestion_manager.current_suggestion().style); // We probably have some suggestions drawn, // let's clean them up. - if (m_suggestion_display->cleanup()) { - auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); - reposition_cursor(*stderr_stream); + if (TRY(m_suggestion_display->cleanup())) { + auto stderr_stream = TRY(Core::Stream::File::standard_error()); + TRY(reposition_cursor(*stderr_stream)); m_refresh_needed = true; } m_suggestion_manager.reset(); m_suggestion_display->finish(); } m_times_tab_pressed = 0; // Safe to say if we get here, the user didn't press TAB + return {}; } bool Editor::search(StringView phrase, bool allow_empty, bool from_beginning) @@ -1298,22 +1310,24 @@ void Editor::recalculate_origin() // but that will be calculated and applied at the next // refresh cycle. } -void Editor::cleanup() + +ErrorOr<void> Editor::cleanup() { auto current_buffer_metrics = actual_rendered_string_metrics(buffer_view(), m_current_masks); auto new_lines = current_prompt_metrics().lines_with_addition(current_buffer_metrics, m_num_columns); if (new_lines < m_shown_lines) m_extra_forward_lines = max(m_shown_lines - new_lines, m_extra_forward_lines); - auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); - reposition_cursor(*stderr_stream, true); + auto stderr_stream = TRY(Core::Stream::File::standard_error()); + TRY(reposition_cursor(*stderr_stream, true)); auto current_line = num_lines() - 1; - VT::clear_lines(current_line, m_extra_forward_lines, *stderr_stream); + TRY(VT::clear_lines(current_line, m_extra_forward_lines, *stderr_stream)); m_extra_forward_lines = 0; - reposition_cursor(*stderr_stream); + TRY(reposition_cursor(*stderr_stream)); + return {}; }; -void Editor::refresh_display() +ErrorOr<void> Editor::refresh_display() { Core::Stream::AllocatingMemoryStream output_stream; ScopeGuard flush_stream { @@ -1339,7 +1353,7 @@ void Editor::refresh_display() m_refresh_needed = true; swap(m_previous_num_columns, m_num_columns); recalculate_origin(); - cleanup(); + TRY(cleanup()); swap(m_previous_num_columns, m_num_columns); has_cleaned_up = true; } @@ -1353,22 +1367,22 @@ void Editor::refresh_display() if (m_origin_row + current_num_lines > m_num_lines) { if (current_num_lines > m_num_lines) { for (size_t i = 0; i < m_num_lines; ++i) - output_stream.write_entire_buffer("\n"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(output_stream.write_entire_buffer("\n"sv.bytes())); m_origin_row = 0; } else { auto old_origin_row = m_origin_row; m_origin_row = m_num_lines - current_num_lines + 1; for (size_t i = 0; i < old_origin_row - m_origin_row; ++i) - output_stream.write_entire_buffer("\n"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(output_stream.write_entire_buffer("\n"sv.bytes())); } } // Do not call hook on pure cursor movement. if (m_cached_prompt_valid && !m_refresh_needed && m_pending_chars.size() == 0) { // Probably just moving around. - reposition_cursor(output_stream); + TRY(reposition_cursor(output_stream)); m_cached_buffer_metrics = actual_rendered_string_metrics(buffer_view(), m_current_masks); m_drawn_end_of_line_offset = m_buffer.size(); - return; + return {}; } if (on_display_refresh) @@ -1378,17 +1392,17 @@ void Editor::refresh_display() if (!m_refresh_needed && m_cursor == m_buffer.size()) { // Just write the characters out and continue, // no need to refresh the entire line. - output_stream.write_entire_buffer(m_pending_chars).release_value_but_fixme_should_propagate_errors(); + TRY(output_stream.write_entire_buffer(m_pending_chars)); m_pending_chars.clear(); m_drawn_cursor = m_cursor; m_drawn_end_of_line_offset = m_buffer.size(); m_cached_buffer_metrics = actual_rendered_string_metrics(buffer_view(), m_current_masks); m_drawn_spans = m_current_spans; - return; + return {}; } } - auto apply_styles = [&, empty_styles = HashMap<u32, Style> {}](size_t i) { + auto apply_styles = [&, empty_styles = HashMap<u32, Style> {}](size_t i) -> ErrorOr<void> { auto ends = m_current_spans.m_spans_ending.get(i).value_or(empty_styles); auto starts = m_current_spans.m_spans_starting.get(i).value_or(empty_styles); @@ -1405,11 +1419,11 @@ void Editor::refresh_display() style.unify_with(applicable_style.value); // Disable any style that should be turned off. - VT::apply_style(style, output_stream, false); + TRY(VT::apply_style(style, output_stream, false)); // Reapply styles for overlapping spans that include this one. style = find_applicable_style(i); - VT::apply_style(style, output_stream, true); + TRY(VT::apply_style(style, output_stream, true)); } if (starts.size() || anchored_starts.size()) { Style style; @@ -1421,8 +1435,10 @@ void Editor::refresh_display() style.unify_with(applicable_style.value); // Set new styles. - VT::apply_style(style, output_stream, true); + TRY(VT::apply_style(style, output_stream, true)); } + + return {}; }; auto print_character_at = [&](size_t i) { @@ -1445,7 +1461,7 @@ void Editor::refresh_display() } else { c = m_buffer[i]; } - auto print_single_character = [&](auto c) { + auto print_single_character = [&](auto c) -> ErrorOr<void> { StringBuilder builder; bool should_print_masked = is_ascii_control(c) && c != '\n'; bool should_print_caret = c < 64 && should_print_masked; @@ -1457,30 +1473,32 @@ void Editor::refresh_display() builder.append(Utf32View { &c, 1 }); if (should_print_masked) - output_stream.write_entire_buffer("\033[7m"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(output_stream.write_entire_buffer("\033[7m"sv.bytes())); - output_stream.write_entire_buffer(builder.string_view().bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(output_stream.write_entire_buffer(builder.string_view().bytes())); if (should_print_masked) - output_stream.write_entire_buffer("\033[27m"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(output_stream.write_entire_buffer("\033[27m"sv.bytes())); + + return {}; }; c.visit( - [&](u32 c) { print_single_character(c); }, - [&](auto& view) { for (auto c : view) print_single_character(c); }); + [&](u32 c) { print_single_character(c).release_value_but_fixme_should_propagate_errors(); }, + [&](auto& view) { for (auto c : view) print_single_character(c).release_value_but_fixme_should_propagate_errors(); }); }; // If there have been no changes to previous sections of the line (style or text) // just append the new text with the appropriate styles. if (!m_always_refresh && m_cached_prompt_valid && m_chars_touched_in_the_middle == 0 && m_drawn_spans.contains_up_to_offset(m_current_spans, m_drawn_cursor)) { auto initial_style = find_applicable_style(m_drawn_end_of_line_offset); - VT::apply_style(initial_style, output_stream); + TRY(VT::apply_style(initial_style, output_stream)); for (size_t i = m_drawn_end_of_line_offset; i < m_buffer.size(); ++i) { - apply_styles(i); + TRY(apply_styles(i)); print_character_at(i); } - VT::apply_style(Style::reset_style(), output_stream); + TRY(VT::apply_style(Style::reset_style(), output_stream)); m_pending_chars.clear(); m_refresh_needed = false; m_cached_buffer_metrics = actual_rendered_string_metrics(buffer_view(), m_current_masks); @@ -1489,7 +1507,7 @@ void Editor::refresh_display() m_drawn_end_of_line_offset = m_buffer.size(); // No need to reposition the cursor, the cursor is already where it needs to be. - return; + return {}; } if constexpr (LINE_EDITOR_DEBUG) { @@ -1514,20 +1532,20 @@ void Editor::refresh_display() // Ouch, reflow entire line. if (!has_cleaned_up) { - cleanup(); + TRY(cleanup()); } - VT::move_absolute(m_origin_row, m_origin_column, output_stream); + TRY(VT::move_absolute(m_origin_row, m_origin_column, output_stream)); - output_stream.write_entire_buffer(m_new_prompt.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(output_stream.write_entire_buffer(m_new_prompt.bytes())); - VT::clear_to_end_of_line(output_stream); + TRY(VT::clear_to_end_of_line(output_stream)); StringBuilder builder; for (size_t i = 0; i < m_buffer.size(); ++i) { - apply_styles(i); + TRY(apply_styles(i)); print_character_at(i); } - VT::apply_style(Style::reset_style(), output_stream); // don't bleed to EOL + TRY(VT::apply_style(Style::reset_style(), output_stream)); // don't bleed to EOL m_pending_chars.clear(); m_refresh_needed = false; @@ -1537,7 +1555,8 @@ void Editor::refresh_display() m_drawn_end_of_line_offset = m_buffer.size(); m_cached_prompt_valid = true; - reposition_cursor(output_stream); + TRY(reposition_cursor(output_stream)); + return {}; } void Editor::strip_styles(bool strip_anchored) @@ -1555,7 +1574,7 @@ void Editor::strip_styles(bool strip_anchored) m_refresh_needed = true; } -void Editor::reposition_cursor(Core::Stream::Stream& stream, bool to_end) +ErrorOr<void> Editor::reposition_cursor(Core::Stream::Stream& stream, bool to_end) { auto cursor = m_cursor; auto saved_cursor = m_cursor; @@ -1571,17 +1590,18 @@ void Editor::reposition_cursor(Core::Stream::Stream& stream, bool to_end) ensure_free_lines_from_origin(line); VERIFY(column + m_origin_column <= m_num_columns); - VT::move_absolute(line + m_origin_row, column + m_origin_column, stream); + TRY(VT::move_absolute(line + m_origin_row, column + m_origin_column, stream)); m_cursor = saved_cursor; + return {}; } -void VT::move_absolute(u32 row, u32 col, Core::Stream::Stream& stream) +ErrorOr<void> VT::move_absolute(u32 row, u32 col, Core::Stream::Stream& stream) { - stream.write_entire_buffer(DeprecatedString::formatted("\033[{};{}H", row, col).bytes()).release_value_but_fixme_should_propagate_errors(); + return stream.write_entire_buffer(DeprecatedString::formatted("\033[{};{}H", row, col).bytes()); } -void VT::move_relative(int row, int col, Core::Stream::Stream& stream) +ErrorOr<void> VT::move_relative(int row, int col, Core::Stream::Stream& stream) { char x_op = 'A', y_op = 'D'; @@ -1595,9 +1615,11 @@ void VT::move_relative(int row, int col, Core::Stream::Stream& stream) col = -col; if (row > 0) - stream.write_entire_buffer(DeprecatedString::formatted("\033[{}{}", row, x_op).bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stream.write_entire_buffer(DeprecatedString::formatted("\033[{}{}", row, x_op).bytes())); if (col > 0) - stream.write_entire_buffer(DeprecatedString::formatted("\033[{}{}", col, y_op).bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stream.write_entire_buffer(DeprecatedString::formatted("\033[{}{}", col, y_op).bytes())); + + return {}; } Style Editor::find_applicable_style(size_t offset) const @@ -1731,53 +1753,56 @@ DeprecatedString Style::to_deprecated_string() const return builder.build(); } -void VT::apply_style(Style const& style, Core::Stream::Stream& stream, bool is_starting) +ErrorOr<void> VT::apply_style(Style const& style, Core::Stream::Stream& stream, bool is_starting) { if (is_starting) { - stream.write_entire_buffer(DeprecatedString::formatted("\033[{};{};{}m{}{}{}", - style.bold() ? 1 : 22, - style.underline() ? 4 : 24, - style.italic() ? 3 : 23, - style.background().to_vt_escape(), - style.foreground().to_vt_escape(), - style.hyperlink().to_vt_escape(true)) - .bytes()) - .release_value_but_fixme_should_propagate_errors(); + TRY(stream.write_entire_buffer(DeprecatedString::formatted("\033[{};{};{}m{}{}{}", + style.bold() ? 1 : 22, + style.underline() ? 4 : 24, + style.italic() ? 3 : 23, + style.background().to_vt_escape(), + style.foreground().to_vt_escape(), + style.hyperlink().to_vt_escape(true)) + .bytes())); } else { - stream.write_entire_buffer(style.hyperlink().to_vt_escape(false).bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stream.write_entire_buffer(style.hyperlink().to_vt_escape(false).bytes())); } + + return {}; } -void VT::clear_lines(size_t count_above, size_t count_below, Core::Stream::Stream& stream) +ErrorOr<void> VT::clear_lines(size_t count_above, size_t count_below, Core::Stream::Stream& stream) { if (count_below + count_above == 0) { - stream.write_entire_buffer("\033[2K"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stream.write_entire_buffer("\033[2K"sv.bytes())); } else { // Go down count_below lines. if (count_below > 0) - stream.write_entire_buffer(DeprecatedString::formatted("\033[{}B", count_below).bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stream.write_entire_buffer(DeprecatedString::formatted("\033[{}B", count_below).bytes())); // Then clear lines going upwards. for (size_t i = count_below + count_above; i > 0; --i) { - stream.write_entire_buffer("\033[2K"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stream.write_entire_buffer("\033[2K"sv.bytes())); if (i != 1) - stream.write_entire_buffer("\033[A"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stream.write_entire_buffer("\033[A"sv.bytes())); } } + + return {}; } -void VT::save_cursor(Core::Stream::Stream& stream) +ErrorOr<void> VT::save_cursor(Core::Stream::Stream& stream) { - stream.write_entire_buffer("\033[s"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + return stream.write_entire_buffer("\033[s"sv.bytes()); } -void VT::restore_cursor(Core::Stream::Stream& stream) +ErrorOr<void> VT::restore_cursor(Core::Stream::Stream& stream) { - stream.write_entire_buffer("\033[u"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + return stream.write_entire_buffer("\033[u"sv.bytes()); } -void VT::clear_to_end_of_line(Core::Stream::Stream& stream) +ErrorOr<void> VT::clear_to_end_of_line(Core::Stream::Stream& stream) { - stream.write_entire_buffer("\033[K"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + return stream.write_entire_buffer("\033[K"sv.bytes()); } enum VTState { diff --git a/Userland/Libraries/LibLine/Editor.h b/Userland/Libraries/LibLine/Editor.h index 0e2ac4c254..3a2ca0f3c2 100644 --- a/Userland/Libraries/LibLine/Editor.h +++ b/Userland/Libraries/LibLine/Editor.h @@ -183,8 +183,8 @@ public: #undef __ENUMERATE_EDITOR_INTERNAL_FUNCTION - void interrupted(); - void resized(); + ErrorOr<void> interrupted(); + ErrorOr<void> resized(); size_t cursor() const { return m_cursor; } void set_cursor(size_t cursor) @@ -252,7 +252,7 @@ public: [this, previous_value] { m_prohibit_input_processing = previous_value; if (!m_prohibit_input_processing && m_have_unprocessed_read_event) - handle_read_event(); + handle_read_event().release_value_but_fixme_should_propagate_errors(); } }; } @@ -270,10 +270,10 @@ private: // FIXME: Port to Core::Property void save_to(JsonObject&); - void try_update_once(); + ErrorOr<void> try_update_once(); void handle_interrupt_event(); - void handle_read_event(); - void handle_resize_event(bool reset_origin); + ErrorOr<void> handle_read_event(); + ErrorOr<void> handle_resize_event(bool reset_origin); void ensure_free_lines_from_origin(size_t count); @@ -326,10 +326,10 @@ private: m_paste_buffer.clear_with_capacity(); } - void refresh_display(); - void cleanup(); - void cleanup_suggestions(); - void really_quit_event_loop(); + ErrorOr<void> refresh_display(); + ErrorOr<void> cleanup(); + ErrorOr<void> cleanup_suggestions(); + ErrorOr<void> really_quit_event_loop(); void restore() { @@ -393,7 +393,7 @@ private: } void recalculate_origin(); - void reposition_cursor(Core::Stream::Stream&, bool to_end = false); + ErrorOr<void> reposition_cursor(Core::Stream::Stream&, bool to_end = false); struct CodepointRange { size_t start { 0 }; diff --git a/Userland/Libraries/LibLine/InternalFunctions.cpp b/Userland/Libraries/LibLine/InternalFunctions.cpp index f54dc36545..f562542843 100644 --- a/Userland/Libraries/LibLine/InternalFunctions.cpp +++ b/Userland/Libraries/LibLine/InternalFunctions.cpp @@ -159,7 +159,7 @@ void Editor::finish_edit() if (!m_always_refresh) { m_input_error = Error::Eof; finish(); - really_quit_event_loop(); + really_quit_event_loop().release_value_but_fixme_should_propagate_errors(); } } @@ -233,7 +233,7 @@ void Editor::enter_search() m_search_editor->on_display_refresh = [this](Editor& search_editor) { // Remove the search editor prompt before updating ourselves (this avoids artifacts when we move the search editor around). - search_editor.cleanup(); + search_editor.cleanup().release_value_but_fixme_should_propagate_errors(); StringBuilder builder; builder.append(Utf32View { search_editor.buffer().data(), search_editor.buffer().size() }); @@ -244,7 +244,7 @@ void Editor::enter_search() m_cursor = 0; } - refresh_display(); + refresh_display().release_value_but_fixme_should_propagate_errors(); // Move the search prompt below ours and tell it to redraw itself. auto prompt_end_line = current_prompt_metrics().lines_with_addition(m_cached_buffer_metrics, m_num_columns); @@ -264,7 +264,7 @@ void Editor::enter_search() search_editor.finish(); m_reset_buffer_on_search_end = true; search_editor.end_search(); - search_editor.deferred_invoke([&search_editor] { search_editor.really_quit_event_loop(); }); + search_editor.deferred_invoke([&search_editor] { search_editor.really_quit_event_loop().release_value_but_fixme_should_propagate_errors(); }); return false; }); @@ -293,7 +293,7 @@ void Editor::enter_search() TemporaryChange refresh_change { m_always_refresh, true }; set_origin(1, 1); m_refresh_needed = true; - refresh_display(); + refresh_display().release_value_but_fixme_should_propagate_errors(); } // move the search prompt below ours @@ -342,12 +342,12 @@ void Editor::enter_search() // Manually cleanup the search line. auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); - reposition_cursor(*stderr_stream); + reposition_cursor(*stderr_stream).release_value_but_fixme_should_propagate_errors(); auto search_metrics = actual_rendered_string_metrics(search_string, {}); auto metrics = actual_rendered_string_metrics(search_prompt, {}); - VT::clear_lines(0, metrics.lines_with_addition(search_metrics, m_num_columns) + search_end_row - m_origin_row - 1, *stderr_stream); + VT::clear_lines(0, metrics.lines_with_addition(search_metrics, m_num_columns) + search_end_row - m_origin_row - 1, *stderr_stream).release_value_but_fixme_should_propagate_errors(); - reposition_cursor(*stderr_stream); + reposition_cursor(*stderr_stream).release_value_but_fixme_should_propagate_errors(); m_refresh_needed = true; m_cached_prompt_valid = false; @@ -434,7 +434,7 @@ void Editor::clear_screen() { warn("\033[3J\033[H\033[2J"); auto stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); - VT::move_absolute(1, 1, *stream); + VT::move_absolute(1, 1, *stream).release_value_but_fixme_should_propagate_errors(); set_origin(1, 1); m_refresh_needed = true; m_cached_prompt_valid = false; @@ -569,11 +569,7 @@ void Editor::edit_in_external_editor() } { - auto file_or_error = Core::Stream::File::open({ file_path, strlen(file_path) }, Core::Stream::OpenMode::Read); - if (file_or_error.is_error()) - return; - - auto file = file_or_error.release_value(); + auto file = Core::Stream::File::open({ file_path, strlen(file_path) }, Core::Stream::OpenMode::Read).release_value_but_fixme_should_propagate_errors(); auto contents = file->read_until_eof().release_value_but_fixme_should_propagate_errors(); StringView data { contents }; while (data.ends_with('\n')) diff --git a/Userland/Libraries/LibLine/SuggestionDisplay.h b/Userland/Libraries/LibLine/SuggestionDisplay.h index 113df0ccfb..99ee3ae1e4 100644 --- a/Userland/Libraries/LibLine/SuggestionDisplay.h +++ b/Userland/Libraries/LibLine/SuggestionDisplay.h @@ -18,20 +18,22 @@ class Editor; class SuggestionDisplay { public: virtual ~SuggestionDisplay() = default; - virtual void display(SuggestionManager const&) = 0; - virtual bool cleanup() = 0; + virtual ErrorOr<void> display(SuggestionManager const&) = 0; + virtual ErrorOr<bool> cleanup() = 0; virtual void finish() = 0; virtual void set_initial_prompt_lines(size_t) = 0; - void redisplay(SuggestionManager const& manager, size_t lines, size_t columns) + ErrorOr<void> redisplay(SuggestionManager const& manager, size_t lines, size_t columns) { if (m_is_showing_suggestions) { - cleanup(); + TRY(cleanup()); set_vt_size(lines, columns); - display(manager); + TRY(display(manager)); } else { set_vt_size(lines, columns); } + + return {}; } virtual void set_vt_size(size_t lines, size_t columns) = 0; @@ -62,8 +64,8 @@ public: { } virtual ~XtermSuggestionDisplay() override = default; - virtual void display(SuggestionManager const&) override; - virtual bool cleanup() override; + virtual ErrorOr<void> display(SuggestionManager const&) override; + virtual ErrorOr<bool> cleanup() override; virtual void finish() override { m_pages.clear(); diff --git a/Userland/Libraries/LibLine/SuggestionManager.cpp b/Userland/Libraries/LibLine/SuggestionManager.cpp index 871211e96f..ee5e7aa431 100644 --- a/Userland/Libraries/LibLine/SuggestionManager.cpp +++ b/Userland/Libraries/LibLine/SuggestionManager.cpp @@ -182,13 +182,13 @@ SuggestionManager::CompletionAttemptResult SuggestionManager::attempt_completion return result; } -size_t SuggestionManager::for_each_suggestion(Function<IterationDecision(CompletionSuggestion const&, size_t)> callback) const +ErrorOr<size_t> SuggestionManager::for_each_suggestion(Function<ErrorOr<IterationDecision>(CompletionSuggestion const&, size_t)> callback) const { size_t start_index { 0 }; for (auto& suggestion : m_suggestions) { if (start_index++ < m_last_displayed_suggestion_index) continue; - if (callback(suggestion, start_index - 1) == IterationDecision::Break) + if (TRY(callback(suggestion, start_index - 1)) == IterationDecision::Break) break; } return start_index; diff --git a/Userland/Libraries/LibLine/SuggestionManager.h b/Userland/Libraries/LibLine/SuggestionManager.h index 849f3c90df..924c5aa9a5 100644 --- a/Userland/Libraries/LibLine/SuggestionManager.h +++ b/Userland/Libraries/LibLine/SuggestionManager.h @@ -78,7 +78,7 @@ public: size_t next_index() const { return m_next_suggestion_index; } void set_start_index(size_t index) const { m_last_displayed_suggestion_index = index; } - size_t for_each_suggestion(Function<IterationDecision(CompletionSuggestion const&, size_t)>) const; + ErrorOr<size_t> for_each_suggestion(Function<ErrorOr<IterationDecision>(CompletionSuggestion const&, size_t)>) const; enum CompletionMode { DontComplete, diff --git a/Userland/Libraries/LibLine/VT.h b/Userland/Libraries/LibLine/VT.h index 5927ef095b..a674915eea 100644 --- a/Userland/Libraries/LibLine/VT.h +++ b/Userland/Libraries/LibLine/VT.h @@ -13,13 +13,13 @@ namespace Line { namespace VT { -void save_cursor(Core::Stream::Stream&); -void restore_cursor(Core::Stream::Stream&); -void clear_to_end_of_line(Core::Stream::Stream&); -void clear_lines(size_t count_above, size_t count_below, Core::Stream::Stream&); -void move_relative(int x, int y, Core::Stream::Stream&); -void move_absolute(u32 x, u32 y, Core::Stream::Stream&); -void apply_style(Style const&, Core::Stream::Stream&, bool is_starting = true); +ErrorOr<void> save_cursor(Core::Stream::Stream&); +ErrorOr<void> restore_cursor(Core::Stream::Stream&); +ErrorOr<void> clear_to_end_of_line(Core::Stream::Stream&); +ErrorOr<void> clear_lines(size_t count_above, size_t count_below, Core::Stream::Stream&); +ErrorOr<void> move_relative(int x, int y, Core::Stream::Stream&); +ErrorOr<void> move_absolute(u32 x, u32 y, Core::Stream::Stream&); +ErrorOr<void> apply_style(Style const&, Core::Stream::Stream&, bool is_starting = true); } } diff --git a/Userland/Libraries/LibLine/XtermSuggestionDisplay.cpp b/Userland/Libraries/LibLine/XtermSuggestionDisplay.cpp index d5cc18de0f..ace6d42f07 100644 --- a/Userland/Libraries/LibLine/XtermSuggestionDisplay.cpp +++ b/Userland/Libraries/LibLine/XtermSuggestionDisplay.cpp @@ -13,30 +13,30 @@ namespace Line { -void XtermSuggestionDisplay::display(SuggestionManager const& manager) +ErrorOr<void> XtermSuggestionDisplay::display(SuggestionManager const& manager) { did_display(); - auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); + auto stderr_stream = TRY(Core::Stream::File::standard_error()); size_t longest_suggestion_length = 0; size_t longest_suggestion_byte_length = 0; size_t longest_suggestion_byte_length_without_trivia = 0; manager.set_start_index(0); - manager.for_each_suggestion([&](auto& suggestion, auto) { + TRY(manager.for_each_suggestion([&](auto& suggestion, auto) { longest_suggestion_length = max(longest_suggestion_length, suggestion.text_view.length() + suggestion.display_trivia_view.length()); longest_suggestion_byte_length = max(longest_suggestion_byte_length, suggestion.text_string.length() + suggestion.display_trivia_string.length()); longest_suggestion_byte_length_without_trivia = max(longest_suggestion_byte_length_without_trivia, suggestion.text_string.length()); return IterationDecision::Continue; - }); + })); size_t num_printed = 0; size_t lines_used = 1; - VT::save_cursor(*stderr_stream); - VT::clear_lines(0, m_lines_used_for_last_suggestions, *stderr_stream); - VT::restore_cursor(*stderr_stream); + TRY(VT::save_cursor(*stderr_stream)); + TRY(VT::clear_lines(0, m_lines_used_for_last_suggestions, *stderr_stream)); + TRY(VT::restore_cursor(*stderr_stream)); auto spans_entire_line { false }; Vector<StringMetrics::LineMetrics> lines; @@ -50,12 +50,12 @@ void XtermSuggestionDisplay::display(SuggestionManager const& manager) // the suggestion list to fit in the prompt line. auto start = max_line_count - m_prompt_lines_at_suggestion_initiation; for (size_t i = start; i < max_line_count; ++i) - stderr_stream->write("\n"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stderr_stream->write("\n"sv.bytes())); lines_used += max_line_count; longest_suggestion_length = 0; } - VT::move_absolute(max_line_count + m_origin_row, 1, *stderr_stream); + TRY(VT::move_absolute(max_line_count + m_origin_row, 1, *stderr_stream)); if (m_pages.is_empty()) { size_t num_printed = 0; @@ -63,7 +63,7 @@ void XtermSuggestionDisplay::display(SuggestionManager const& manager) // Cache the pages. manager.set_start_index(0); size_t page_start = 0; - manager.for_each_suggestion([&](auto& suggestion, auto index) { + TRY(manager.for_each_suggestion([&](auto& suggestion, auto index) { size_t next_column = num_printed + suggestion.text_view.length() + longest_suggestion_length + 2; if (next_column > m_num_columns) { auto lines = (suggestion.text_view.length() + m_num_columns - 1) / m_num_columns; @@ -84,7 +84,7 @@ void XtermSuggestionDisplay::display(SuggestionManager const& manager) num_printed += longest_suggestion_length + 2; return IterationDecision::Continue; - }); + })); // Append the last page. m_pages.append({ page_start, manager.count() }); } @@ -92,13 +92,13 @@ void XtermSuggestionDisplay::display(SuggestionManager const& manager) auto page_index = fit_to_page_boundary(manager.next_index()); manager.set_start_index(m_pages[page_index].start); - manager.for_each_suggestion([&](auto& suggestion, auto index) { + TRY(manager.for_each_suggestion([&](auto& suggestion, auto index) -> ErrorOr<IterationDecision> { size_t next_column = num_printed + suggestion.text_view.length() + longest_suggestion_length + 2; if (next_column > m_num_columns) { auto lines = (suggestion.text_view.length() + m_num_columns - 1) / m_num_columns; lines_used += lines; - stderr_stream->write("\n"sv.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stderr_stream->write("\n"sv.bytes())); num_printed = 0; } @@ -109,23 +109,23 @@ void XtermSuggestionDisplay::display(SuggestionManager const& manager) // Only apply color to the selection if something is *actually* added to the buffer. if (manager.is_current_suggestion_complete() && index == manager.next_index()) { - VT::apply_style({ Style::Foreground(Style::XtermColor::Blue) }, *stderr_stream); + TRY(VT::apply_style({ Style::Foreground(Style::XtermColor::Blue) }, *stderr_stream)); } if (spans_entire_line) { num_printed += m_num_columns; - stderr_stream->write(suggestion.text_string.bytes()).release_value_but_fixme_should_propagate_errors(); - stderr_stream->write(suggestion.display_trivia_string.bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stderr_stream->write(suggestion.text_string.bytes())); + TRY(stderr_stream->write(suggestion.display_trivia_string.bytes())); } else { auto field = DeprecatedString::formatted("{: <{}} {}", suggestion.text_string, longest_suggestion_byte_length_without_trivia, suggestion.display_trivia_string); - stderr_stream->write(DeprecatedString::formatted("{: <{}}", field, longest_suggestion_byte_length + 2).bytes()).release_value_but_fixme_should_propagate_errors(); + TRY(stderr_stream->write(DeprecatedString::formatted("{: <{}}", field, longest_suggestion_byte_length + 2).bytes())); num_printed += longest_suggestion_length + 2; } if (manager.is_current_suggestion_complete() && index == manager.next_index()) - VT::apply_style(Style::reset_style(), *stderr_stream); + TRY(VT::apply_style(Style::reset_style(), *stderr_stream)); return IterationDecision::Continue; - }); + })); m_lines_used_for_last_suggestions = lines_used; @@ -144,23 +144,25 @@ void XtermSuggestionDisplay::display(SuggestionManager const& manager) if (string.length() > m_num_columns - 1) { // This would overflow into the next line, so just don't print an indicator. - return; + return {}; } - VT::move_absolute(m_origin_row + lines_used, m_num_columns - string.length() - 1, *stderr_stream); - VT::apply_style({ Style::Background(Style::XtermColor::Green) }, *stderr_stream); - stderr_stream->write(string.bytes()).release_value_but_fixme_should_propagate_errors(); - VT::apply_style(Style::reset_style(), *stderr_stream); + TRY(VT::move_absolute(m_origin_row + lines_used, m_num_columns - string.length() - 1, *stderr_stream)); + TRY(VT::apply_style({ Style::Background(Style::XtermColor::Green) }, *stderr_stream)); + TRY(stderr_stream->write(string.bytes())); + TRY(VT::apply_style(Style::reset_style(), *stderr_stream)); } + + return {}; } -bool XtermSuggestionDisplay::cleanup() +ErrorOr<bool> XtermSuggestionDisplay::cleanup() { did_cleanup(); if (m_lines_used_for_last_suggestions) { - auto stderr_stream = Core::Stream::File::standard_error().release_value_but_fixme_should_propagate_errors(); - VT::clear_lines(0, m_lines_used_for_last_suggestions, *stderr_stream); + auto stderr_stream = TRY(Core::Stream::File::standard_error()); + TRY(VT::clear_lines(0, m_lines_used_for_last_suggestions, *stderr_stream)); m_lines_used_for_last_suggestions = 0; return true; } |