From 866c2f777dfbbd6a303a02a7255822d3a2bb9584 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Thu, 3 Aug 2023 08:55:21 +0100 Subject: [PATCH] Switch to Markly for HTML rendering Unfortunately Markly does not include header generation, so for now I've implemented this with a custom renderer. --- CHANGELOG.md | 2 + Gemfile.lock | 6 --- lib/obsidian/parser.rb | 4 +- lib/obsidian/parser/html_renderer.rb | 40 +++++++++++++++++++ lib/obsidian/parser/markdown_content.rb | 5 ++- .../parser/obsidian_flavored_markdown.rb | 9 ++--- .../parser/parsed_markdown_document.rb | 9 +++-- obsidian-parser.gemspec | 2 - .../parser/parsed_markdown_document_spec.rb | 4 +- spec/obsidian/parser_spec.rb | 2 +- 10 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 lib/obsidian/parser/html_renderer.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index cf01e89..48f250a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ## [Unreleased] +- Replace Kramdown with Markly +- Enabled support for Github Flavored Markdown tables and tasklists ## [0.5.4] - 2023-08-02 - Fix page getting clobbered when wikilinks point to non-existent pages. diff --git a/Gemfile.lock b/Gemfile.lock index ca8437e..971fe1c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,8 +2,6 @@ PATH remote: . specs: obsidian-parser (0.5.4) - kramdown (~> 2.4) - kramdown-parser-gfm (~> 1.1) markly (~> 0.7.0) GEM @@ -13,10 +11,6 @@ GEM coderay (1.1.3) diff-lcs (1.5.0) json (2.6.3) - kramdown (2.4.0) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) language_server-protocol (3.17.0.3) lint_roller (1.1.0) markly (0.7.0) diff --git a/lib/obsidian/parser.rb b/lib/obsidian/parser.rb index 863cd50..d8d2def 100644 --- a/lib/obsidian/parser.rb +++ b/lib/obsidian/parser.rb @@ -5,6 +5,7 @@ require_relative "parser/obsidian_flavored_markdown" require_relative "parser/page" require_relative "parser/markdown_content" +require_relative "parser/html_renderer" require "forwardable" @@ -20,6 +21,7 @@ class Parser def initialize(vault_directory) @index = Obsidian::Page.create_root + renderer = HtmlRenderer.new vault_directory.glob("**/*.md").each do |path| dirname, basename = path.relative_path_from(vault_directory).split @@ -39,7 +41,7 @@ def initialize(vault_directory) @index.add_page( slug, last_modified: path.mtime, - content: MarkdownContent.new(path, @index) + content: MarkdownContent.new(path, @index, renderer: renderer) ) end diff --git a/lib/obsidian/parser/html_renderer.rb b/lib/obsidian/parser/html_renderer.rb new file mode 100644 index 0000000..d33e7e0 --- /dev/null +++ b/lib/obsidian/parser/html_renderer.rb @@ -0,0 +1,40 @@ +class HtmlRenderer < Markly::Renderer::HTML + def header(node) + block do + out("", + :children, "") + end + end + + private + + def header_id(node) + # Taken from Kramdown + # https://github.com/gettalong/kramdown/blob/bd678ecb59f70778fdb3b08bdcd39e2ab7379b45/lib/kramdown/converter/base.rb + gen_id = extract_text(node).gsub(/^[^a-zA-Z]+/, "") + gen_id.tr!("^a-zA-Z0-9 -", "") + gen_id.tr!(" ", "-") + gen_id.downcase! + + gen_id = "section" if gen_id.empty? + + @used_ids ||= {} + if @used_ids.key?(gen_id) + gen_id += "-#{@used_ids[gen_id] += 1}" + else + @used_ids[gen_id] = 0 + end + + gen_id + end + + def extract_text(node) + node.each do |subnode| + if subnode.type == :text + return subnode.string_content + end + end + + "" + end +end diff --git a/lib/obsidian/parser/markdown_content.rb b/lib/obsidian/parser/markdown_content.rb index 3985685..941ac1e 100644 --- a/lib/obsidian/parser/markdown_content.rb +++ b/lib/obsidian/parser/markdown_content.rb @@ -2,14 +2,15 @@ module Obsidian class MarkdownContent - def initialize(path, root) + def initialize(path, root, renderer:) @path = path @root = root + @renderer = renderer end def generate_html markdown = @path.read - Obsidian::ObsidianFlavoredMarkdown.parse(markdown, root: @root).to_html + Obsidian::ObsidianFlavoredMarkdown.parse(markdown, root: @root, renderer: @renderer).to_html end end end diff --git a/lib/obsidian/parser/obsidian_flavored_markdown.rb b/lib/obsidian/parser/obsidian_flavored_markdown.rb index 403f43a..3e9135a 100644 --- a/lib/obsidian/parser/obsidian_flavored_markdown.rb +++ b/lib/obsidian/parser/obsidian_flavored_markdown.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "kramdown" -require "kramdown-parser-gfm" require "markly" module Obsidian @@ -38,11 +36,10 @@ def self.expand_wikilinks(markdown_text, root:) end end - def self.parse(markdown_text, root: nil) + def self.parse(markdown_text, renderer:, root: nil) normalized = expand_wikilinks(markdown_text, root: root) - document = Kramdown::Document.new(normalized, input: "GFM") - document2 = Markly.parse(normalized, flags: Markly::SMART | Markly::UNSAFE | Markly::HARD_BREAKS, extensions: [:table, :tasklist, :autolink]) - Obsidian::ParsedMarkdownDocument.new(document, document2) + document = Markly.parse(normalized, flags: Markly::SMART | Markly::UNSAFE | Markly::HARD_BREAKS, extensions: [:table, :tasklist, :autolink]) + Obsidian::ParsedMarkdownDocument.new(document, renderer: renderer) end end end diff --git a/lib/obsidian/parser/parsed_markdown_document.rb b/lib/obsidian/parser/parsed_markdown_document.rb index a306b90..39a809d 100644 --- a/lib/obsidian/parser/parsed_markdown_document.rb +++ b/lib/obsidian/parser/parsed_markdown_document.rb @@ -2,9 +2,9 @@ module Obsidian class ParsedMarkdownDocument - def initialize(document, document2) - @document2 = document - @document = document2 + def initialize(document, renderer:) + @document = document + @renderer = renderer end def extract_links @@ -22,12 +22,13 @@ def extract_links end def to_html - @document2.to_html + renderer.render(document) end private attr_reader :document + attr_reader :renderer def _extract_text_content(element) if element.type == :text diff --git a/obsidian-parser.gemspec b/obsidian-parser.gemspec index f55bedc..06872f8 100644 --- a/obsidian-parser.gemspec +++ b/obsidian-parser.gemspec @@ -30,8 +30,6 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.add_dependency "kramdown", "~> 2.4" - spec.add_dependency "kramdown-parser-gfm", "~> 1.1" spec.add_dependency "markly", "~> 0.7.0" # For more information and examples about making a new gem, check out our diff --git a/spec/obsidian/parser/parsed_markdown_document_spec.rb b/spec/obsidian/parser/parsed_markdown_document_spec.rb index feef8d7..75f7f14 100644 --- a/spec/obsidian/parser/parsed_markdown_document_spec.rb +++ b/spec/obsidian/parser/parsed_markdown_document_spec.rb @@ -4,7 +4,7 @@ let(:index) { nil } def create_instance(markdown) - Obsidian::ObsidianFlavoredMarkdown.parse(markdown, root: index) + Obsidian::ObsidianFlavoredMarkdown.parse(markdown, root: index, renderer: HtmlRenderer.new) end it "extracts [foo](bar) links" do @@ -38,7 +38,7 @@ def create_instance(markdown) [bar]: /url "title" END - parsed_document = Obsidian::ObsidianFlavoredMarkdown.parse(markdown) + parsed_document = Obsidian::ObsidianFlavoredMarkdown.parse(markdown, renderer: HtmlRenderer.new) links = parsed_document.extract_links diff --git a/spec/obsidian/parser_spec.rb b/spec/obsidian/parser_spec.rb index 528ef6e..928b5b0 100644 --- a/spec/obsidian/parser_spec.rb +++ b/spec/obsidian/parser_spec.rb @@ -39,7 +39,7 @@ end it "converts markdown into HTML content" do - expect(parser.pages.find { |note| note.title == "cat" }.content.generate_html).to eq("

Cats are the best

\n\n

Meow meow meow

\n") + expect(parser.pages.find { |note| note.title == "cat" }.content.generate_html).to eq("

Cats are the best

\n

Meow meow meow

\n") end it "adds index.md content to index pages" do