Преглед на файлове

HackStudio: Use GTextDoument::find_all() to implement find-in-files

This fixes the bug seen in my monthly OS update video, where we'd look
through a stale copy of each file, instead of the potentially edited
version in the GTextDocument.

Search results are now also represented as a full GTextRange, and when
you jump to a search result, we select the whole matching range. :^)
Andreas Kling преди 5 години
родител
ревизия
390b219cd1
променени са 3 файла, в които са добавени 23 реда и са изтрити 61 реда
  1. 19 18
      DevTools/HackStudio/FindInFilesWidget.cpp
  2. 4 38
      DevTools/HackStudio/ProjectFile.cpp
  3. 0 5
      DevTools/HackStudio/ProjectFile.h

+ 19 - 18
DevTools/HackStudio/FindInFilesWidget.cpp

@@ -9,14 +9,14 @@ extern GTextEditor& current_editor();
 extern void open_file(const String&);
 extern OwnPtr<Project> g_project;
 
-struct FilenameAndLineNumber {
+struct FilenameAndRange {
     String filename;
-    int line_number { -1 };
+    GTextRange range;
 };
 
 class SearchResultsModel final : public GModel {
 public:
-    explicit SearchResultsModel(const Vector<FilenameAndLineNumber>&& matches)
+    explicit SearchResultsModel(const Vector<FilenameAndRange>&& matches)
         : m_matches(move(matches))
     {
     }
@@ -27,23 +27,29 @@ public:
     {
         if (role == Role::Display) {
             auto& match = m_matches.at(index.row());
-            return String::format("%s:%d", match.filename.characters(), match.line_number);
+            return String::format("%s: (%d,%d - %d,%d)",
+                match.filename.characters(),
+                match.range.start().line() + 1,
+                match.range.start().column(),
+                match.range.end().line() + 1,
+                match.range.end().column());
         }
         return {};
     }
     virtual void update() override {}
+    virtual GModelIndex index(int row, int column = 0, const GModelIndex& = GModelIndex()) const override { return create_index(row, column, &m_matches.at(row)); }
 
 private:
-    Vector<FilenameAndLineNumber> m_matches;
+    Vector<FilenameAndRange> m_matches;
 };
 
 static RefPtr<SearchResultsModel> find_in_files(const StringView& text)
 {
-    Vector<FilenameAndLineNumber> matches;
+    Vector<FilenameAndRange> matches;
     g_project->for_each_text_file([&](auto& file) {
-        auto matches_in_file = file.find(text);
-        for (int match : matches_in_file) {
-            matches.append({ file.name(), match });
+        auto matches_in_file = file.document().find_all(text);
+        for (auto& range : matches_in_file) {
+            matches.append({ file.name(), range });
         }
     });
 
@@ -63,15 +69,10 @@ FindInFilesWidget::FindInFilesWidget(GWidget* parent)
 
     m_result_view = GListView::construct(this);
 
-    m_result_view->on_activation = [this](auto& index) {
-        auto match_string = m_result_view->model()->data(index).to_string();
-        auto parts = match_string.split(':');
-        ASSERT(parts.size() == 2);
-        bool ok;
-        int line_number = parts[1].to_int(ok);
-        ASSERT(ok);
-        open_file(parts[0]);
-        current_editor().set_cursor(line_number - 1, 0);
+    m_result_view->on_activation = [](auto& index) {
+        auto& match = *(const FilenameAndRange*)index.internal_data();
+        open_file(match.filename);
+        current_editor().set_selection(match.range);
         current_editor().set_focus(true);
     };
 

+ 4 - 38
DevTools/HackStudio/ProjectFile.cpp

@@ -6,45 +6,11 @@ const GTextDocument& ProjectFile::document() const
 {
     if (!m_document) {
         m_document = GTextDocument::create(nullptr);
-        m_document->set_text(contents());
-    }
-    return *m_document;
-}
-
-const ByteBuffer& ProjectFile::contents() const
-{
-    if (m_contents.is_null()) {
         auto file = CFile::construct(m_name);
-        if (file->open(CFile::ReadOnly))
-            m_contents = file->read_all();
-    }
-    return m_contents;
-}
-
-Vector<int> ProjectFile::find(const StringView& needle) const
-{
-    // NOTE: This forces us to load the contents if we hadn't already.
-    contents();
-
-    Vector<int> matching_line_numbers;
-
-    String needle_as_string(needle);
-
-    int line_index = 0;
-    int start_of_line = 0;
-    for (int i = 0; i < m_contents.size(); ++i) {
-        char ch = m_contents[i];
-        if (ch == '\n') {
-            // FIXME: Please come back here and do this the good boy way.
-            String line(StringView(m_contents.data() + start_of_line, i - start_of_line));
-            auto* found = strstr(line.characters(), needle_as_string.characters());
-            if (found)
-                matching_line_numbers.append(line_index + 1);
-            ++line_index;
-            start_of_line = i + 1;
-            continue;
+        if (!file->open(CFile::ReadOnly)) {
+            ASSERT_NOT_REACHED();
         }
+        m_document->set_text(file->read_all());
     }
-
-    return matching_line_numbers;
+    return *m_document;
 }

+ 0 - 5
DevTools/HackStudio/ProjectFile.h

@@ -15,10 +15,6 @@ public:
 
     const String& name() const { return m_name; }
 
-    const ByteBuffer& contents() const;
-
-    Vector<int> find(const StringView&) const;
-
     const GTextDocument& document() const;
 
 private:
@@ -28,6 +24,5 @@ private:
     }
 
     String m_name;
-    mutable ByteBuffer m_contents;
     mutable RefPtr<GTextDocument> m_document;
 };