]> git.wincent.com - wikitext.git/commitdiff
Fix inconsistent behaviour of unexpected PRE_START tokens
authorWincent Colaiuta <win@wincent.com>
Sun, 23 Mar 2008 16:50:55 +0000 (17:50 +0100)
committerWincent Colaiuta <win@wincent.com>
Sun, 23 Mar 2008 16:50:55 +0000 (17:50 +0100)
This fixes the issue where PRE_START tokens weren't working when they
followed a list (clearly a bug) by changing the way in which
unexpected PRE_START tokens are handled in general.

Basically, we were explicitly allowing them to appear inside
BLOCKQUOTE_START blocks and when the scope was empty, and disallowing
them everywhere else. This allowed a number of inconsistencies to
creep in; one example is that a PRE_START inside a H1 block would not
be allowed _unless_ the H1 itself was inside a BLOCKQUOTE_START.

Not only is this a confusing inconsistency, it's also a departure from
the pattern held almost everywhere else in the parser, where if we see
an unexpected token we respond by closing all the previous spans and
blocks until we get to a scope where we can emit the unexpected token.

So now we have consistent behaviour and the only place where PRE_START
tokens are explicitly disallowed is inside BLOCKQUOTE blocks (not
BLOCKQUOTE_START blocks), as indicated in the documentation.

Signed-off-by: Wincent Colaiuta <win@wincent.com>
ext/parser.c
spec/pre_spec.rb
spec/regressions_spec.rb

index 69d924f836d8fad0e4fb31ccc861a38c8b51a75d..9c200495006a8a87ac0ca636337aad72a368ae9f 100644 (file)
@@ -1046,9 +1046,16 @@ VALUE Wikitext_parser_parse(int argc, VALUE *argv, VALUE self)
                     ary_push(parser->scope, PRE_START);
                     ary_push(parser->line, PRE_START);
                 }
-                else if (parser->scope->count == 0 || (IN(P) && !IN(BLOCKQUOTE)))
+                else if (IN(BLOCKQUOTE))
+                {
+                    // PRE_START is illegal
+                    i = NIL_P(parser->capture) ? parser->output : parser->capture;
+                    _Wikitext_pop_excess_elements(parser);
+                    _Wikitext_start_para_if_necessary(parser);
+                    rb_str_cat(i, escaped_pre_start, sizeof(escaped_pre_start) - 1);
+                }
+                else
                 {
-                    // would be nice to eliminate the repetition here but it's probably the clearest way
                     _Wikitext_rollback_failed_link(parser);             // if any
                     _Wikitext_rollback_failed_external_link(parser);    // if any
                     _Wikitext_pop_from_stack_up_to(parser, Qnil, P, Qtrue);
@@ -1057,14 +1064,6 @@ VALUE Wikitext_parser_parse(int argc, VALUE *argv, VALUE self)
                     ary_push(parser->scope, PRE_START);
                     ary_push(parser->line, PRE_START);
                 }
-                else
-                {
-                    // everywhere else, PRE_START is illegal (in LI, BLOCKQUOTE, H1_START etc)
-                    i = NIL_P(parser->capture) ? parser->output : parser->capture;
-                    _Wikitext_pop_excess_elements(parser);
-                    _Wikitext_start_para_if_necessary(parser);
-                    rb_str_cat(i, escaped_pre_start, sizeof(escaped_pre_start) - 1);
-                }
                 break;
 
             case PRE_END:
index 249fc9b0ead086cd898088c1b00726f2b66fa0cf..9ecd18bc6756a64ee2987fed472df7729c655e4f 100755 (executable)
@@ -263,13 +263,14 @@ describe Wikitext::Parser, 'parsing PRE_START/PRE_END blocks' do
     @parser.parse('> </pre>').should == expected
   end
 
-  it 'should ignore PRE_START inside UL blocks' do
+  it 'should break out of UL blocks on seeing PRE_START' do
     expected = dedent <<-END
       <ul>
-        <li>&lt;pre&gt;</li>
+        <li>foo</li>
       </ul>
+      <pre>bar</pre>
     END
-    @parser.parse('* <pre>').should == expected
+    @parser.parse('* foo<pre>bar</pre>').should == expected
   end
 
   it 'should ignore PRE_END inside UL blocks' do
