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