Document.cpp 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/ByteString.h>
  7. #include <AK/NonnullOwnPtr.h>
  8. #include <AK/NonnullRefPtr.h>
  9. #include <AK/StringBuilder.h>
  10. #include <AK/Vector.h>
  11. #include <LibGemini/Document.h>
  12. namespace Gemini {
  13. ByteString Document::render_to_html() const
  14. {
  15. StringBuilder html_builder;
  16. html_builder.append("<!DOCTYPE html>\n<html>\n"sv);
  17. html_builder.append("<head>\n<title>"sv);
  18. html_builder.append(m_url.serialize_path());
  19. html_builder.append("</title>\n</head>\n"sv);
  20. html_builder.append("<body>\n"sv);
  21. for (auto& line : m_lines) {
  22. html_builder.append(line->render_to_html());
  23. }
  24. html_builder.append("</body>"sv);
  25. html_builder.append("</html>"sv);
  26. return html_builder.to_byte_string();
  27. }
  28. NonnullRefPtr<Document> Document::parse(StringView lines, const URL& url)
  29. {
  30. auto document = adopt_ref(*new Document(url));
  31. document->read_lines(lines);
  32. return document;
  33. }
  34. void Document::read_lines(StringView source)
  35. {
  36. auto close_list_if_needed = [&] {
  37. if (m_inside_unordered_list) {
  38. m_inside_unordered_list = false;
  39. m_lines.append(make<Control>(Control::UnorderedListEnd));
  40. }
  41. };
  42. for (auto& line : source.lines()) {
  43. if (line.starts_with("```"sv)) {
  44. close_list_if_needed();
  45. m_inside_preformatted_block = !m_inside_preformatted_block;
  46. if (m_inside_preformatted_block) {
  47. m_lines.append(make<Control>(Control::PreformattedStart));
  48. } else {
  49. m_lines.append(make<Control>(Control::PreformattedEnd));
  50. }
  51. continue;
  52. }
  53. if (m_inside_preformatted_block) {
  54. m_lines.append(make<Preformatted>(move(line)));
  55. continue;
  56. }
  57. if (line.starts_with('*')) {
  58. if (!m_inside_unordered_list)
  59. m_lines.append(make<Control>(Control::UnorderedListStart));
  60. m_lines.append(make<UnorderedList>(move(line)));
  61. m_inside_unordered_list = true;
  62. continue;
  63. }
  64. close_list_if_needed();
  65. if (line.starts_with("=>"sv)) {
  66. m_lines.append(make<Link>(move(line), *this));
  67. continue;
  68. }
  69. if (line.starts_with('#')) {
  70. size_t level = 0;
  71. while (line.length() > level && line[level] == '#')
  72. ++level;
  73. m_lines.append(make<Heading>(move(line), level));
  74. continue;
  75. }
  76. m_lines.append(make<Text>(move(line)));
  77. }
  78. }
  79. }