Option to make HTML rendered lines markup independent from each other #15

Merged
merged 3 commits into from Apr 1, 2012
@@ -47,6 +47,12 @@ module Encoders
#
# Default: 'CodeRay output'
#
+ # === :independent_lines
+ # Split multilines blocks into line-wide blocks.
+ # Forced to true if :line_numbers option is set to :inline.
+ #
+ # Default: false
+ #
# === :line_numbers
# Include line numbers in :table, :inline, or nil (no line numbers)
#
@@ -99,7 +105,8 @@ class HTML < Encoder
:style => :alpha,
:wrap => nil,
:title => 'CodeRay output',
-
+
+ :independent_lines => false,
:line_numbers => nil,
:line_number_anchors => 'n',
:line_number_start => 1,
@@ -167,7 +174,11 @@ def setup options
@real_out = @out
@out = ''
end
-
+
+ options[:independent_lines] = true if options[:line_numbers] == :inline
+
+ @independent_lines = (options[:independent_lines] == true)
@korny

korny Feb 17, 2012

Owner

How about using the value of options[:independent_lines] directly? I would expect boolean options to act like Ruby conditions.

@emassip

emassip Feb 17, 2012

Contributor

I saw you like otimizations then I decided to use a boolean variable to prevent the hash key lookup during rendering =)

@korny

korny Feb 17, 2012

Owner

True :D I mean:

@independent_lines = options[:independent_lines]
@emassip

emassip Feb 17, 2012

Contributor

Because options[:independent_lines] could be missing (nil)

@korny

korny Feb 17, 2012

Owner

So? It would default to false, and even if it's set to nil, it would behave as expected.

@emassip

emassip Feb 17, 2012

Contributor

Indeed, you're right, this is useless.

