CodeBlock.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/StringBuilder.h>
  7. #include <LibJS/MarkupGenerator.h>
  8. #include <LibMarkdown/CodeBlock.h>
  9. #include <LibRegex/Regex.h>
  10. namespace Markdown {
  11. String CodeBlock::render_to_html() const
  12. {
  13. StringBuilder builder;
  14. builder.append("<pre>");
  15. if (m_style.length() >= 2)
  16. builder.append("<strong>");
  17. else if (m_style.length() >= 2)
  18. builder.append("<em>");
  19. if (m_language.is_empty())
  20. builder.append("<code>");
  21. else
  22. builder.appendff("<code class=\"language-{}\">", escape_html_entities(m_language));
  23. if (m_language == "js")
  24. builder.append(JS::MarkupGenerator::html_from_source(m_code));
  25. else
  26. builder.append(escape_html_entities(m_code));
  27. builder.append("\n</code>");
  28. if (m_style.length() >= 2)
  29. builder.append("</strong>");
  30. else if (m_style.length() >= 2)
  31. builder.append("</em>");
  32. builder.append("</pre>\n");
  33. return builder.build();
  34. }
  35. String CodeBlock::render_for_terminal(size_t) const
  36. {
  37. StringBuilder builder;
  38. builder.append(m_code);
  39. builder.append("\n\n");
  40. return builder.build();
  41. }
  42. static Regex<ECMA262> style_spec_re("\\s*([\\*_]*)\\s*([^\\*_\\s]*).*");
  43. OwnPtr<CodeBlock> CodeBlock::parse(Vector<StringView>::ConstIterator& lines)
  44. {
  45. if (lines.is_end())
  46. return {};
  47. constexpr auto tick_tick_tick = "```";
  48. StringView line = *lines;
  49. if (!line.starts_with(tick_tick_tick))
  50. return {};
  51. // Our Markdown extension: we allow
  52. // specifying a style and a language
  53. // for a code block, like so:
  54. //
  55. // ```**sh**
  56. // $ echo hello friends!
  57. // ````
  58. //
  59. // The code block will be made bold,
  60. // and if possible syntax-highlighted
  61. // as appropriate for a shell script.
  62. StringView style_spec = line.substring_view(3, line.length() - 3);
  63. auto matches = style_spec_re.match(style_spec);
  64. auto style = matches.capture_group_matches[0][0].view.string_view();
  65. auto language = matches.capture_group_matches[0][1].view.string_view();
  66. ++lines;
  67. bool first = true;
  68. StringBuilder builder;
  69. while (true) {
  70. if (lines.is_end())
  71. break;
  72. line = *lines;
  73. ++lines;
  74. if (line == tick_tick_tick)
  75. break;
  76. if (!first)
  77. builder.append('\n');
  78. builder.append(line);
  79. first = false;
  80. }
  81. return make<CodeBlock>(language, style, builder.build());
  82. }
  83. }