diff --git a/app/services/messages/markdown_renderer_service.rb b/app/services/messages/markdown_renderer_service.rb index 9348b2bc7..8984374d1 100644 --- a/app/services/messages/markdown_renderer_service.rb +++ b/app/services/messages/markdown_renderer_service.rb @@ -53,22 +53,49 @@ class Messages::MarkdownRendererService end def render_whatsapp + content_with_preserved_newlines = preserve_multiple_newlines(@content) renderer = Messages::MarkdownRenderers::WhatsAppRenderer.new - renderer.render(commonmarker_doc).gsub(/\n+\z/, '') + doc = CommonMarker.render_doc(content_with_preserved_newlines, [:DEFAULT, :STRIKETHROUGH_DOUBLE_TILDE]) + result = renderer.render(doc).gsub(/\n+\z/, '') + restore_multiple_newlines(result) end def render_instagram + content_with_preserved_newlines = preserve_multiple_newlines(@content) renderer = Messages::MarkdownRenderers::InstagramRenderer.new - renderer.render(commonmarker_doc).gsub(/\n+\z/, '') + doc = CommonMarker.render_doc(content_with_preserved_newlines, [:DEFAULT, :STRIKETHROUGH_DOUBLE_TILDE]) + result = renderer.render(doc).gsub(/\n+\z/, '') + restore_multiple_newlines(result) end def render_line + content_with_preserved_newlines = preserve_multiple_newlines(@content) renderer = Messages::MarkdownRenderers::LineRenderer.new - renderer.render(commonmarker_doc).gsub(/\n+\z/, '') + doc = CommonMarker.render_doc(content_with_preserved_newlines, [:DEFAULT, :STRIKETHROUGH_DOUBLE_TILDE]) + result = renderer.render(doc).gsub(/\n+\z/, '') + restore_multiple_newlines(result) end def render_plain_text + content_with_preserved_newlines = preserve_multiple_newlines(@content) renderer = Messages::MarkdownRenderers::PlainTextRenderer.new - renderer.render(commonmarker_doc).gsub(/\n+\z/, '') + doc = CommonMarker.render_doc(content_with_preserved_newlines, [:DEFAULT, :STRIKETHROUGH_DOUBLE_TILDE]) + result = renderer.render(doc).gsub(/\n+\z/, '') + restore_multiple_newlines(result) + end + + # Preserve multiple consecutive newlines (3+) by replacing them with placeholders + # Standard markdown treats 2 newlines as paragraph break, we preserve 3+ + def preserve_multiple_newlines(content) + content.gsub(/\n{3,}/) do |match| + "{{PRESERVE_#{match.length}_NEWLINES}}" + end + end + + # Restore multiple newlines from placeholders + def restore_multiple_newlines(content) + content.gsub(/\{\{PRESERVE_(\d+)_NEWLINES\}\}/) do |_match| + "\n" * Regexp.last_match(1).to_i + end end end diff --git a/spec/services/messages/markdown_renderer_service_spec.rb b/spec/services/messages/markdown_renderer_service_spec.rb index 26c661495..d589c6ad1 100644 --- a/spec/services/messages/markdown_renderer_service_spec.rb +++ b/spec/services/messages/markdown_renderer_service_spec.rb @@ -67,6 +67,13 @@ RSpec.describe Messages::MarkdownRendererService, type: :service do expect(result).to include("Line 1\nLine 2\nLine 3") expect(result).not_to include('Line 1 Line 2') end + + it 'preserves multiple consecutive newlines for spacing' do + content = "Para 1\n\n\n\nPara 2" + result = described_class.new(content, channel_type).render + expect(result.scan("\n").count).to eq(4) + expect(result).to include("Para 1\n\n\n\nPara 2") + end end context 'when channel is Channel::Instagram' do @@ -116,6 +123,13 @@ RSpec.describe Messages::MarkdownRendererService, type: :service do expect(result).to include("Line 1\nLine 2\nLine 3") expect(result).not_to include('Line 1 Line 2') end + + it 'preserves multiple consecutive newlines for spacing' do + content = "Para 1\n\n\n\nPara 2" + result = described_class.new(content, channel_type).render + expect(result.scan("\n").count).to eq(4) + expect(result).to include("Para 1\n\n\n\nPara 2") + end end context 'when channel is Channel::Line' do @@ -201,6 +215,13 @@ RSpec.describe Messages::MarkdownRendererService, type: :service do expect(result).to include("Line 1\nLine 2\nLine 3") expect(result).not_to include('Line 1 Line 2') end + + it 'preserves multiple consecutive newlines for spacing' do + content = "Para 1\n\n\n\nPara 2" + result = described_class.new(content, channel_type).render + expect(result.scan("\n").count).to eq(4) + expect(result).to include("Para 1\n\n\n\nPara 2") + end end context 'when channel is Channel::Telegram' do