diff --git a/lib/org-ruby/html_output_buffer.rb b/lib/org-ruby/html_output_buffer.rb index 5e5d595..dfb9131 100644 --- a/lib/org-ruby/html_output_buffer.rb +++ b/lib/org-ruby/html_output_buffer.rb @@ -342,6 +342,7 @@ def inline_formatting(str) quote_tags("") end end + rewrite_targets(str) if @options[:use_sub_superscripts] @re_help.rewrite_subp str do |type, text| @@ -353,28 +354,7 @@ def inline_formatting(str) end end - @re_help.rewrite_links str do |link, defi| - [link, defi].compact.each do |text| - # We don't support search links right now. Get rid of it. - text.sub!(/\A(file:[^\s]+)::[^\s]*?\Z/, "\\1") - text.sub!(/\Afile(|\+emacs|\+sys):(?=[^\s]+\Z)/, "") - end - - # We don't add a description for images in links, because its - # empty value forces the image to be inlined. - defi ||= link unless link =~ @re_help.org_image_file_regexp - - if defi =~ @re_help.org_image_file_regexp - defi = quote_tags "\"#{defi}\"" - end - - if defi - link = @options[:link_abbrevs][link] if @options[:link_abbrevs].has_key? link - quote_tags("") + defi + quote_tags("") - else - quote_tags "\"#{link}\"" - end - end + rewrite_links(str) if @output_type == :table_row str.gsub!(/^\|\s*/, quote_tags("")) @@ -395,18 +375,7 @@ def inline_formatting(str) end # Reference footnote - @re_help.rewrite_footnote str do |label, content| - footnote = document.footnotes.find do |footnote| - footnote[:label] == label || footnote[:content] == content - end - - a_id = (footnote[:label].nil? || footnote[:label].empty?) ? footnote[:index] : footnote[:label] - a_text = footnote[:index] - a_href = (footnote[:label].nil? || footnote[:label].empty?) ? footnote[:index] : footnote[:label] - - footnote_tag = "#{a_text}" - quote_tags(footnote_tag) - end + rewrite_footnote(str) end # Two backslashes \\ at the end of the line make a line break without breaking paragraph. @@ -419,6 +388,62 @@ def inline_formatting(str) str = @re_help.restore_code_snippets str end + def rewrite_footnote(str) + @re_help.rewrite_footnote(str) do |label, content| + footnote = document.footnotes.find do |footnote| + footnote[:label] == label || footnote[:content] == content + end + + a_id = (footnote[:label].nil? || footnote[:label].empty?) ? footnote[:index] : footnote[:label] + a_text = footnote[:index] + a_href = (footnote[:label].nil? || footnote[:label].empty?) ? footnote[:index] : footnote[:label] + + footnote_tag = "#{a_text}" + quote_tags(footnote_tag) + end + end + + def rewrite_links(str) + @re_help.rewrite_links(str) do |link, defi| + [link, defi].compact.each do |text| + text.sub!(/\A(file:[^\s]+)::[^\s]*?\Z/, "\\1") + # We don't support search links right now. Get rid of it. + text.sub!(/\Afile(|\+emacs|\+sys):(?=[^\s]+\Z)/, "") + end + + # We don't add a description for images in links, because its + # empty value forces the image to be inlined. + defi ||= link unless link =~ @re_help.org_image_file_regexp + + if defi =~ @re_help.org_image_file_regexp + defi = quote_tags "\"#{defi}\"" + end + + if defi + link = @options[:link_abbrevs][link] if @options[:link_abbrevs].has_key?(link) + target = document.targets.find do |target| + puts "Find #{defi} target #{target}" + target[:content] == defi + end + link = "#tg.#{target[:index]}" if target + quote_tags("") + defi + quote_tags("") + else + quote_tags "\"#{link}\"" + end + end + end + + def rewrite_targets(line) + line.gsub!(RegexpHelper.target) do |_match| + match = Regexp.last_match + target = document.targets.find do |target| + target[:content] == match[:content] + end + target_tag = "#{target[:content]}" + quote_tags(target_tag) + end + end + def normalize_lang(lang) case lang when 'emacs-lisp', 'common-lisp', 'lisp' diff --git a/lib/org-ruby/line.rb b/lib/org-ruby/line.rb index ef15712..107cd63 100644 --- a/lib/org-ruby/line.rb +++ b/lib/org-ruby/line.rb @@ -70,6 +70,10 @@ def footnote? RegexpHelper.footnote_reference.match(@line) end + def target? + RegexpHelper.target.match(@line) + end + def property_drawer_begin_block? match = RegexpHelper.drawer.match(@line) match && match[:name].downcase == 'properties' diff --git a/lib/org-ruby/line_regexp.rb b/lib/org-ruby/line_regexp.rb index a69b7d2..0dc52ca 100644 --- a/lib/org-ruby/line_regexp.rb +++ b/lib/org-ruby/line_regexp.rb @@ -74,6 +74,10 @@ def metadata /^\s*(CLOCK|DEADLINE|START|CLOSED|SCHEDULED):/ end + def org_link + /\[\[(?[^\[\]]+)\](\[(?[^\[\]]+)\])?\]/x + end + def property_item /^\s*:(?[\w\-]+):\s*(?.*)$/ end @@ -102,5 +106,9 @@ def table_separator def tags /\s*:(?[\w:@]+):\s*$/ end + + def target + /<{2}(?[\w\s]+)>{2}/ + end end end diff --git a/lib/org-ruby/parser.rb b/lib/org-ruby/parser.rb index d1e4c5e..6b94578 100644 --- a/lib/org-ruby/parser.rb +++ b/lib/org-ruby/parser.rb @@ -173,6 +173,8 @@ def parse_lines(lines) # Store footnotes document.store_footnote(line) + # Store targets + document.store_target(line) if (line.end_block? && [line.paragraph_type, :comment].include?(mode)) || (line.property_drawer_end_block? && (mode == :property_drawer)) diff --git a/lib/org-ruby/regexp_helper.rb b/lib/org-ruby/regexp_helper.rb index ddad892..3646f22 100644 --- a/lib/org-ruby/regexp_helper.rb +++ b/lib/org-ruby/regexp_helper.rb @@ -147,7 +147,7 @@ def capture_footnote_definition(str) # HTML-style link, and that is how things will get recorded in # +result+. def rewrite_links(str) - str.gsub!(org_link_regexp) do |_match| + str.gsub!(RegexpHelper.org_link) do |_match| yield Regexp.last_match['url'], Regexp.last_match['friendly_text'] end str.gsub!(org_angle_link_text_regexp) do |_match| @@ -172,10 +172,6 @@ def org_emphasis_regexp "(?=#{post_emphasis})") end - def org_link_regexp - /\[\[(?[^\[\]]+)\](\[(?[^\[\]]+)\])?\]/x - end - def org_image_file_regexp /\.(gif|jpe?g|p(?:bm|gm|n[gm]|pm)|svgz?|tiff?|x[bp]m)/i end diff --git a/lib/orgmode/elements/document.rb b/lib/orgmode/elements/document.rb index 86c1efe..804400c 100644 --- a/lib/orgmode/elements/document.rb +++ b/lib/orgmode/elements/document.rb @@ -1,10 +1,11 @@ module Orgmode module Elements class Document - attr_reader :footnotes + attr_reader :footnotes, :targets def initialize @footnotes = [] + @targets = [] end def store_footnote(line) @@ -29,6 +30,17 @@ def store_footnote(line) footnote[:content] = content end end + + def store_target(line) + return unless line.target? + + line.to_s.scan(RegexpHelper.target) do |match| + content = match.first + target_index = @targets.length + 1 + target = { index: target_index, content: content } + @targets.push(target) + end + end end end end diff --git a/spec/html_examples/link-features.html b/spec/html_examples/link-features.html index 30b0854..4994cf3 100644 --- a/spec/html_examples/link-features.html +++ b/spec/html_examples/link-features.html @@ -27,3 +27,6 @@