+
@HTML_ESCAPE = HTML_ESCAPE.dup
@HTML_ESCAPE["\t"] = ' ' * options[:tab_width]
@@ -245,13 +256,25 @@ def text_token text, kind
if text =~ /#{HTML_ESCAPE_PATTERN}/o
text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] }
end
- if style = @span_for_kind[@last_opened ? [kind, *@opened] : kind]
+
+ style = @span_for_kind[@last_opened ? [kind, *@opened] : kind]
+
+ if @independent_lines && (i = text.index("\n")) && (c = @opened.size + (style ? 1 : 0)) > 0
+ close = '</span>' * c
+ reopen = ''
+ @opened.each_with_index do |k, index|
+ reopen << (@span_for_kind[index > 0 ? [k, *@opened[0 ... index ]] : k] || '<span>')
+ end
+ text[i .. -1] = text[i .. -1].gsub("\n", "#{close}\n#{reopen}#{style}")
+ end
+
+ if style
@out << style << text << '</span>'
else
@out << text
end
end
-
+
# token groups, eg. strings
def begin_group kind
@out << (@span_for_kind[@last_opened ? [kind, *@opened] : kind] || '<span>')
@@ -299,4 +322,4 @@ def end_line kind
end
end
-end
+end
@@ -68,23 +68,11 @@ def self.number! output, mode = :table, options = {}
when :inline
max_width = (start + line_count).to_s.size
line_number = start
- nesting = []
output.gsub!(/^.*$\n?/) do |line|
- line.chomp!
- open = nesting.join
- line.scan(%r!<(/)?span[^>]*>?!) do |close,|
- if close
- nesting.pop
- else
- nesting << $&
- end
- end
- close = '</span>' * nesting.size
-
line_number_text = bolding.call line_number
indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x)
line_number += 1
- "<span class=\"line-numbers\">#{indent}#{line_number_text}</span>#{open}#{line}#{close}\n"
+ "<span class=\"line-numbers\">#{indent}#{line_number_text}</span>#{line}"
end
when :table
@@ -112,4 +100,4 @@ def self.number! output, mode = :table, options = {}
end
end
-end
+end
View
@@ -0,0 +1,104 @@
+require 'test/unit'
+require 'coderay'
+
+class HtmlTest < Test::Unit::TestCase
+
+ def test_independent_lines_option
+
+ snippets = {}
+
+ snippets[:ruby] = {}
+
+ snippets[:ruby][:in] = <<-RUBY
+ruby_inside = <<-RUBY_INSIDE
+This is tricky,
+isn't it?
+RUBY_INSIDE
+ RUBY
+
+ snippets[:ruby][:expected_with_option_off] = <<-HTML_OPT_INDEPENDENT_LINES_OFF
+ruby_inside = <span class=\"string\"><span class=\"delimiter\">&lt;&lt;-RUBY_INSIDE</span></span><span class=\"string\"><span class=\"content\">
+This is tricky,
+isn't it?</span><span class=\"delimiter\">
+RUBY_INSIDE</span></span>
+ HTML_OPT_INDEPENDENT_LINES_OFF
+
+ snippets[:ruby][:expected_with_option_on] = <<-HTML_OPT_INDEPENDENT_LINES_ON
+ruby_inside = <span class=\"string\"><span class=\"delimiter\">&lt;&lt;-RUBY_INSIDE</span></span><span class=\"string\"><span class=\"content\"></span></span>
+<span class=\"string\"><span class=\"content\">This is tricky,</span></span>
+<span class=\"string\"><span class=\"content\">isn't it?</span><span class=\"delimiter\"></span></span>
+<span class=\"string\"><span class=\"delimiter\">RUBY_INSIDE</span></span>
+ HTML_OPT_INDEPENDENT_LINES_ON
+
+ snippets[:java] = {}
+
+ snippets[:java][:in] = <<-JAVA
+import java.lang.*;
+
+/**
+ * This is some multiline javadoc
+ * used to test the
+ */
+public class Test {
+ public static final String MESSAGE = "My message\
+ To the world";
+
+ static void main() {
+ /*
+ * Another multiline
+ * comment
+ */
+ System.out.println(MESSAGE);
+ }
+}
+ JAVA
+
+ snippets[:java][:expected_with_option_off] = <<-HTML_OPT_INDEPENDENT_LINES_OFF
+<span class=\"keyword\">import</span> <span class=\"include\">java.lang</span>.*;
+
+<span class=\"comment\">/**
+ * This is some multiline javadoc
+ * used to test the
+ */</span>
+<span class=\"directive\">public</span> <span class=\"type\">class</span> <span class=\"class\">Test</span> {
+ <span class=\"directive\">public</span> <span class=\"directive\">static</span> <span class=\"directive\">final</span> <span class=\"predefined-type\">String</span> MESSAGE = <span class=\"string\"><span class=\"delimiter\">&quot;</span><span class=\"content\">My message To the world</span><span class=\"delimiter\">&quot;</span></span>;
+
+ <span class=\"directive\">static</span> <span class=\"type\">void</span> main() {
+ <span class=\"comment\">/*
+ * Another multiline
+ * comment
+ */</span>
+ <span class=\"predefined-type\">System</span>.out.println(MESSAGE);
+ }
+}
+ HTML_OPT_INDEPENDENT_LINES_OFF
+
+ snippets[:java][:expected_with_option_on] = <<-HTML_OPT_INDEPENDENT_LINES_ON
+<span class=\"keyword\">import</span> <span class=\"include\">java.lang</span>.*;
+
+<span class=\"comment\">/**</span>
+<span class=\"comment\"> * This is some multiline javadoc</span>
+<span class=\"comment\"> * used to test the</span>
+<span class=\"comment\"> */</span>
+<span class=\"directive\">public</span> <span class=\"type\">class</span> <span class=\"class\">Test</span> {
+ <span class=\"directive\">public</span> <span class=\"directive\">static</span> <span class=\"directive\">final</span> <span class=\"predefined-type\">String</span> MESSAGE = <span class=\"string\"><span class=\"delimiter\">&quot;</span><span class=\"content\">My message To the world</span><span class=\"delimiter\">&quot;</span></span>;
+
+ <span class=\"directive\">static</span> <span class=\"type\">void</span> main() {
+ <span class=\"comment\">/*</span>
+<span class=\"comment\"> * Another multiline</span>
+<span class=\"comment\"> * comment</span>
+<span class=\"comment\"> */</span>
+ <span class=\"predefined-type\">System</span>.out.println(MESSAGE);
+ }
+}
+ HTML_OPT_INDEPENDENT_LINES_ON
+
+ snippets.entries().each do |lang, code|
+ tokens = CodeRay.scan code[:in], lang
+
+ assert_equal code[:expected_with_option_off], tokens.html
+ assert_equal code[:expected_with_option_off], tokens.html(:independent_lines => false)
+ assert_equal code[:expected_with_option_on], tokens.html(:independent_lines => true)
+ end
+ end
+end