From 7ce8b59596184d48db56c1b075ddc3546b1fdc7e Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Tue, 30 Jan 2024 17:12:21 -0500 Subject: [PATCH] it can talk! --- README.md | 14 +++++++-- ext/commonmarker/src/node.rs | 20 +++++++++++++ test/sourcepos_test.rb | 55 ++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ea875b22..1ee95ec3 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ require 'commonmarker' Commonmarker.to_html('"Hi *there*"', options: { parse: { smart: true } }) -#

“Hi there

\n +# =>

“Hi there

\n ``` (The second argument is optional--[see below](#options-and-plugins) for more information.) @@ -49,10 +49,10 @@ require 'commonmarker' doc = Commonmarker.parse("*Hello* world", options: { parse: { smart: true } }) -puts(doc.to_html) #

Hello world

\n +puts(doc.to_html) # =>

Hello world

\n doc.walk do |node| - puts node.type # [:document, :paragraph, :emph, :text, :text] + puts node.type # => [:document, :paragraph, :emph, :text, :text] end ``` @@ -66,6 +66,14 @@ When it comes to modifying the document, you can perform the following operation - `append_child` - `detach` +You can also get the source position of a node by calling `source_position`: + +```ruby +doc = Commonmarker.parse("*Hello* world") +puts doc.first_child.first_child.source_position +# => {:start_line=>1, :start_column=>1, :end_line=>1, :end_column=>7} +``` + You can also modify the following attributes: - `url` diff --git a/ext/commonmarker/src/node.rs b/ext/commonmarker/src/node.rs index 4801b663..476bf2ec 100644 --- a/ext/commonmarker/src/node.rs +++ b/ext/commonmarker/src/node.rs @@ -219,6 +219,21 @@ impl CommonmarkerNode { }) } + fn get_sourcepos(&self) -> Result { + let node = self.inner.borrow(); + + let result = RHash::new(); + result.aset(Symbol::new("start_line"), node.data.sourcepos.start.line)?; + result.aset( + Symbol::new("start_column"), + node.data.sourcepos.start.column, + )?; + result.aset(Symbol::new("end_line"), node.data.sourcepos.end.line)?; + result.aset(Symbol::new("end_column"), node.data.sourcepos.end.column)?; + + Ok(result) + } + fn insert_node_before(&self, new_sibling: &CommonmarkerNode) -> Result { let node = new_sibling.inner.clone(); node.detach(); @@ -546,6 +561,11 @@ pub fn init(m_commonmarker: RModule) -> Result<(), magnus::Error> { c_node.define_method("detach", method!(CommonmarkerNode::detach_node, 0))?; + c_node.define_method( + "source_position", + method!(CommonmarkerNode::get_sourcepos, 0), + )?; + c_node.define_method("url", method!(CommonmarkerNode::get_url, 0))?; c_node.define_method("url=", method!(CommonmarkerNode::set_url, 1))?; c_node.define_method("title", method!(CommonmarkerNode::get_title, 0))?; diff --git a/test/sourcepos_test.rb b/test/sourcepos_test.rb index 0f2049c3..d50278ce 100644 --- a/test/sourcepos_test.rb +++ b/test/sourcepos_test.rb @@ -20,4 +20,59 @@ def test_to_html assert_equal(expected, Commonmarker.to_html(md, options: { render: { sourcepos: true } })) end + + def test_can_generate_source_positions + md = <<~MARKDOWN + ## Try CommonMark + + You can try CommonMark here. This dingus is powered by + [commonmark.js](https://github.com/jgm/commonmark.js), the + JavaScript reference implementation. + + 1. item one + 2. item two + - sublist + - sublist + MARKDOWN + doc = Commonmarker.parse(md) + + source_positions = [] + + doc.walk do |node| + source_positions << node.source_position + end + + source_positions.delete_if { |h| h.values.all?(&:zero?) } + + assert_equal( + [ + { start_line: 1, start_column: 1, end_line: 10, end_column: 12 }, + { start_line: 1, start_column: 1, end_line: 1, end_column: 17 }, + { start_line: 1, start_column: 4, end_line: 1, end_column: 17 }, + { start_line: 3, start_column: 1, end_line: 5, end_column: 36 }, + { start_line: 3, start_column: 1, end_line: 3, end_column: 55 }, + { start_line: 3, start_column: 56, end_line: 3, end_column: 56 }, + { start_line: 4, start_column: 1, end_line: 4, end_column: 53 }, + { start_line: 4, start_column: 2, end_line: 4, end_column: 14 }, + { start_line: 4, start_column: 54, end_line: 4, end_column: 58 }, + { start_line: 4, start_column: 59, end_line: 4, end_column: 59 }, + { start_line: 5, start_column: 1, end_line: 5, end_column: 36 }, + { start_line: 7, start_column: 1, end_line: 10, end_column: 12 }, + { start_line: 7, start_column: 1, end_line: 7, end_column: 11 }, + { start_line: 7, start_column: 4, end_line: 7, end_column: 11 }, + { start_line: 7, start_column: 4, end_line: 7, end_column: 11 }, + { start_line: 8, start_column: 1, end_line: 10, end_column: 12 }, + { start_line: 8, start_column: 4, end_line: 8, end_column: 11 }, + { start_line: 8, start_column: 4, end_line: 8, end_column: 11 }, + { start_line: 9, start_column: 4, end_line: 10, end_column: 12 }, + { start_line: 9, start_column: 4, end_line: 9, end_column: 12 }, + { start_line: 9, start_column: 6, end_line: 9, end_column: 12 }, + { start_line: 9, start_column: 6, end_line: 9, end_column: 12 }, + { start_line: 10, start_column: 4, end_line: 10, end_column: 12 }, + { start_line: 10, start_column: 6, end_line: 10, end_column: 12 }, + { start_line: 10, start_column: 6, end_line: 10, end_column: 12 }, + ], + source_positions, + ) + end end