Serenity Operating System
at master 100 lines 4.0 kB view raw
1/* 2 * Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include "Node.h" 8#include "PageNode.h" 9#include "SectionNode.h" 10#include <AK/Assertions.h> 11#include <AK/LexicalPath.h> 12#include <AK/Optional.h> 13#include <AK/StringView.h> 14#include <AK/URL.h> 15#include <LibCore/DeprecatedFile.h> 16#include <LibManual/Path.h> 17 18namespace Manual { 19 20ErrorOr<NonnullRefPtr<PageNode const>> Node::try_create_from_query(Vector<StringView, 2> const& query_parameters) 21{ 22 if (query_parameters.size() > 2) 23 return Error::from_string_literal("Queries longer than 2 strings are not supported yet"); 24 25 auto query_parameter_iterator = query_parameters.begin(); 26 27 if (query_parameter_iterator.is_end()) 28 return PageNode::help_index_page(); 29 30 auto first_query_parameter = *query_parameter_iterator; 31 ++query_parameter_iterator; 32 if (query_parameter_iterator.is_end()) { 33 // [/path/to/docs.md] 34 auto path_from_query = LexicalPath { first_query_parameter }; 35 if (path_from_query.is_absolute() 36 && path_from_query.is_child_of(manual_base_path) 37 && path_from_query.extension() == "md"sv) { 38 auto section_directory = path_from_query.parent(); 39 auto man_string_location = section_directory.basename().find("man"sv); 40 if (!man_string_location.has_value()) 41 return Error::from_string_literal("Page is inside invalid section"); 42 auto section_name = section_directory.basename().substring_view(man_string_location.value() + 3); 43 auto section = TRY(SectionNode::try_create_from_number(section_name)); 44 return try_make_ref_counted<PageNode>(section, TRY(String::from_utf8(path_from_query.title()))); 45 } 46 47 // [page] (in any section) 48 Optional<NonnullRefPtr<PageNode>> maybe_page; 49 for (auto const& section : sections) { 50 auto const page = TRY(try_make_ref_counted<PageNode>(section, TRY(String::from_utf8(first_query_parameter)))); 51 if (Core::DeprecatedFile::exists(TRY(page->path()))) { 52 maybe_page = page; 53 break; 54 } 55 } 56 if (maybe_page.has_value()) 57 return maybe_page.release_value(); 58 return Error::from_string_literal("Page not found"); 59 } 60 // [section] [name] 61 auto second_query_parameter = *query_parameter_iterator; 62 auto section = TRY(SectionNode::try_create_from_number(first_query_parameter)); 63 auto const page = TRY(try_make_ref_counted<PageNode>(section, TRY(String::from_utf8(second_query_parameter)))); 64 if (Core::DeprecatedFile::exists(TRY(page->path()))) 65 return page; 66 return Error::from_string_literal("Page doesn't exist in section"); 67} 68 69ErrorOr<NonnullRefPtr<Node const>> Node::try_find_from_help_url(URL const& url) 70{ 71 if (url.host() != "man") 72 return Error::from_string_view("Bad help operation"sv); 73 if (url.paths().size() < 2) 74 return Error::from_string_view("Bad help page URL"sv); 75 76 auto paths = url.paths(); 77 auto const section = paths.take_first(); 78 auto maybe_section_number = section.to_uint(); 79 if (!maybe_section_number.has_value()) 80 return Error::from_string_view("Bad section number"sv); 81 auto section_number = maybe_section_number.value(); 82 if (section_number > number_of_sections) 83 return Error::from_string_view("Section number out of bounds"sv); 84 85 NonnullRefPtr<Node const> current_node = sections[section_number - 1]; 86 87 while (!paths.is_empty()) { 88 auto next_path_segment = TRY(String::from_deprecated_string(paths.take_first())); 89 auto children = TRY(current_node->children()); 90 for (auto const& child : children) { 91 if (TRY(child->name()) == next_path_segment) { 92 current_node = child; 93 break; 94 } 95 } 96 } 97 return current_node; 98} 99 100}