Document.cpp 2.5 KB

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