From 879bf3e97b5d36b83e39eef66c8b54874b8199ab Mon Sep 17 00:00:00 2001 From: Oriko Date: Thu, 12 Mar 2020 00:18:13 +0200 Subject: [PATCH] HackStudio: Add header navigation --- DevTools/HackStudio/Editor.cpp | 77 ++++++++++++++++++++++++++- DevTools/HackStudio/Editor.h | 3 ++ DevTools/HackStudio/EditorWrapper.cpp | 5 ++ DevTools/HackStudio/main.cpp | 14 ++++- 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/DevTools/HackStudio/Editor.cpp b/DevTools/HackStudio/Editor.cpp index 9cecd1b330..c183d117b9 100644 --- a/DevTools/HackStudio/Editor.cpp +++ b/DevTools/HackStudio/Editor.cpp @@ -34,14 +34,14 @@ #include #include #include +#include #include #include #include #include #include -#include -//#define EDITOR_DEBUG +// #define EDITOR_DEBUG Editor::Editor() { @@ -194,3 +194,76 @@ void Editor::mousemove_event(GUI::MouseEvent& event) } GUI::Application::the().hide_tooltip(); } + +void Editor::mousedown_event(GUI::MouseEvent& event) +{ + if (!(event.modifiers() & Mod_Ctrl)) { + GUI::TextEditor::mousedown_event(event); + return; + } + + auto text_position = text_position_at(event.position()); + if (!text_position.is_valid()) { + GUI::TextEditor::mousedown_event(event); + return; + } + + for (auto& span : document().spans()) { + if (span.range.contains(text_position)) { + auto adjusted_range = span.range; + adjusted_range.end().set_column(adjusted_range.end().column() + 1); + auto span_text = document().text_in_range(adjusted_range); + auto header_path = span_text.substring(1, span_text.length() - 2); +#ifdef EDITOR_DEBUG + dbg() << "Ctrl+click: " << adjusted_range << " \"" << header_path << "\""; +#endif + navigate_to_include_if_available(header_path); + return; + } + } + + GUI::TextEditor::mousedown_event(event); +} + +static HashMap& include_paths() +{ + static HashMap paths; + + auto add_directory = [](String base, Optional recursive, auto handle_directory) -> void { + Core::DirIterator it(recursive.value_or(base), Core::DirIterator::Flags::SkipDots); + while (it.has_next()) { + auto path = it.next_full_path(); + if (!Core::File::is_directory(path)) { + auto key = path.substring(base.length() + 1, path.length() - base.length() - 1); +#ifdef EDITOR_DEBUG + dbg() << "Adding header \"" << key << "\" in path \"" << path << "\""; +#endif + paths.set(key, path); + } else { + handle_directory(base, path, handle_directory); + } + } + }; + + if (paths.is_empty()) { + add_directory(".", {}, add_directory); + add_directory("/usr/local/include", {}, add_directory); + add_directory("/usr/local/include/c++/9.2.0", {}, add_directory); + add_directory("/usr/include", {}, add_directory); + } + + return paths; +} + +void Editor::navigate_to_include_if_available(String path) +{ + auto it = include_paths().find(path); + if (it == include_paths().end()) { +#ifdef EDITOR_DEBUG + dbg() << "no header " << path << " found."; +#endif + return; + } + + on_open(it->value); +} diff --git a/DevTools/HackStudio/Editor.h b/DevTools/HackStudio/Editor.h index f4096cd126..c02d7d01e6 100644 --- a/DevTools/HackStudio/Editor.h +++ b/DevTools/HackStudio/Editor.h @@ -37,6 +37,7 @@ public: virtual ~Editor() override; Function on_focus; + Function on_open; EditorWrapper& wrapper(); const EditorWrapper& wrapper() const; @@ -46,8 +47,10 @@ private: virtual void focusout_event(Core::Event&) override; virtual void paint_event(GUI::PaintEvent&) override; virtual void mousemove_event(GUI::MouseEvent&) override; + virtual void mousedown_event(GUI::MouseEvent&) override; void show_documentation_tooltip_if_available(const String&, const Gfx::Point& screen_location); + void navigate_to_include_if_available(String); explicit Editor(); diff --git a/DevTools/HackStudio/EditorWrapper.cpp b/DevTools/HackStudio/EditorWrapper.cpp index 041642195e..5a638f98e3 100644 --- a/DevTools/HackStudio/EditorWrapper.cpp +++ b/DevTools/HackStudio/EditorWrapper.cpp @@ -33,6 +33,7 @@ #include extern RefPtr g_current_editor_wrapper; +extern Function g_open_file; EditorWrapper::EditorWrapper() { @@ -67,6 +68,10 @@ EditorWrapper::EditorWrapper() m_editor->on_focus = [this] { g_current_editor_wrapper = this; }; + + m_editor->on_open = [this](String path) { + g_open_file(path); + }; } EditorWrapper::~EditorWrapper() diff --git a/DevTools/HackStudio/main.cpp b/DevTools/HackStudio/main.cpp index 4c2bab762c..d3e04044fa 100644 --- a/DevTools/HackStudio/main.cpp +++ b/DevTools/HackStudio/main.cpp @@ -66,6 +66,7 @@ NonnullRefPtrVector g_all_editor_wrappers; RefPtr g_current_editor_wrapper; +Function g_open_file; String g_currently_open_file; OwnPtr g_project; @@ -529,6 +530,8 @@ int main(int argc, char** argv) remove_current_editor_action->set_enabled(g_all_editor_wrappers.size() > 1); }; + g_open_file = open_file; + open_file("main.cpp"); update_actions(); @@ -547,8 +550,15 @@ void run(TerminalWrapper& wrapper) void open_file(const String& filename) { - auto file = g_project->get_file(filename); - current_editor().set_document(const_cast(file->document())); + auto project_file = g_project->get_file(filename); + if (project_file) { + current_editor().set_document(const_cast(project_file->document())); + current_editor().set_readonly(false); + } else { + auto external_file = ProjectFile::construct_with_name(filename); + current_editor().set_document(const_cast(external_file->document())); + current_editor().set_readonly(true); + } if (filename.ends_with(".cpp") || filename.ends_with(".h")) current_editor().set_syntax_highlighter(make());