@@ -281,13 +282,14 @@ describe Wikitext::Parser, 'parsing PRE_START/PRE_END blocks' do
     @parser.parse('* </pre>').should == expected
   end
 
-  it 'should ignore PRE_START inside OL blocks' do
+  it 'should break out of OL blocks on seeing PRE_START' do
     expected = dedent <<-END
       <ol>
-        <li>&lt;pre&gt;</li>
+        <li>foo</li>
       </ol>
+      <pre>bar</pre>
     END
-    @parser.parse('# <pre>').should == expected
+    @parser.parse('# foo<pre>bar</pre>').should == expected
   end
 
   it 'should ignore PRE_END inside OL blocks' do
@@ -299,48 +301,78 @@ describe Wikitext::Parser, 'parsing PRE_START/PRE_END blocks' do
     @parser.parse('# </pre>').should == expected
   end
 
-  it 'should ignore PRE_START inside H1 blocks' do
-    @parser.parse('= <pre> =').should == "<h1>&lt;pre&gt;</h1>\n"
+  it 'should break out of H1 blocks on seeing PRE_START' do
+    expected = dedent <<-END
+      <h1>foo</h1>
+      <pre>bar</pre>
+      <p> =</p>
+    END
+    @parser.parse('= foo<pre>bar</pre> =').should == expected
   end
 
   it 'should ignore PRE_END inside H1 blocks' do
     @parser.parse('= </pre> =').should == "<h1>&lt;/pre&gt;</h1>\n"
   end
 
-  it 'should ignore PRE_START inside H2 blocks' do
-    @parser.parse('== <pre> ==').should == "<h2>&lt;pre&gt;</h2>\n"
+  it 'should break out of H2 blocks on seeing PRE_START' do
+    expected = dedent <<-END
+      <h2>foo</h2>
+      <pre>bar</pre>
+      <p> ==</p>
+    END
+    @parser.parse('== foo<pre>bar</pre> ==').should == expected
   end
 
   it 'should ignore PRE_END inside H2 blocks' do
     @parser.parse('== </pre> ==').should == "<h2>&lt;/pre&gt;</h2>\n"
   end
 
-  it 'should ignore PRE_START inside H3 blocks' do
-    @parser.parse('=== <pre> ===').should == "<h3>&lt;pre&gt;</h3>\n"
+  it 'should break out of H3 blocks on seeing PRE_START' do
+    expected = dedent <<-END
+      <h3>foo</h3>
+      <pre>bar</pre>
+      <p> ===</p>
+    END
+    @parser.parse('=== foo<pre>bar</pre> ===').should == expected
   end
 
   it 'should ignore PRE_END inside H3 blocks' do
     @parser.parse('=== </pre> ===').should == "<h3>&lt;/pre&gt;</h3>\n"
   end
 
-  it 'should ignore PRE_START inside H4 blocks' do
-    @parser.parse('==== <pre> ====').should == "<h4>&lt;pre&gt;</h4>\n"
+  it 'should break out of H4 blocks on seeing PRE_START' do
+    expected = dedent <<-END
+      <h4>foo</h4>
+      <pre>bar</pre>
+      <p> ====</p>
+    END
+    @parser.parse('==== foo<pre>bar</pre> ====').should == expected
   end
 
   it 'should ignore PRE_END inside H4 blocks' do
     @parser.parse('==== </pre> ====').should == "<h4>&lt;/pre&gt;</h4>\n"
   end
 
-  it 'should ignore PRE_START inside H5 blocks' do
-    @parser.parse('===== <pre> =====').should == "<h5>&lt;pre&gt;</h5>\n"
+  it 'should break out of H5 blocks on seeing PRE_START' do
+    expected = dedent <<-END
+      <h5>foo</h5>
+      <pre>bar</pre>
+      <p> =====</p>
+    END
+    @parser.parse('===== foo<pre>bar</pre> =====').should == expected
   end
 
   it 'should ignore PRE_END inside H5 blocks' do
     @parser.parse('===== </pre> =====').should == "<h5>&lt;/pre&gt;</h5>\n"
   end
 
