SectionNode.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "SectionNode.h"
  7. #include "PageNode.h"
  8. #include "Path.h"
  9. #include "SubsectionNode.h"
  10. #include <AK/HashTable.h>
  11. #include <AK/LexicalPath.h>
  12. #include <AK/QuickSort.h>
  13. #include <LibCore/DirIterator.h>
  14. #include <LibFileSystem/FileSystem.h>
  15. namespace Manual {
  16. ErrorOr<NonnullRefPtr<SectionNode>> SectionNode::try_create_from_number(StringView section)
  17. {
  18. auto maybe_section_number = section.to_number<u32>();
  19. if (!maybe_section_number.has_value())
  20. return Error::from_string_literal("Section is not a number");
  21. auto section_number = maybe_section_number.release_value();
  22. if (section_number < 1 || section_number > number_of_sections)
  23. return Error::from_string_literal("Section number is not valid");
  24. return sections[section_number - 1];
  25. }
  26. ErrorOr<String> SectionNode::path() const
  27. {
  28. return String::formatted("{}/{}{}", manual_base_path, top_level_section_prefix, m_section);
  29. }
  30. ErrorOr<String> SectionNode::name() const
  31. {
  32. return String::formatted("{}. {}", m_section, m_name);
  33. }
  34. ErrorOr<void> SectionNode::reify_if_needed() const
  35. {
  36. if (m_reified)
  37. return {};
  38. m_reified = true;
  39. auto own_path = TRY(path());
  40. Core::DirIterator dir_iterator { own_path.to_byte_string(), Core::DirIterator::Flags::SkipDots };
  41. Vector<ByteString> directories;
  42. HashTable<ByteString> files;
  43. while (dir_iterator.has_next()) {
  44. auto entry = dir_iterator.next();
  45. if (entry->type == Core::DirectoryEntry::Type::Directory)
  46. TRY(directories.try_append(entry->name));
  47. else if (entry->type == Core::DirectoryEntry::Type::File && entry->name.ends_with(".md"sv, CaseSensitivity::CaseInsensitive))
  48. TRY(files.try_set(entry->name));
  49. }
  50. struct Child {
  51. NonnullRefPtr<Node const> node;
  52. String name_for_sorting;
  53. };
  54. Vector<Child> children;
  55. for (auto const& directory : directories) {
  56. LexicalPath lexical_path(directory);
  57. RefPtr<PageNode> associated_page;
  58. auto matching_page_name = ByteString::formatted("{}.md", directory);
  59. if (files.remove(matching_page_name))
  60. associated_page = TRY(try_make_ref_counted<PageNode>(*this, TRY(String::from_utf8(lexical_path.title()))));
  61. TRY(children.try_append({ .node = TRY(try_make_ref_counted<SubsectionNode>(*this, lexical_path.title(), associated_page)),
  62. .name_for_sorting = TRY(String::from_utf8(lexical_path.title())) }));
  63. }
  64. for (auto const& file : files) {
  65. LexicalPath lexical_path(file);
  66. children.append({ .node = TRY(try_make_ref_counted<PageNode>(*this, TRY(String::from_utf8(lexical_path.title())))),
  67. .name_for_sorting = TRY(String::from_utf8(lexical_path.title())) });
  68. }
  69. quick_sort(children, [](auto const& a, auto const& b) { return a.name_for_sorting < b.name_for_sorting; });
  70. m_children.ensure_capacity(children.size());
  71. for (auto child : children)
  72. m_children.unchecked_append(move(child.node));
  73. return {};
  74. }
  75. void SectionNode::set_open(bool open)
  76. {
  77. if (m_open == open)
  78. return;
  79. m_open = open;
  80. }
  81. Array<NonnullRefPtr<SectionNode>, number_of_sections> const sections = { {
  82. make_ref_counted<SectionNode>("1"sv, "User Programs"sv),
  83. make_ref_counted<SectionNode>("2"sv, "System Calls"sv),
  84. make_ref_counted<SectionNode>("3"sv, "Library Functions"sv),
  85. make_ref_counted<SectionNode>("4"sv, "Special Files"sv),
  86. make_ref_counted<SectionNode>("5"sv, "File Formats"sv),
  87. make_ref_counted<SectionNode>("6"sv, "Games"sv),
  88. make_ref_counted<SectionNode>("7"sv, "Miscellanea"sv),
  89. make_ref_counted<SectionNode>("8"sv, "Sysadmin Tools"sv),
  90. } };
  91. }