/src/serenity/Userland/Libraries/LibMarkdown/Heading.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/Slugify.h> |
8 | | #include <AK/StringBuilder.h> |
9 | | #include <LibMarkdown/Heading.h> |
10 | | #include <LibMarkdown/Visitor.h> |
11 | | #include <LibUnicode/Normalize.h> |
12 | | |
13 | | namespace Markdown { |
14 | | |
15 | | ByteString Heading::render_to_html(bool) const |
16 | 0 | { |
17 | 0 | auto input = Unicode::normalize(m_text.render_for_raw_print(), Unicode::NormalizationForm::NFD); |
18 | 0 | auto slugified = MUST(AK::slugify(input)); |
19 | 0 | return ByteString::formatted("<h{} id='{}'><a href='#{}'>#</a> {}</h{}>\n", m_level, slugified, slugified, m_text.render_to_html(), m_level); |
20 | 0 | } |
21 | | |
22 | | Vector<ByteString> Heading::render_lines_for_terminal(size_t) const |
23 | 0 | { |
24 | 0 | StringBuilder builder; |
25 | |
|
26 | 0 | builder.append("\n\033[0;31;1m"sv); |
27 | 0 | switch (m_level) { |
28 | 0 | case 1: |
29 | 0 | case 2: |
30 | 0 | builder.append(m_text.render_for_terminal().to_uppercase()); |
31 | 0 | builder.append("\033[0m"sv); |
32 | 0 | break; |
33 | 0 | default: |
34 | 0 | builder.append(m_text.render_for_terminal()); |
35 | 0 | builder.append("\033[0m"sv); |
36 | 0 | break; |
37 | 0 | } |
38 | | |
39 | 0 | return Vector<ByteString> { builder.to_byte_string() }; |
40 | 0 | } |
41 | | |
42 | | RecursionDecision Heading::walk(Visitor& visitor) const |
43 | 0 | { |
44 | 0 | RecursionDecision rd = visitor.visit(*this); |
45 | 0 | if (rd != RecursionDecision::Recurse) |
46 | 0 | return rd; |
47 | | |
48 | 0 | return m_text.walk(visitor); |
49 | 0 | } |
50 | | |
51 | | OwnPtr<Heading> Heading::parse(LineIterator& lines) |
52 | 19.5M | { |
53 | 19.5M | if (lines.is_end()) |
54 | 0 | return {}; |
55 | | |
56 | 19.5M | StringView line = *lines; |
57 | 19.5M | size_t indent = 0; |
58 | | |
59 | | // Allow for up to 3 spaces of indentation. |
60 | | // https://spec.commonmark.org/0.30/#example-68 |
61 | 19.6M | for (size_t i = 0; i < 3; ++i) { |
62 | 19.6M | if (line[i] != ' ') |
63 | 19.5M | break; |
64 | | |
65 | 88.1k | ++indent; |
66 | 88.1k | } |
67 | | |
68 | 19.5M | size_t level; |
69 | | |
70 | 21.1M | for (level = 0; indent + level < line.length(); level++) { |
71 | 20.0M | if (line[indent + level] != '#') |
72 | 18.4M | break; |
73 | 20.0M | } |
74 | | |
75 | 19.5M | if (!level || indent + level >= line.length() || line[indent + level] != ' ' || level > 6) |
76 | 19.2M | return {}; |
77 | | |
78 | 322k | StringView title_view = line.substring_view(indent + level + 1); |
79 | 322k | auto text = Text::parse(title_view); |
80 | 322k | auto heading = make<Heading>(move(text), level); |
81 | | |
82 | 322k | ++lines; |
83 | 322k | return heading; |
84 | 19.5M | } |
85 | | |
86 | | } |