diff --git a/Userland/DevTools/HackStudio/CodeDocument.cpp b/Userland/DevTools/HackStudio/CodeDocument.cpp index f37b259e1e..c4caef0024 100644 --- a/Userland/DevTools/HackStudio/CodeDocument.cpp +++ b/Userland/DevTools/HackStudio/CodeDocument.cpp @@ -32,4 +32,14 @@ CodeDocument::CodeDocument(Client* client) { } +CodeDocument::DiffType CodeDocument::line_difference(size_t line) const +{ + return m_line_differences[line]; +} + +void CodeDocument::set_line_differences(Badge, Vector line_differences) +{ + m_line_differences = move(line_differences); +} + } diff --git a/Userland/DevTools/HackStudio/CodeDocument.h b/Userland/DevTools/HackStudio/CodeDocument.h index 4db89d1751..a0a2687091 100644 --- a/Userland/DevTools/HackStudio/CodeDocument.h +++ b/Userland/DevTools/HackStudio/CodeDocument.h @@ -13,6 +13,8 @@ namespace HackStudio { +class Editor; + class CodeDocument final : public GUI::TextDocument { public: virtual ~CodeDocument() override = default; @@ -29,6 +31,15 @@ public: virtual bool is_code_document() const override final { return true; } + enum class DiffType { + None, + AddedLine, + ModifiedLine, + DeletedLinesBefore, + }; + DiffType line_difference(size_t line) const; + void set_line_differences(Badge, Vector); + private: explicit CodeDocument(DeprecatedString const& file_path, Client* client = nullptr); explicit CodeDocument(Client* client = nullptr); @@ -37,6 +48,8 @@ private: Optional m_language; Vector m_breakpoint_lines; Optional m_execution_position; + + Vector m_line_differences; }; } diff --git a/Userland/DevTools/HackStudio/Editor.cpp b/Userland/DevTools/HackStudio/Editor.cpp index 1ca6c0ec28..e50bb353a5 100644 --- a/Userland/DevTools/HackStudio/Editor.cpp +++ b/Userland/DevTools/HackStudio/Editor.cpp @@ -86,6 +86,24 @@ Editor::Editor() add_breakpoint(line).release_value_but_fixme_should_propagate_errors(); }; + m_git_diff_indicator_id = register_gutter_indicator( + [&](auto& painter, Gfx::IntRect rect, size_t line) { + auto diff_type = code_document().line_difference(line); + switch (diff_type) { + case CodeDocument::DiffType::AddedLine: + painter.draw_text(rect, "+"sv, font(), Gfx::TextAlignment::Center); + break; + case CodeDocument::DiffType::ModifiedLine: + painter.draw_text(rect, "!"sv, font(), Gfx::TextAlignment::Center); + break; + case CodeDocument::DiffType::DeletedLinesBefore: + painter.draw_text(rect, "-"sv, font(), Gfx::TextAlignment::Center); + break; + case CodeDocument::DiffType::None: + VERIFY_NOT_REACHED(); + } + }).release_value_but_fixme_should_propagate_errors(); + m_breakpoint_indicator_id = register_gutter_indicator( [&](auto& painter, Gfx::IntRect rect, size_t) { auto const& icon = breakpoint_icon_bitmap(); @@ -159,36 +177,6 @@ void Editor::paint_event(GUI::PaintEvent& event) rect.set_height(rect.height() - horizontal_scrollbar().height()); painter.draw_rect(rect, palette().selection()); } - - if (gutter_visible()) { - size_t first_visible_line = text_position_at(event.rect().top_left()).line(); - size_t last_visible_line = text_position_at(event.rect().bottom_right()).line(); - - if (wrapper().git_repo()) { - for (auto& hunk : wrapper().hunks()) { - auto start_line = hunk.target_start_line; - auto finish_line = start_line + hunk.added_lines.size(); - - auto additions = hunk.added_lines.size(); - auto deletions = hunk.removed_lines.size(); - - for (size_t line_offset = 0; line_offset < additions; line_offset++) { - auto line = start_line + line_offset; - if (line < first_visible_line || line > last_visible_line) { - continue; - } - auto sign = (line_offset < deletions) ? "!"sv : "+"sv; - painter.draw_text(gutter_icon_rect(line), sign, font(), Gfx::TextAlignment::Center); - } - if (additions < deletions) { - auto deletions_line = min(finish_line, line_count() - 1); - if (deletions_line <= last_visible_line) { - painter.draw_text(gutter_icon_rect(deletions_line), "-"sv, font(), Gfx::TextAlignment::Center); - } - } - } - } - } } static HashMap& man_paths() @@ -827,4 +815,41 @@ void Editor::remove_breakpoint(size_t line_number) Debugger::the().on_breakpoint_change(wrapper().filename_title(), line_number, BreakpointChange::Removed); } +ErrorOr Editor::update_git_diff_indicators() +{ + clear_gutter_indicators(m_git_diff_indicator_id); + + if (!wrapper().git_repo()) + return {}; + + Vector line_differences; + TRY(line_differences.try_ensure_capacity(document().line_count())); + for (auto i = 0u; i < document().line_count(); ++i) + line_differences.unchecked_append(CodeDocument::DiffType::None); + + for (auto& hunk : wrapper().hunks()) { + auto start_line = hunk.target_start_line; + auto finish_line = start_line + hunk.added_lines.size(); + + auto additions = hunk.added_lines.size(); + auto deletions = hunk.removed_lines.size(); + + for (size_t line_offset = 0; line_offset < additions; line_offset++) { + auto line = start_line + line_offset; + auto difference = (line_offset < deletions) ? CodeDocument::DiffType::ModifiedLine : CodeDocument::DiffType::AddedLine; + line_differences[line] = difference; + add_gutter_indicator(m_git_diff_indicator_id, line); + } + if (additions < deletions) { + auto deletions_line = min(finish_line, line_count() - 1); + line_differences[deletions_line] = CodeDocument::DiffType::DeletedLinesBefore; + add_gutter_indicator(m_git_diff_indicator_id, deletions_line); + } + } + code_document().set_line_differences({}, move(line_differences)); + update(); + + return {}; +} + } diff --git a/Userland/DevTools/HackStudio/Editor.h b/Userland/DevTools/HackStudio/Editor.h index cffaa472e2..24f4180785 100644 --- a/Userland/DevTools/HackStudio/Editor.h +++ b/Userland/DevTools/HackStudio/Editor.h @@ -44,6 +44,8 @@ public: void clear_execution_position(); void set_debug_mode(bool); + ErrorOr update_git_diff_indicators(); + CodeDocument const& code_document() const; CodeDocument& code_document(); @@ -125,6 +127,7 @@ private: GutterIndicatorID m_breakpoint_indicator_id; GutterIndicatorID m_execution_indicator_id; + GutterIndicatorID m_git_diff_indicator_id; }; } diff --git a/Userland/DevTools/HackStudio/EditorWrapper.cpp b/Userland/DevTools/HackStudio/EditorWrapper.cpp index 6cb484f9be..ea104594db 100644 --- a/Userland/DevTools/HackStudio/EditorWrapper.cpp +++ b/Userland/DevTools/HackStudio/EditorWrapper.cpp @@ -87,8 +87,10 @@ void EditorWrapper::save() void EditorWrapper::update_diff() { - if (m_git_repo) + if (m_git_repo) { m_hunks = Diff::parse_hunks(m_git_repo->unstaged_diff(filename()).value()); + editor().update_git_diff_indicators().release_value_but_fixme_should_propagate_errors(); + } } void EditorWrapper::set_project_root(DeprecatedString const& project_root)