diff --git a/Gemfile b/Gemfile
index 1699e8a74..d4349c7cd 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,4 +1,5 @@
source "https://rubygems.org"
+git_source(:bc) { |repo| "https://github.com/basecamp/#{repo}" }
ruby file: ".ruby-version"
gem "rails", github: "rails/rails", branch: "main"
@@ -9,6 +10,7 @@ gem "propshaft"
gem "stimulus-rails"
gem "turbo-rails"
gem "hotwire_combobox", github: "josefarias/hotwire_combobox", branch: :main
+gem "house_md", bc: "house", branch: :renderer
# Deployment and drivers
gem "bootsnap", require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 4b63b69ab..1c26d38e1 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,3 +1,12 @@
+GIT
+ remote: https://github.com/basecamp/house
+ revision: a8b19e70bbb95a7a0d27e38985a99c2d697a6650
+ branch: renderer
+ specs:
+ house_md (1.0.0)
+ rails
+ zeitwerk
+
GIT
remote: https://github.com/josefarias/hotwire_combobox.git
revision: 57ee6c9087320fab9383a07fa919fe75e0ea72ba
@@ -346,6 +355,7 @@ DEPENDENCIES
capybara
debug
hotwire_combobox!
+ house_md!
importmap-rails
jbuilder
propshaft
diff --git a/config/initializers/markdown.rb b/config/initializers/markdown.rb
index 57e7c4384..2d3a879a3 100644
--- a/config/initializers/markdown.rb
+++ b/config/initializers/markdown.rb
@@ -1,4 +1,4 @@
ActiveSupport.on_load :action_text_markdown do
require "markdown_renderer"
- ActionText::Markdown.renderer = -> { MarkdownRenderer.new }
+ ActionText::Markdown.html_renderer = -> { MarkdownRenderer.new }
end
diff --git a/lib/markdown_renderer.rb b/lib/markdown_renderer.rb
index 1205e6d6d..9117b28d0 100644
--- a/lib/markdown_renderer.rb
+++ b/lib/markdown_renderer.rb
@@ -1,40 +1,47 @@
-class MarkdownRenderer
- require_relative "markdown_renderer/parsing"
- require_relative "markdown_renderer/markup"
+require "rouge/plugins/redcarpet"
- include Parsing, Markup
+class MarkdownRenderer < HouseMd::Renderer
+ class Generator < HouseMd::Generator::Html
+ include Rouge::Plugins::Redcarpet
- def initialize
- @id_counts = Hash.new(0)
- end
+ def initialize
+ @id_counts = Hash.new 0
+ end
- def render(content)
- content
- .then { |c| parse_paragraphs(c) }
- .then { |c| parse_bold_italics(c) }
- .then { |c| parse_bold(c) }
- .then { |c| parse_italics(c) }
- .then { |c| parse_strikethrough(c) }
- .then { |c| parse_highlight(c) }
- .then { |c| parse_headers(c) }
- .then { |c| parse_tables(c) }
- .then { |c| parse_ordered_lists(c) }
- .then { |c| parse_unordered_lists(c) }
- .then { |c| parse_block_quotes(c) }
- .then { |c| parse_horizontal_rules(c) }
- .then { |c| parse_images(c) }
- .then { |c| parse_links(c) }
- .then { |c| parse_code_blocks(c) }
- .then { |c| parse_code_spans(c) }
- end
-
- private
- attr_reader :id_counts
-
- def unique_id(text)
- text.parameterize.then do |base_id|
- id_counts[base_id] += 1
- id_counts[base_id] > 1 ? "#{base_id}-#{id_counts[base_id]}" : base_id
+ def header(text, header_level)
+ unique_id(text).then do |id|
+ <<~HTML.chomp
+
+
+ HTML
+ end
+
+ def code_block(code, language)
+ block_code(code, language) # call Rouge Redcarpet plugin
+ end
+
+ private
+ attr_reader :id_counts
+
+ def unique_id(text)
+ text.parameterize.then do |base_id|
+ id_counts[base_id] += 1
+ id_counts[base_id] > 1 ? "#{base_id}-#{id_counts[base_id]}" : base_id
+ end
+ end
+ end
+
+ def initialize
+ @generator = Generator.new
+ end
end
diff --git a/lib/markdown_renderer/markup.rb b/lib/markdown_renderer/markup.rb
deleted file mode 100644
index 2e2753c5e..000000000
--- a/lib/markdown_renderer/markup.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-require "rouge/plugins/redcarpet"
-
-module MarkdownRenderer::Markup
- include Rouge::Plugins::Redcarpet
-
- TABLE_ROW_INDENT = " " * 4
- LIST_ITEM_INDENT = " " * 2
- BLOCK_QUOTE_INDENT = " " * 2
- TABLE_HEADER_INDENT = " " * 6
-
- # FIXME: the attributes suggest this should be an app-level override instead
- def header(text, header_level)
- unique_id(text).then do |id|
- <<~HTML.chomp
-
#{text}"
- end
-
- def highlight(text)
- "#{text}"
- end
-
- def table(headers, rows)
- <<~HTML
-
| #{header} | " }.join("\n" + TABLE_HEADER_INDENT)} -
|---|
| #{cell} | " }.join}
- #{text.gsub(/^>\s?/, '').split("\n").join("\n" + BLOCK_QUOTE_INDENT)} -- HTML - end - - def horizontal_rule - "
#{text}"
- end
-
- # FIXME: the attributes suggest this should be an app-level override instead
- def image(url, alt_text)
- <<~HTML.chomp
-
- #{text}
" - end - - def soft_line_break - "\n#{line_break}\n" - end - - def line_break - "This is an introduction paragraph with some text.
- -Hello, world! Hello, world! Hello, world! Hello, world! Hello, world!
Hello, world!
-
- Hello, world!
-
- Hello, world!
-
- Hello, world!
-
- Hello, world!
Here’s what you need to know:
- -Our product offers:
- -Here’s some
-
- multiline text.
-
- It has line breaks
-
- in-between.
- Please read this carefully - It contains vital information - That you shouldn’t miss -- - - -
| Table 1 Header 1 | -Table 1 Header 2 | -
|---|---|
| Table 1 Data 1 | Table 1 Data 2 |
| Table 1 Data 3 | Table 1 Data 4 |
Some content between tables...
- -| Table 2 Header 1 | -Table 2 Header 2 | -
|---|---|
| Table 2 Data 1 | Table 2 Data 2 |
| Table 2 Data 3 | Table 2 Data 4 |
class Post < ApplicationRecord
- def title
- "foo"
- end
- end
- puts "Hello, world!"
Thanks for reading!
- -