In these links, .org used to be converted to .html. Not anymore since 0.9.2

Links abbreviations

URLs can be abbreviated by a LINK definition in the org file

This is an abbreviated link example

+

Internal links

+

Links with plain text point to target and each link has it’s own id.

+

This is a target and the link has tg.index id.

diff --git a/spec/html_examples/link-features.org b/spec/html_examples/link-features.org index 1b3ffc4..166be15 100644 --- a/spec/html_examples/link-features.org +++ b/spec/html_examples/link-features.org @@ -46,3 +46,9 @@ sections within documents, etc. #+LINK: example http://example.com/something [[example][This is an abbreviated link example]] + +* Internal links + + Links with plain text point to [[target]] and each [[link]] has it's own id. + + This is a <> and the <> has ~tg.index~ id. diff --git a/spec/org-ruby/line_regexp_spec.rb b/spec/org-ruby/line_regexp_spec.rb index c67e598..8b5b655 100644 --- a/spec/org-ruby/line_regexp_spec.rb +++ b/spec/org-ruby/line_regexp_spec.rb @@ -181,6 +181,12 @@ class DummyRegexp it { expect(regexp.metadata).to match ' SCHEDULED:' } end + describe '.org-link-regexp' do + it { expect(regexp.org_link).to match '[[url][description]]' } + it { expect(regexp.org_link).to match '[[url]]' } + it { expect(regexp.org_link).to match '[[a][~a~]]' } + end + describe '.property_item' do it { expect(regexp.property_item).to match ':key:value' } it { expect(regexp.property_item).to match ':key: value' } @@ -234,5 +240,15 @@ class DummyRegexp it { expect(regexp.tags).not_to match ":@tag :" } it { expect(regexp.tags).not_to match "@tag:" } end + + describe '.target' do + it { expect(regexp.target).to match "<>" } + it { expect(regexp.target).to match "Line <>" } + it { expect(regexp.target).to match "<> end" } + it 'captures match content' do + match = regexp.target.match("Pre <> post") + expect(match[:content]).to eq "This is a target" + end + end end end diff --git a/spec/orgmode/elements/document_spec.rb b/spec/orgmode/elements/document_spec.rb new file mode 100644 index 0000000..26b7ab3 --- /dev/null +++ b/spec/orgmode/elements/document_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' +module Orgmode + module Elements + RSpec.describe Document do + let(:document) { Document.new } + + describe 'initialize' do + it 'has empty footnotes' do + expect(document.footnotes).to be_empty + end + it 'has empty targets' do + expect(document.targets).to be_empty + end + end + + describe '#store_target' do + let(:target_content) { 'Target content' } + let(:target) { "<<#{target_content}>>" } + let(:line) { Line.new target } + + it 'save target in targets' do + document.store_target line + saved_target = document.targets.last + expect(saved_target[:content]).to eq target_content + expect(saved_target[:index]).to be 1 + end + + context 'when line has several targets' do + let(:line) { Line.new "Line with <> than <> target." } + + it "save all targets" do + document.store_target line + contents = document.targets.map { |target| target[:content] } + expect(contents).to include('more', 'one') + end + end + end + end + end +end diff --git a/spec/regexp_helper_spec.rb b/spec/regexp_helper_spec.rb index 3e43dac..2cafd14 100644 --- a/spec/regexp_helper_spec.rb +++ b/spec/regexp_helper_spec.rb @@ -10,15 +10,6 @@ example { expect(helper.org_emphasis_regexp).to match '[[a][~a~]]' } end - describe '#org-link-regexp' do - it 'match org-links' do - expect(helper.org_link_regexp).to match '[[url][description]]' - end - - example { expect(helper.org_link_regexp).to match '[[url]]' } - example { expect(helper.org_link_regexp).to match '[[a][~a~]]' } - end - it "should recognize simple markup" do e = Orgmode::RegexpHelper.new total = 0