diff options
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Applications/Help/CMakeLists.txt | 5 | ||||
-rw-r--r-- | Userland/Applications/Help/MainWidget.cpp | 80 | ||||
-rw-r--r-- | Userland/Applications/Help/MainWidget.h | 4 | ||||
-rw-r--r-- | Userland/Applications/Help/ManualModel.cpp | 99 | ||||
-rw-r--r-- | Userland/Applications/Help/ManualModel.h | 12 | ||||
-rw-r--r-- | Userland/Applications/Help/ManualNode.h | 22 | ||||
-rw-r--r-- | Userland/Applications/Help/ManualPageNode.cpp | 25 | ||||
-rw-r--r-- | Userland/Applications/Help/ManualPageNode.h | 33 | ||||
-rw-r--r-- | Userland/Applications/Help/ManualSectionNode.cpp | 46 | ||||
-rw-r--r-- | Userland/Applications/Help/ManualSectionNode.h | 44 | ||||
-rw-r--r-- | Userland/Applications/Help/main.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibManual/CMakeLists.txt | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibManual/Node.h | 30 | ||||
-rw-r--r-- | Userland/Libraries/LibManual/PageNode.cpp | 29 | ||||
-rw-r--r-- | Userland/Libraries/LibManual/PageNode.h | 38 | ||||
-rw-r--r-- | Userland/Libraries/LibManual/SectionNode.cpp | 62 | ||||
-rw-r--r-- | Userland/Libraries/LibManual/SectionNode.h | 65 |
18 files changed, 339 insertions, 265 deletions
diff --git a/Userland/Applications/Help/CMakeLists.txt b/Userland/Applications/Help/CMakeLists.txt index 9f7f9ee67a..7b037da522 100644 --- a/Userland/Applications/Help/CMakeLists.txt +++ b/Userland/Applications/Help/CMakeLists.txt @@ -12,8 +12,6 @@ set(SOURCES main.cpp MainWidget.cpp ManualModel.cpp - ManualPageNode.cpp - ManualSectionNode.cpp ) set(GENERATED_SOURCES @@ -21,4 +19,5 @@ set(GENERATED_SOURCES ) serenity_app(Help ICON app-help) -target_link_libraries(Help PRIVATE LibCore LibWebView LibWeb LibMarkdown LibGfx LibGUI LibDesktop LibMain) +target_link_libraries(Help PRIVATE LibCore LibWebView LibWeb LibMarkdown LibGfx LibGUI LibDesktop LibMain LibManual) +link_with_locale_data(Help) diff --git a/Userland/Applications/Help/MainWidget.cpp b/Userland/Applications/Help/MainWidget.cpp index 796ff97265..ffe7b88a98 100644 --- a/Userland/Applications/Help/MainWidget.cpp +++ b/Userland/Applications/Help/MainWidget.cpp @@ -8,7 +8,9 @@ */ #include "MainWidget.h" -#include <AK/DeprecatedString.h> +#include <AK/LexicalPath.h> +#include <AK/String.h> +#include <AK/StringView.h> #include <AK/URL.h> #include <Applications/Help/HelpWindowGML.h> #include <LibCore/ArgsParser.h> @@ -30,6 +32,9 @@ #include <LibGUI/Window.h> #include <LibGfx/Bitmap.h> #include <LibMain/Main.h> +#include <LibManual/Node.h> +#include <LibManual/PageNode.h> +#include <LibManual/SectionNode.h> #include <LibMarkdown/Document.h> namespace Help { @@ -66,25 +71,25 @@ MainWidget::MainWidget() } auto& search_model = *static_cast<GUI::FilteringProxyModel*>(view_model); auto const& mapped_index = search_model.map(index); - DeprecatedString path = m_manual_model->page_path(mapped_index); - if (path.is_null()) { + auto path = m_manual_model->page_path(mapped_index); + if (!path.has_value()) { m_web_view->load_empty_document(); return; } m_browse_view->selection().clear(); m_browse_view->selection().add(mapped_index); - m_history.push(path); - open_page(path); + m_history.push(path.value()); + open_page(path.value()); }; m_browse_view = find_descendant_of_type_named<GUI::TreeView>("browse_view"); m_browse_view->on_selection_change = [this] { - DeprecatedString path = m_manual_model->page_path(m_browse_view->selection().first()); - if (path.is_null()) + auto path = m_manual_model->page_path(m_browse_view->selection().first()); + if (!path.has_value()) return; - m_history.push(path); - open_page(path); + m_history.push(path.value()); + open_page(path.value()); }; m_browse_view->on_toggle = [this](GUI::ModelIndex const& index, bool open) { m_manual_model->update_section_node_on_toggle(index, open); @@ -105,7 +110,7 @@ MainWidget::MainWidget() return; } m_history.push(path); - open_page(path); + open_page(MUST(String::from_utf8(path))); } else if (url.scheme() == "help") { if (url.host() == "man") { if (url.paths().size() != 2) { @@ -138,23 +143,17 @@ MainWidget::MainWidget() m_go_back_action = GUI::CommonActions::make_go_back_action([this](auto&) { m_history.go_back(); - open_page(m_history.current()); + open_page(MUST(String::from_deprecated_string(m_history.current()))); }); m_go_forward_action = GUI::CommonActions::make_go_forward_action([this](auto&) { m_history.go_forward(); - open_page(m_history.current()); + open_page(MUST(String::from_deprecated_string(m_history.current()))); }); m_go_back_action->set_enabled(false); m_go_forward_action->set_enabled(false); - m_go_home_action = GUI::CommonActions::make_go_home_action([this](auto&) { - DeprecatedString path = "/usr/share/man/man7/Help-index.md"; - m_history.push(path); - open_page(path); - }); - m_copy_action = GUI::CommonActions::make_copy_action([this](auto&) { auto selected_text = m_web_view->selected_text(); if (!selected_text.is_empty()) @@ -174,37 +173,27 @@ MainWidget::MainWidget() }; } -void MainWidget::set_start_page(StringView start_page, u32 section) +ErrorOr<void> MainWidget::set_start_page(StringView start_page, u32 section) { bool set_start_page = false; if (!start_page.is_null()) { if (section != 0) { // > Help [section] [name] - DeprecatedString path = DeprecatedString::formatted("/usr/share/man/man{}/{}.md", section, start_page); + String path = TRY(String::formatted("/usr/share/man/man{}/{}.md", section, start_page)); m_history.push(path); open_page(path); set_start_page = true; } else if (URL url = URL::create_with_url_or_path(start_page); url.is_valid() && url.path().ends_with(".md"sv)) { // > Help [/path/to/documentation/file.md] m_history.push(url.path()); - open_page(url.path()); + open_page(TRY(String::from_deprecated_string(url.path()))); set_start_page = true; } else { // > Help [query] // First, see if we can find the page by name - char const* sections[] = { - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8" - }; - for (auto s : sections) { - DeprecatedString path = DeprecatedString::formatted("/usr/share/man/man{}/{}.md", s, start_page); + for (auto s : Manual::section_numbers) { + String path = TRY(String::formatted("/usr/share/man/man{}/{}.md", s, start_page)); if (Core::File::exists(path)) { m_history.push(path); open_page(path); @@ -225,10 +214,17 @@ void MainWidget::set_start_page(StringView start_page, u32 section) } if (!set_start_page) m_go_home_action->activate(); + return {}; } ErrorOr<void> MainWidget::initialize_fallibles(GUI::Window& window) { + static String help_index_path = TRY(String::from_utf8("/usr/share/man/man7/Help-index.md"sv)); + m_go_home_action = GUI::CommonActions::make_go_home_action([this](auto&) { + m_history.push(help_index_path); + open_page(help_index_path); + }); + (void)TRY(m_toolbar->try_add_action(*m_go_back_action)); (void)TRY(m_toolbar->try_add_action(*m_go_forward_action)); (void)TRY(m_toolbar->try_add_action(*m_go_home_action)); @@ -244,10 +240,10 @@ ErrorOr<void> MainWidget::initialize_fallibles(GUI::Window& window) TRY(go_menu->try_add_action(*m_go_home_action)); auto help_menu = TRY(window.try_add_menu("&Help")); + static String help_page_path = TRY(String::from_utf8("/usr/share/man/man1/Help.md"sv)); TRY(help_menu->try_add_action(GUI::CommonActions::make_command_palette_action(&window))); TRY(help_menu->try_add_action(GUI::Action::create("&Contents", { Key_F1 }, TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/filetype-unknown.png"sv)), [&](auto&) { - DeprecatedString path = "/usr/share/man/man1/Help.md"; - open_page(path); + open_page(help_page_path); }))); TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("Help", TRY(GUI::Icon::try_create_default_icon("app-help"sv)), &window))); @@ -282,8 +278,12 @@ void MainWidget::open_url(URL const& url) if (browse_view_index.has_value()) { m_browse_view->expand_tree(browse_view_index.value().parent()); - DeprecatedString page_and_section = m_manual_model->page_and_section(browse_view_index.value()); - window()->set_title(DeprecatedString::formatted("{} - Help", page_and_section)); + auto page_and_section = m_manual_model->page_and_section(browse_view_index.value()); + if (!page_and_section.has_value()) + return; + auto title = String::formatted("{} - Help", page_and_section.value()); + if (!title.is_error()) + window()->set_title(title.release_value().to_deprecated_string()); } else { window()->set_title("Help"); } @@ -297,17 +297,17 @@ void MainWidget::open_external(URL const& url) GUI::MessageBox::show(window(), DeprecatedString::formatted("The link to '{}' could not be opened.", url), "Failed to open link"sv, GUI::MessageBox::Type::Error); } -void MainWidget::open_page(DeprecatedString const& path) +void MainWidget::open_page(Optional<String> const& path) { m_go_back_action->set_enabled(m_history.can_go_back()); m_go_forward_action->set_enabled(m_history.can_go_forward()); - if (path.is_null()) { + if (!path.has_value()) { window()->set_title("Help"); m_web_view->load_empty_document(); return; } - open_url(URL::create_with_url_or_path(path)); + open_url(URL::create_with_url_or_path(path.value().to_deprecated_string())); } } diff --git a/Userland/Applications/Help/MainWidget.h b/Userland/Applications/Help/MainWidget.h index 18f3aa91be..8f1012a84b 100644 --- a/Userland/Applications/Help/MainWidget.h +++ b/Userland/Applications/Help/MainWidget.h @@ -20,13 +20,13 @@ public: virtual ~MainWidget() override = default; ErrorOr<void> initialize_fallibles(GUI::Window&); - void set_start_page(StringView page, u32 section); + ErrorOr<void> set_start_page(StringView page, u32 section); private: MainWidget(); void open_url(URL const&); - void open_page(DeprecatedString const& path); + void open_page(Optional<String> const& path); void open_external(URL const&); History m_history; diff --git a/Userland/Applications/Help/ManualModel.cpp b/Userland/Applications/Help/ManualModel.cpp index cf07fedc1b..1584d349a3 100644 --- a/Userland/Applications/Help/ManualModel.cpp +++ b/Userland/Applications/Help/ManualModel.cpp @@ -5,21 +5,11 @@ */ #include "ManualModel.h" -#include "ManualNode.h" -#include "ManualPageNode.h" -#include "ManualSectionNode.h" #include <AK/Try.h> - -static ManualSectionNode s_sections[] = { - { "1", "User Programs" }, - { "2", "System Calls" }, - { "3", "Library Functions" }, - { "4", "Special Files" }, - { "5", "File Formats" }, - { "6", "Games" }, - { "7", "Miscellanea" }, - { "8", "Sysadmin Tools" } -}; +#include <AK/Utf8View.h> +#include <LibManual/Node.h> +#include <LibManual/PageNode.h> +#include <LibManual/SectionNode.h> ManualModel::ManualModel() { @@ -34,11 +24,14 @@ Optional<GUI::ModelIndex> ManualModel::index_from_path(StringView path) const auto parent_index = index(section, 0); for (int row = 0; row < row_count(parent_index); ++row) { auto child_index = index(row, 0, parent_index); - auto* node = static_cast<ManualNode const*>(child_index.internal_data()); + auto* node = static_cast<Manual::Node const*>(child_index.internal_data()); if (!node->is_page()) continue; - auto* page = static_cast<ManualPageNode const*>(node); - if (page->path() != path) + auto* page = static_cast<Manual::PageNode const*>(node); + auto const maybe_path = page->path(); + if (maybe_path.is_error()) + return {}; + if (maybe_path.value().bytes_as_string_view() != path) continue; return child_index; } @@ -46,29 +39,32 @@ Optional<GUI::ModelIndex> ManualModel::index_from_path(StringView path) const return {}; } -DeprecatedString ManualModel::page_name(const GUI::ModelIndex& index) const +Optional<String> ManualModel::page_name(const GUI::ModelIndex& index) const { if (!index.is_valid()) return {}; - auto* node = static_cast<ManualNode const*>(index.internal_data()); + auto* node = static_cast<Manual::Node const*>(index.internal_data()); if (!node->is_page()) return {}; - auto* page = static_cast<ManualPageNode const*>(node); + auto* page = static_cast<Manual::PageNode const*>(node); return page->name(); } -DeprecatedString ManualModel::page_path(const GUI::ModelIndex& index) const +Optional<String> ManualModel::page_path(const GUI::ModelIndex& index) const { if (!index.is_valid()) return {}; - auto* node = static_cast<ManualNode const*>(index.internal_data()); + auto* node = static_cast<Manual::Node const*>(index.internal_data()); if (!node->is_page()) return {}; - auto* page = static_cast<ManualPageNode const*>(node); - return page->path(); + auto* page = static_cast<Manual::PageNode const*>(node); + auto path = page->path(); + if (path.is_error()) + return {}; + return path.release_value(); } -ErrorOr<StringView> ManualModel::page_view(DeprecatedString const& path) const +ErrorOr<StringView> ManualModel::page_view(String const& path) const { if (path.is_empty()) return StringView {}; @@ -87,23 +83,29 @@ ErrorOr<StringView> ManualModel::page_view(DeprecatedString const& path) const return view; } -DeprecatedString ManualModel::page_and_section(const GUI::ModelIndex& index) const +Optional<String> ManualModel::page_and_section(const GUI::ModelIndex& index) const { if (!index.is_valid()) return {}; - auto* node = static_cast<ManualNode const*>(index.internal_data()); + auto* node = static_cast<Manual::Node const*>(index.internal_data()); if (!node->is_page()) return {}; - auto* page = static_cast<ManualPageNode const*>(node); - auto* section = static_cast<ManualSectionNode const*>(page->parent()); - return DeprecatedString::formatted("{}({})", page->name(), section->section_name()); + auto* page = static_cast<Manual::PageNode const*>(node); + auto* section = static_cast<Manual::SectionNode const*>(page->parent()); + auto page_name = page->name(); + if (page_name.is_error()) + return {}; + auto name = String::formatted("{}({})", page_name.release_value(), section->section_name()); + if (name.is_error()) + return {}; + return name.release_value(); } GUI::ModelIndex ManualModel::index(int row, int column, const GUI::ModelIndex& parent_index) const { if (!parent_index.is_valid()) - return create_index(row, column, &s_sections[row]); - auto* parent = static_cast<ManualNode const*>(parent_index.internal_data()); + return create_index(row, column, Manual::sections[row].ptr()); + auto* parent = static_cast<Manual::Node const*>(parent_index.internal_data()); auto* child = &parent->children()[row]; return create_index(row, column, child); } @@ -112,19 +114,19 @@ GUI::ModelIndex ManualModel::parent_index(const GUI::ModelIndex& index) const { if (!index.is_valid()) return {}; - auto* child = static_cast<ManualNode const*>(index.internal_data()); + auto* child = static_cast<Manual::Node const*>(index.internal_data()); auto* parent = child->parent(); if (parent == nullptr) return {}; if (parent->parent() == nullptr) { - for (size_t row = 0; row < sizeof(s_sections) / sizeof(s_sections[0]); row++) - if (&s_sections[row] == parent) + for (size_t row = 0; row < sizeof(Manual::sections) / sizeof(Manual::sections[0]); row++) + if (Manual::sections[row].ptr() == parent) return create_index(row, 0, parent); VERIFY_NOT_REACHED(); } for (size_t row = 0; row < parent->parent()->children().size(); row++) { - ManualNode* child_at_row = &parent->parent()->children()[row]; + Manual::Node* child_at_row = &parent->parent()->children()[row]; if (child_at_row == parent) return create_index(row, 0, parent); } @@ -134,8 +136,8 @@ GUI::ModelIndex ManualModel::parent_index(const GUI::ModelIndex& index) const int ManualModel::row_count(const GUI::ModelIndex& index) const { if (!index.is_valid()) - return sizeof(s_sections) / sizeof(s_sections[0]); - auto* node = static_cast<ManualNode const*>(index.internal_data()); + return sizeof(Manual::sections) / sizeof(Manual::sections[0]); + auto* node = static_cast<Manual::Node const*>(index.internal_data()); return node->children().size(); } @@ -146,12 +148,16 @@ int ManualModel::column_count(const GUI::ModelIndex&) const GUI::Variant ManualModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const { - auto* node = static_cast<ManualNode const*>(index.internal_data()); + auto* node = static_cast<Manual::Node const*>(index.internal_data()); switch (role) { case GUI::ModelRole::Search: if (!node->is_page()) return {}; - return DeprecatedString(page_view(page_path(index)).value()); + if (auto path = page_path(index); path.has_value()) + if (auto page = page_view(path.release_value()); !page.is_error()) + // FIXME: We already provide String, but GUI::Variant still needs DeprecatedString. + return DeprecatedString(page.release_value()); + return {}; case GUI::ModelRole::Display: return node->name(); case GUI::ModelRole::Icon: @@ -167,17 +173,24 @@ GUI::Variant ManualModel::data(const GUI::ModelIndex& index, GUI::ModelRole role void ManualModel::update_section_node_on_toggle(const GUI::ModelIndex& index, bool const open) { - auto* node = static_cast<ManualSectionNode*>(index.internal_data()); + auto* node = static_cast<Manual::SectionNode*>(index.internal_data()); node->set_open(open); } TriState ManualModel::data_matches(const GUI::ModelIndex& index, const GUI::Variant& term) const { auto name = page_name(index); - if (name.contains(term.as_string(), CaseSensitivity::CaseInsensitive)) + if (!name.has_value()) + return TriState::False; + + if (name.value().bytes_as_string_view().contains(term.as_string(), CaseSensitivity::CaseInsensitive)) return TriState::True; - auto view_result = page_view(page_path(index)); + auto path = page_path(index); + // NOTE: This is slightly inaccurate, as page_path can also fail due to OOM. We consider it acceptable to have a data mismatch in that case. + if (!path.has_value()) + return TriState::False; + auto view_result = page_view(path.release_value()); if (view_result.is_error() || view_result.value().is_empty()) return TriState::False; diff --git a/Userland/Applications/Help/ManualModel.h b/Userland/Applications/Help/ManualModel.h index 8655fe1009..41415d9605 100644 --- a/Userland/Applications/Help/ManualModel.h +++ b/Userland/Applications/Help/ManualModel.h @@ -6,10 +6,10 @@ #pragma once -#include <AK/DeprecatedString.h> #include <AK/NonnullRefPtr.h> #include <AK/Optional.h> #include <AK/Result.h> +#include <AK/String.h> #include <LibGUI/Model.h> class ManualModel final : public GUI::Model { @@ -23,10 +23,10 @@ public: Optional<GUI::ModelIndex> index_from_path(StringView) const; - DeprecatedString page_name(const GUI::ModelIndex&) const; - DeprecatedString page_path(const GUI::ModelIndex&) const; - DeprecatedString page_and_section(const GUI::ModelIndex&) const; - ErrorOr<StringView> page_view(DeprecatedString const& path) const; + Optional<String> page_name(const GUI::ModelIndex&) const; + Optional<String> page_path(const GUI::ModelIndex&) const; + Optional<String> page_and_section(const GUI::ModelIndex&) const; + ErrorOr<StringView> page_view(String const& path) const; void update_section_node_on_toggle(const GUI::ModelIndex&, bool const); virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override; @@ -42,5 +42,5 @@ private: GUI::Icon m_section_open_icon; GUI::Icon m_section_icon; GUI::Icon m_page_icon; - mutable HashMap<DeprecatedString, NonnullRefPtr<Core::MappedFile>> m_mapped_files; + mutable HashMap<String, NonnullRefPtr<Core::MappedFile>> m_mapped_files; }; diff --git a/Userland/Applications/Help/ManualNode.h b/Userland/Applications/Help/ManualNode.h deleted file mode 100644 index d9157b06fc..0000000000 --- a/Userland/Applications/Help/ManualNode.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/DeprecatedString.h> -#include <AK/NonnullOwnPtrVector.h> - -class ManualNode { -public: - virtual ~ManualNode() = default; - - virtual NonnullOwnPtrVector<ManualNode>& children() const = 0; - virtual ManualNode const* parent() const = 0; - virtual DeprecatedString name() const = 0; - virtual bool is_page() const { return false; } - virtual bool is_open() const { return false; } -}; diff --git a/Userland/Applications/Help/ManualPageNode.cpp b/Userland/Applications/Help/ManualPageNode.cpp deleted file mode 100644 index 52223c5d46..0000000000 --- a/Userland/Applications/Help/ManualPageNode.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "ManualPageNode.h" -#include "ManualSectionNode.h" - -ManualNode const* ManualPageNode::parent() const -{ - return &m_section; -} - -NonnullOwnPtrVector<ManualNode>& ManualPageNode::children() const -{ - static NonnullOwnPtrVector<ManualNode> empty_vector; - return empty_vector; -} - -DeprecatedString ManualPageNode::path() const -{ - return DeprecatedString::formatted("{}/{}.md", m_section.path(), m_page); -} diff --git a/Userland/Applications/Help/ManualPageNode.h b/Userland/Applications/Help/ManualPageNode.h deleted file mode 100644 index e0a9ade594..0000000000 --- a/Userland/Applications/Help/ManualPageNode.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "ManualNode.h" - -class ManualSectionNode; - -class ManualPageNode : public ManualNode { -public: - virtual ~ManualPageNode() override = default; - - ManualPageNode(ManualSectionNode const& section, StringView page) - : m_section(section) - , m_page(page) - { - } - - virtual NonnullOwnPtrVector<ManualNode>& children() const override; - virtual ManualNode const* parent() const override; - virtual DeprecatedString name() const override { return m_page; }; - virtual bool is_page() const override { return true; } - - DeprecatedString path() const; - -private: - ManualSectionNode const& m_section; - DeprecatedString m_page; -}; diff --git a/Userland/Applications/Help/ManualSectionNode.cpp b/Userland/Applications/Help/ManualSectionNode.cpp deleted file mode 100644 index 2259715693..0000000000 --- a/Userland/Applications/Help/ManualSectionNode.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "ManualSectionNode.h" -#include "ManualPageNode.h" -#include <AK/DeprecatedString.h> -#include <AK/LexicalPath.h> -#include <AK/QuickSort.h> -#include <LibCore/DirIterator.h> - -DeprecatedString ManualSectionNode::path() const -{ - return DeprecatedString::formatted("/usr/share/man/man{}", m_section); -} - -void ManualSectionNode::reify_if_needed() const -{ - if (m_reified) - return; - m_reified = true; - - Core::DirIterator dir_iter { path(), Core::DirIterator::Flags::SkipDots }; - - Vector<DeprecatedString> page_names; - while (dir_iter.has_next()) { - LexicalPath lexical_path(dir_iter.next_path()); - if (lexical_path.extension() != "md") - continue; - page_names.append(lexical_path.title()); - } - - quick_sort(page_names); - - for (auto& page_name : page_names) - m_children.append(make<ManualPageNode>(*this, move(page_name))); -} - -void ManualSectionNode::set_open(bool open) -{ - if (m_open == open) - return; - m_open = open; -} diff --git a/Userland/Applications/Help/ManualSectionNode.h b/Userland/Applications/Help/ManualSectionNode.h deleted file mode 100644 index ee7850f1db..0000000000 --- a/Userland/Applications/Help/ManualSectionNode.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "ManualNode.h" - -class ManualSectionNode : public ManualNode { -public: - virtual ~ManualSectionNode() override = default; - - ManualSectionNode(DeprecatedString section, DeprecatedString name) - : m_section(section) - , m_full_name(DeprecatedString::formatted("{}. {}", section, name)) - { - } - - virtual NonnullOwnPtrVector<ManualNode>& children() const override - { - reify_if_needed(); - return m_children; - } - - virtual ManualNode const* parent() const override { return nullptr; } - virtual DeprecatedString name() const override { return m_full_name; } - virtual bool is_open() const override { return m_open; } - void set_open(bool open); - - DeprecatedString const& section_name() const { return m_section; } - DeprecatedString path() const; - -private: - void reify_if_needed() const; - - DeprecatedString m_section; - DeprecatedString m_full_name; - mutable NonnullOwnPtrVector<ManualNode> m_children; - mutable bool m_reified { false }; - bool m_open { false }; -}; diff --git a/Userland/Applications/Help/main.cpp b/Userland/Applications/Help/main.cpp index d6db39b13d..52bd2ca23e 100644 --- a/Userland/Applications/Help/main.cpp +++ b/Userland/Applications/Help/main.cpp @@ -87,7 +87,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) auto main_widget = TRY(window->try_set_main_widget<MainWidget>()); TRY(main_widget->initialize_fallibles(window)); - main_widget->set_start_page(start_page, section); + TRY(main_widget->set_start_page(start_page, section)); window->show(); diff --git a/Userland/Libraries/CMakeLists.txt b/Userland/Libraries/CMakeLists.txt index dde02378b1..c1e7ac418a 100644 --- a/Userland/Libraries/CMakeLists.txt +++ b/Userland/Libraries/CMakeLists.txt @@ -35,6 +35,7 @@ add_subdirectory(LibKeyboard) add_subdirectory(LibLine) add_subdirectory(LibLocale) add_subdirectory(LibMain) +add_subdirectory(LibManual) add_subdirectory(LibMarkdown) add_subdirectory(LibPartition) add_subdirectory(LibPCIDB) diff --git a/Userland/Libraries/LibManual/CMakeLists.txt b/Userland/Libraries/LibManual/CMakeLists.txt new file mode 100644 index 0000000000..13f0454acb --- /dev/null +++ b/Userland/Libraries/LibManual/CMakeLists.txt @@ -0,0 +1,7 @@ +set(SOURCES + PageNode.cpp + SectionNode.cpp +) + +serenity_lib(LibManual manual) +target_link_libraries(LibManual PRIVATE LibCore) diff --git a/Userland/Libraries/LibManual/Node.h b/Userland/Libraries/LibManual/Node.h new file mode 100644 index 0000000000..232a7c3094 --- /dev/null +++ b/Userland/Libraries/LibManual/Node.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/NonnullRefPtrVector.h> +#include <AK/RefCounted.h> +#include <AK/String.h> +#include <AK/StringView.h> + +namespace Manual { + +class PageNode; + +class Node : public RefCounted<Node> { +public: + virtual ~Node() = default; + + virtual NonnullRefPtrVector<Node>& children() const = 0; + virtual Node const* parent() const = 0; + virtual String name() const = 0; + virtual bool is_page() const { return false; } + virtual bool is_open() const { return false; } +}; + +} diff --git a/Userland/Libraries/LibManual/PageNode.cpp b/Userland/Libraries/LibManual/PageNode.cpp new file mode 100644 index 0000000000..0b44ee97c0 --- /dev/null +++ b/Userland/Libraries/LibManual/PageNode.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "PageNode.h" +#include "SectionNode.h" + +namespace Manual { + +Node const* PageNode::parent() const +{ + return m_section.ptr(); +} + +NonnullRefPtrVector<Node>& PageNode::children() const +{ + static NonnullRefPtrVector<Node> empty_vector; + return empty_vector; +} + +ErrorOr<String> PageNode::path() const +{ + return TRY(String::formatted("{}/{}.md", TRY(m_section->path()), m_page)); +} + +} diff --git a/Userland/Libraries/LibManual/PageNode.h b/Userland/Libraries/LibManual/PageNode.h new file mode 100644 index 0000000000..f74e78fb2f --- /dev/null +++ b/Userland/Libraries/LibManual/PageNode.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/NonnullRefPtr.h> +#include <LibManual/Node.h> + +namespace Manual { + +class SectionNode; + +class PageNode : public Node { +public: + virtual ~PageNode() override = default; + + PageNode(NonnullRefPtr<SectionNode> section, String page) + : m_section(move(section)) + , m_page(move(page)) + { + } + + virtual NonnullRefPtrVector<Node>& children() const override; + virtual Node const* parent() const override; + virtual String name() const override { return m_page; }; + virtual bool is_page() const override { return true; } + + ErrorOr<String> path() const; + +private: + NonnullRefPtr<SectionNode> m_section; + String m_page; +}; + +} diff --git a/Userland/Libraries/LibManual/SectionNode.cpp b/Userland/Libraries/LibManual/SectionNode.cpp new file mode 100644 index 0000000000..8ab6c89380 --- /dev/null +++ b/Userland/Libraries/LibManual/SectionNode.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "SectionNode.h" +#include "PageNode.h" +#include <AK/LexicalPath.h> +#include <AK/QuickSort.h> +#include <LibCore/DirIterator.h> + +namespace Manual { + +ErrorOr<String> SectionNode::path() const +{ + return String::formatted("/usr/share/man/man{}", m_section); +} + +ErrorOr<void> SectionNode::reify_if_needed() const +{ + if (m_reified) + return {}; + m_reified = true; + + Core::DirIterator dir_iter { TRY(path()).to_deprecated_string(), Core::DirIterator::Flags::SkipDots }; + + Vector<String> page_names; + while (dir_iter.has_next()) { + LexicalPath lexical_path(dir_iter.next_path()); + if (lexical_path.extension() != "md") + continue; + page_names.append(TRY(String::from_utf8(lexical_path.title()))); + } + + quick_sort(page_names); + + for (auto& page_name : page_names) + m_children.append(TRY(try_make_ref_counted<PageNode>(*this, move(page_name)))); + + return {}; +} + +void SectionNode::set_open(bool open) +{ + if (m_open == open) + return; + m_open = open; +} + +Array<NonnullRefPtr<SectionNode>, number_of_sections> const sections = { { + make_ref_counted<SectionNode>("1"sv, "User Programs"sv), + make_ref_counted<SectionNode>("2"sv, "System Calls"sv), + make_ref_counted<SectionNode>("3"sv, "Library Functions"sv), + make_ref_counted<SectionNode>("4"sv, "Special Files"sv), + make_ref_counted<SectionNode>("5"sv, "File Formats"sv), + make_ref_counted<SectionNode>("6"sv, "Games"sv), + make_ref_counted<SectionNode>("7"sv, "Miscellanea"sv), + make_ref_counted<SectionNode>("8"sv, "Sysadmin Tools"sv), +} }; + +} diff --git a/Userland/Libraries/LibManual/SectionNode.h b/Userland/Libraries/LibManual/SectionNode.h new file mode 100644 index 0000000000..cc7546f8e1 --- /dev/null +++ b/Userland/Libraries/LibManual/SectionNode.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Error.h> +#include <AK/String.h> +#include <LibManual/Node.h> + +namespace Manual { + +class SectionNode : public Node { +public: + virtual ~SectionNode() override = default; + + SectionNode(StringView section, StringView name) + : m_section(MUST(String::from_utf8(section))) + , m_full_name(MUST(String::formatted("{}. {}", section, name))) + { + } + + virtual NonnullRefPtrVector<Node>& children() const override + { + MUST(reify_if_needed()); + return m_children; + } + + virtual Node const* parent() const override { return nullptr; } + virtual String name() const override { return m_full_name; } + virtual bool is_open() const override { return m_open; } + void set_open(bool open); + + String const& section_name() const { return m_section; } + ErrorOr<String> path() const; + +private: + ErrorOr<void> reify_if_needed() const; + + String m_section; + String m_full_name; + mutable NonnullRefPtrVector<Node> m_children; + mutable bool m_reified { false }; + bool m_open { false }; +}; + +constexpr size_t number_of_sections = 8; + +extern Array<NonnullRefPtr<SectionNode>, number_of_sections> const sections; + +constexpr Array<StringView, number_of_sections> const section_numbers = { + "1"sv, + "2"sv, + "3"sv, + "4"sv, + "5"sv, + "6"sv, + "7"sv, + "8"sv, +}; + +} |