diff options
author | Itamar <itamar8910@gmail.com> | 2020-08-15 10:58:31 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-08-15 15:06:35 +0200 |
commit | 627f258c9753902b733d94db6924852111ac3d9b (patch) | |
tree | e6e7fa86e4e9a28ba299ea4259b00a75fd73a7e2 | |
parent | e793cc3d1312c48f1f994a5eeec9f7a1d18487f3 (diff) | |
download | serenity-627f258c9753902b733d94db6924852111ac3d9b.zip |
HackStudio: Use CodeDocument instead of TextDocument
This commit adds a new GUI widget type, called CodeDocument, which
is a TextDocument that can additionaly store data related to the
debugger.
This fixes various bugs and crashes that occured when we switched
between files in debug mode, because we previously held stale breakpoint
data for the previous file in the Editor object.
We now keep this data at the "document" level rather than the Editor
level, which fixes things.
-rw-r--r-- | DevTools/HackStudio/CMakeLists.txt | 1 | ||||
-rw-r--r-- | DevTools/HackStudio/CodeDocument.cpp | 39 | ||||
-rw-r--r-- | DevTools/HackStudio/CodeDocument.h | 49 | ||||
-rw-r--r-- | DevTools/HackStudio/Editor.cpp | 40 | ||||
-rw-r--r-- | DevTools/HackStudio/Editor.h | 13 | ||||
-rw-r--r-- | DevTools/HackStudio/ProjectFile.cpp | 2 | ||||
-rw-r--r-- | DevTools/HackStudio/ProjectFile.h | 4 | ||||
-rw-r--r-- | Libraries/LibGUI/TextDocument.h | 7 | ||||
-rw-r--r-- | Libraries/LibGUI/TextEditor.h | 4 |
9 files changed, 137 insertions, 22 deletions
diff --git a/DevTools/HackStudio/CMakeLists.txt b/DevTools/HackStudio/CMakeLists.txt index 34366c4b41..ff85a9adf1 100644 --- a/DevTools/HackStudio/CMakeLists.txt +++ b/DevTools/HackStudio/CMakeLists.txt @@ -18,6 +18,7 @@ set(SOURCES Tool.cpp WidgetTool.cpp WidgetTreeModel.cpp + CodeDocument.cpp ) serenity_bin(HackStudio) diff --git a/DevTools/HackStudio/CodeDocument.cpp b/DevTools/HackStudio/CodeDocument.cpp new file mode 100644 index 0000000000..797aba5da7 --- /dev/null +++ b/DevTools/HackStudio/CodeDocument.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "CodeDocument.h" + +NonnullRefPtr<CodeDocument> CodeDocument::create(Client* client) +{ + return adopt(*new CodeDocument(client)); +} +CodeDocument::CodeDocument(Client* client) + : TextDocument(client) +{ +} + +CodeDocument::~CodeDocument() +{ +} diff --git a/DevTools/HackStudio/CodeDocument.h b/DevTools/HackStudio/CodeDocument.h new file mode 100644 index 0000000000..ca95efb53a --- /dev/null +++ b/DevTools/HackStudio/CodeDocument.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <LibGUI/TextDocument.h> + +class CodeDocument final : public GUI::TextDocument { +public: + virtual ~CodeDocument() override; + static NonnullRefPtr<CodeDocument> create(Client* client = nullptr); + + const Vector<size_t>& breakpoint_lines() const { return m_breakpoint_lines; } + Vector<size_t>& breakpoint_lines() { return m_breakpoint_lines; } + Optional<size_t> execution_position() const { return m_execution_position; } + void set_execution_position(size_t line) { m_execution_position = line; } + void clear_execution_position() { m_execution_position.clear(); } + + virtual bool is_code_document() const override final { return true; } + +private: + explicit CodeDocument(Client* client); + + Vector<size_t> m_breakpoint_lines; + Optional<size_t> m_execution_position; +}; diff --git a/DevTools/HackStudio/Editor.cpp b/DevTools/HackStudio/Editor.cpp index 3701511ba7..168efaefac 100644 --- a/DevTools/HackStudio/Editor.cpp +++ b/DevTools/HackStudio/Editor.cpp @@ -38,8 +38,8 @@ #include <LibGUI/Window.h> #include <LibMarkdown/Document.h> #include <LibWeb/DOM/ElementFactory.h> -#include <LibWeb/HTML/HTMLHeadElement.h> #include <LibWeb/DOM/Text.h> +#include <LibWeb/HTML/HTMLHeadElement.h> #include <LibWeb/PageView.h> // #define EDITOR_DEBUG @@ -109,16 +109,16 @@ void Editor::paint_event(GUI::PaintEvent& event) if (ruler_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 : m_breakpoint_lines) { + for (size_t line : breakpoint_lines()) { if (line < first_visible_line || line > last_visible_line) { continue; } const auto& icon = breakpoint_icon_bitmap(); painter.blit(breakpoint_icon_rect(line).center(), icon, icon.rect()); } - if (m_execution_position.has_value()) { + if (execution_position().has_value()) { const auto& icon = current_position_icon_bitmap(); - painter.blit(breakpoint_icon_rect(m_execution_position.value()).center(), icon, icon.rect()); + painter.blit(breakpoint_icon_rect(execution_position().value()).center(), icon, icon.rect()); } } } @@ -261,11 +261,11 @@ void Editor::mousedown_event(GUI::MouseEvent& event) auto text_position = text_position_at(event.position()); auto ruler_line_rect = ruler_content_rect(text_position.line()); if (event.button() == GUI::MouseButton::Left && event.position().x() < ruler_line_rect.width()) { - if (!m_breakpoint_lines.contains_slow(text_position.line())) { - m_breakpoint_lines.append(text_position.line()); + if (!breakpoint_lines().contains_slow(text_position.line())) { + breakpoint_lines().append(text_position.line()); on_breakpoint_change(wrapper().filename_label().text(), text_position.line(), BreakpointChange::Added); } else { - m_breakpoint_lines.remove_first_matching([&](size_t line) { return line == text_position.line(); }); + breakpoint_lines().remove_first_matching([&](size_t line) { return line == text_position.line(); }); on_breakpoint_change(wrapper().filename_label().text(), text_position.line(), BreakpointChange::Removed); } } @@ -373,18 +373,18 @@ void Editor::navigate_to_include_if_available(String path) void Editor::set_execution_position(size_t line_number) { - m_execution_position = line_number; + code_document().set_execution_position(line_number); scroll_position_into_view({ line_number, 0 }); update(breakpoint_icon_rect(line_number)); } void Editor::clear_execution_position() { - if (!m_execution_position.has_value()) { + if (!execution_position().has_value()) { return; } - size_t previous_position = m_execution_position.value(); - m_execution_position = {}; + size_t previous_position = execution_position().value(); + code_document().clear_execution_position(); update(breakpoint_icon_rect(previous_position)); } @@ -399,3 +399,21 @@ const Gfx::Bitmap& Editor::current_position_icon_bitmap() static auto bitmap = Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png"); return *bitmap; } + +const CodeDocument& Editor::code_document() const +{ + const auto& doc = document(); + ASSERT(doc.is_code_document()); + return static_cast<const CodeDocument&>(doc); +} + +CodeDocument& Editor::code_document() +{ + return const_cast<CodeDocument&>(static_cast<const Editor&>(*this).code_document()); +} + +void Editor::set_document(GUI::TextDocument& doc) +{ + ASSERT(doc.is_code_document()); + GUI::TextEditor::set_document(doc); +} diff --git a/DevTools/HackStudio/Editor.h b/DevTools/HackStudio/Editor.h index accf1bec6b..47d9b5c977 100644 --- a/DevTools/HackStudio/Editor.h +++ b/DevTools/HackStudio/Editor.h @@ -26,6 +26,7 @@ #pragma once +#include "CodeDocument.h" #include "Debugger/BreakpointCallback.h" #include <AK/Optional.h> #include <LibGUI/TextEditor.h> @@ -44,12 +45,19 @@ public: EditorWrapper& wrapper(); const EditorWrapper& wrapper() const; - const Vector<size_t>& breakpoint_lines() const { return m_breakpoint_lines; } + const Vector<size_t>& breakpoint_lines() const { return code_document().breakpoint_lines(); } + Vector<size_t>& breakpoint_lines() { return code_document().breakpoint_lines(); } + Optional<size_t> execution_position() const { return code_document().execution_position(); } void set_execution_position(size_t line_number); void clear_execution_position(); BreakpointChangeCallback on_breakpoint_change; + const CodeDocument& code_document() const; + CodeDocument& code_document(); + + virtual void set_document(GUI::TextDocument&) override; + private: virtual void focusin_event(GUI::FocusEvent&) override; virtual void focusout_event(GUI::FocusEvent&) override; @@ -77,7 +85,4 @@ private: bool m_hovering_editor { false }; bool m_hovering_link { false }; bool m_holding_ctrl { false }; - - Vector<size_t> m_breakpoint_lines; - Optional<size_t> m_execution_position; }; diff --git a/DevTools/HackStudio/ProjectFile.cpp b/DevTools/HackStudio/ProjectFile.cpp index 0e9493f40f..3cf3a65c1b 100644 --- a/DevTools/HackStudio/ProjectFile.cpp +++ b/DevTools/HackStudio/ProjectFile.cpp @@ -36,7 +36,7 @@ ProjectFile::ProjectFile(const String& name) const GUI::TextDocument& ProjectFile::document() const { if (!m_document) { - m_document = GUI::TextDocument::create(nullptr); + m_document = CodeDocument::create(nullptr); auto file = Core::File::construct(m_name); if (!file->open(Core::File::ReadOnly)) { ASSERT_NOT_REACHED(); diff --git a/DevTools/HackStudio/ProjectFile.h b/DevTools/HackStudio/ProjectFile.h index 1019d83368..084b5fe829 100644 --- a/DevTools/HackStudio/ProjectFile.h +++ b/DevTools/HackStudio/ProjectFile.h @@ -26,11 +26,11 @@ #pragma once +#include "CodeDocument.h" #include <AK/ByteBuffer.h> #include <AK/NonnullRefPtr.h> #include <AK/RefCounted.h> #include <AK/String.h> -#include <LibGUI/TextDocument.h> class ProjectFile : public RefCounted<ProjectFile> { public: @@ -47,5 +47,5 @@ private: explicit ProjectFile(const String& name); String m_name; - mutable RefPtr<GUI::TextDocument> m_document; + mutable RefPtr<CodeDocument> m_document; }; diff --git a/Libraries/LibGUI/TextDocument.h b/Libraries/LibGUI/TextDocument.h index ff5f8e6cc3..5a061da3b0 100644 --- a/Libraries/LibGUI/TextDocument.h +++ b/Libraries/LibGUI/TextDocument.h @@ -75,7 +75,7 @@ public: }; static NonnullRefPtr<TextDocument> create(Client* client = nullptr); - ~TextDocument(); + virtual ~TextDocument(); size_t line_count() const { return m_lines.size(); } const TextDocumentLine& line(size_t line_index) const { return m_lines[line_index]; } @@ -137,9 +137,12 @@ public: TextPosition insert_at(const TextPosition&, const StringView&, const Client* = nullptr); void remove(const TextRange&); -private: + virtual bool is_code_document() const { return false; } + +protected: explicit TextDocument(Client* client); +private: void update_undo_timer(); NonnullOwnPtrVector<TextDocumentLine> m_lines; diff --git a/Libraries/LibGUI/TextEditor.h b/Libraries/LibGUI/TextEditor.h index e67c3fa801..fdb95b72e7 100644 --- a/Libraries/LibGUI/TextEditor.h +++ b/Libraries/LibGUI/TextEditor.h @@ -58,7 +58,7 @@ public: const TextDocument& document() const { return *m_document; } TextDocument& document() { return *m_document; } - void set_document(TextDocument&); + virtual void set_document(TextDocument&); bool has_visible_list() const { return m_has_visible_list; } void set_has_visible_list(bool); @@ -175,7 +175,7 @@ protected: virtual void context_menu_event(ContextMenuEvent&) override; virtual void resize_event(ResizeEvent&) override; virtual void theme_change_event(ThemeChangeEvent&) override; - virtual void cursor_did_change() { } + virtual void cursor_did_change() {} Gfx::IntRect ruler_content_rect(size_t line) const; TextPosition text_position_at(const Gfx::IntPoint&) const; |