Bladeren bron

HackStudio: Indicate git changes in the editor's gutter

"+" for added lines, "!" for changed, "-" for removed.
Dmitrii Ubskii 4 jaren geleden
bovenliggende
commit
d5828dbecb

+ 26 - 0
Userland/DevTools/HackStudio/Editor.cpp

@@ -121,6 +121,7 @@ void Editor::paint_event(GUI::PaintEvent& event)
     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();
+
         for (size_t line : breakpoint_lines()) {
             if (line < first_visible_line || line > last_visible_line) {
                 continue;
@@ -132,6 +133,31 @@ void Editor::paint_event(GUI::PaintEvent& event)
             const auto& icon = current_position_icon_bitmap();
             painter.blit(gutter_icon_rect(execution_position().value()).top_left(), icon, icon.rect());
         }
+
+        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;
+                    }
+                    char const* sign = (line_offset < deletions) ? "!" : "+";
+                    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), "-", font(), Gfx::TextAlignment::Center);
+                    }
+                }
+            }
+        }
     }
 }
 

+ 27 - 0
Userland/DevTools/HackStudio/EditorWrapper.cpp

@@ -92,6 +92,7 @@ void EditorWrapper::set_filename(const String& filename)
 {
     m_filename = filename;
     update_title();
+    update_diff();
 }
 
 void EditorWrapper::save()
@@ -99,6 +100,32 @@ void EditorWrapper::save()
     editor().write_to_file(filename());
     m_document_dirty = false;
     update_title();
+    update_diff();
+    editor().update();
+}
+
+void EditorWrapper::update_diff()
+{
+    if (m_git_repo)
+        m_hunks = Diff::parse_hunks(m_git_repo->unstaged_diff(LexicalPath(filename())).value());
+}
+
+void EditorWrapper::set_project_root(LexicalPath const& project_root)
+{
+    m_project_root = project_root;
+
+    auto result = GitRepo::try_to_create(m_project_root);
+    switch (result.type) {
+    case GitRepo::CreateResult::Type::Success:
+        m_git_repo = result.repo;
+        break;
+    case GitRepo::CreateResult::Type::GitProgramNotFound:
+        break;
+    case GitRepo::CreateResult::Type::NoGitRepo:
+        break;
+    default:
+        VERIFY_NOT_REACHED();
+    }
 }
 
 void EditorWrapper::update_title()

+ 15 - 0
Userland/DevTools/HackStudio/EditorWrapper.h

@@ -7,9 +7,12 @@
 #pragma once
 
 #include "Debugger/BreakpointCallback.h"
+#include "Git/GitRepo.h"
 #include "LanguageClient.h"
 #include <AK/Function.h>
+#include <AK/RefPtr.h>
 #include <AK/Vector.h>
+#include <LibDiff/Hunks.h>
 #include <LibGUI/Widget.h>
 #include <string.h>
 
@@ -40,6 +43,14 @@ public:
     const String& filename() const { return m_filename; }
     bool document_dirty() const { return m_document_dirty; }
 
+    LexicalPath const& project_root() const { return m_project_root; }
+    void set_project_root(LexicalPath const& project_root);
+
+    GitRepo const* git_repo() const { return m_git_repo; }
+
+    void update_diff();
+    Vector<Diff::Hunk> const& hunks() const { return m_hunks; }
+
 private:
     EditorWrapper();
 
@@ -50,6 +61,10 @@ private:
     RefPtr<GUI::Label> m_cursor_label;
     RefPtr<Editor> m_editor;
     bool m_document_dirty { false };
+
+    LexicalPath m_project_root;
+    RefPtr<GitRepo> m_git_repo;
+    Vector<Diff::Hunk> m_hunks;
 };
 
 }

+ 3 - 0
Userland/DevTools/HackStudio/HackStudioWidget.cpp

@@ -196,6 +196,8 @@ void HackStudioWidget::open_project(const String& root_path)
         debugger.reset_breakpoints();
         debugger.set_source_root(m_project->root_path());
     }
+    for (auto& editor_wrapper : m_all_editor_wrappers)
+        editor_wrapper.set_project_root(LexicalPath(m_project->root_path()));
 }
 
 Vector<String> HackStudioWidget::selected_file_paths() const
@@ -498,6 +500,7 @@ void HackStudioWidget::add_new_editor(GUI::Widget& parent)
     m_current_editor_wrapper = wrapper;
     m_all_editor_wrappers.append(wrapper);
     wrapper->editor().set_focus(true);
+    wrapper->set_project_root(LexicalPath(m_project->root_path()));
 }
 
 NonnullRefPtr<GUI::Action> HackStudioWidget::create_switch_to_next_editor_action()