-  it 'should ignore PRE_START inside H6 blocks' do
-    @parser.parse('====== <pre> ======').should == "<h6>&lt;pre&gt;</h6>\n"
+  it 'should break out of H6 blocks on seeing PRE_START' do
+    expected = dedent <<-END
+      <h6>foo</h6>
+      <pre>bar</pre>
+      <p> ======</p>
+    END
+    @parser.parse('====== foo<pre>bar</pre> ======').should == expected
   end
 
   it 'should ignore PRE_END inside H6 blocks' do
index 7a3eeadbae5bb52da66e203a349cef47106d86d4..302c948978e777d7bc037ca3a5bb5435b1a81dfe 100755 (executable)
@@ -22,8 +22,8 @@ describe Wikitext::Parser, 'regressions' do
     @parser = Wikitext::Parser.new
   end
 
+  # turns out that this was never a bug in wikitext -- it was a bug in the host application -- but keeping the test does no harm
   it 'should correctly transform example #1' do
-    # turns out that this was never a bug in wikitext: it was a bug in the host application
     input = dedent <<-END
       = Leopard =
       
@@ -43,7 +43,8 @@ describe Wikitext::Parser, 'regressions' do
     @parser.parse(input).should == expected
   end
 
-  # this one discovered in a real Rails application
+  # discovered at: http://rails.wincent.com/wiki/nginx_log_rotation
+  # fixed by 0a328f1
   it 'should allow empty lines in PRE blocks marked up with a leading space' do
     input = dedent <<-END
        # -d turns on debug mode: output is verbose, no actual changes are made to the log files
@@ -61,4 +62,62 @@ describe Wikitext::Parser, 'regressions' do
     END
     @parser.parse(input).should == expected
   end
+
+  # discovered at: http://rails.wincent.com/wiki/Installing_Ragel_5.2.0_on_Mac_OS_X_Tiger
+  # fixed by ?
+  it 'should handle PRE_START blocks which follow unordered lists' do
+    input = dedent <<-END
+      * Get link to latest source code from: http://www.cs.queensu.ca/~thurston/ragel/
+      
+      <pre>wget http://www.cs.queensu.ca/~thurston/ragel/ragel-5.20.tar.gz
+      tar xzvf ragel-5.20.tar.gz
+      cd ragel-5.20</pre>
+    END
+    expected = dedent <<-END
+      <ul>
+        <li>Get link to latest source code from: <a href="http://www.cs.queensu.ca/~thurston/ragel/" class="external">http://www.cs.queensu.ca/~thurston/ragel/</a></li>
+      </ul>
+      <pre>wget <a href="http://www.cs.queensu.ca/~thurston/ragel/ragel-5.20.tar.gz" class="external">http://www.cs.queensu.ca/~thurston/ragel/ragel-5.20.tar.gz</a>
+      tar xzvf ragel-5.20.tar.gz
+      cd ragel-5.20</pre>
+    END
+    @parser.parse(input).should == expected
+  end
+
+  # discovered at: http://rails.wincent.com/wiki/Movable_Type_security_notes
+  # fixed by ?
+  it 'should handle PRE_START blocks which follow unordered lists' do
+    input = dedent <<-END
+      # Turn off the [[Movable Type]] search function; use Google instead (it's better anyway) with a form something like this:
+      
+      <pre><form method="get"...></pre>
+    END
+    expected = dedent <<-END
+      <ol>
+        <li>Turn off the <a href="/wiki/Movable%20Type">Movable Type</a> search function; use Google instead (it's better anyway) with a form something like this:</li>
+      </ol>
+      <pre>&lt;form method=&quot;get&quot;...&gt;</pre>
+    END
+    @parser.parse(input).should == expected
+  end
+
+  # discovered at: http://rails.wincent.com/wiki/Movable_Type_security_notes
+  # fixed by ?
+  it 'should respect additional indentation found inside PRE blocks' do
+    pending
+
+    # note the two extra spaces on each line
+    input = dedent <<-END
+        <input type="text" name="q" size="20" maxlength="255" value="" />
+        <input type="hidden" name="hl" value="en" />
+    END
+
+    # first line had only one additional space
+    # second line had no additional spaces at all
+    expected = dedent <<-END
+      <pre>  &lt;input type="text" name="q" size="20" maxlength="255" value="" /&gt;
+        &lt;input type="hidden" name="hl" value="en" /&gt;</pre>
+    END
+    @parser.parse(input).should == expected
+  end
 end