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. + * 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::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. + * 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 + +class CodeDocument final : public GUI::TextDocument { +public: + virtual ~CodeDocument() override; + static NonnullRefPtr create(Client* client = nullptr); + + const Vector& breakpoint_lines() const { return m_breakpoint_lines; } + Vector& breakpoint_lines() { return m_breakpoint_lines; } + Optional 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 m_breakpoint_lines; + Optional 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 #include #include -#include #include +#include #include // #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(doc); +} + +CodeDocument& Editor::code_document() +{ + return const_cast(static_cast(*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 #include @@ -44,12 +45,19 @@ public: EditorWrapper& wrapper(); const EditorWrapper& wrapper() const; - const Vector& breakpoint_lines() const { return m_breakpoint_lines; } + const Vector& breakpoint_lines() const { return code_document().breakpoint_lines(); } + Vector& breakpoint_lines() { return code_document().breakpoint_lines(); } + Optional 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 m_breakpoint_lines; - Optional 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 #include #include #include -#include class ProjectFile : public RefCounted { public: @@ -47,5 +47,5 @@ private: explicit ProjectFile(const String& name); String m_name; - mutable RefPtr m_document; + mutable RefPtr 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 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 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;