kramdown 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kramdown might be problematic. Click here for more details.

Files changed (43) hide show
  1. data/ChangeLog +315 -0
  2. data/Rakefile +35 -0
  3. data/VERSION +1 -1
  4. data/benchmark/generate_data.rb +6 -4
  5. data/benchmark/historic-jruby-1.4.0.dat +7 -7
  6. data/benchmark/historic-ruby-1.8.6.dat +7 -7
  7. data/benchmark/historic-ruby-1.8.7.dat +7 -7
  8. data/benchmark/historic-ruby-1.9.1p243.dat +7 -7
  9. data/benchmark/historic-ruby-1.9.2dev.dat +7 -7
  10. data/bin/kramdown +15 -4
  11. data/data/kramdown/document.html +9 -0
  12. data/data/kramdown/document.latex +38 -0
  13. data/doc/default.less.css +468 -0
  14. data/doc/default.template +23 -34
  15. data/doc/index.page +25 -20
  16. data/doc/news.page +1 -1
  17. data/doc/syntax.page +226 -159
  18. data/doc/tests.page +2 -1
  19. data/lib/kramdown/converter/html.rb +14 -2
  20. data/lib/kramdown/converter/latex.rb +19 -1
  21. data/lib/kramdown/document.rb +17 -9
  22. data/lib/kramdown/parser/kramdown.rb +4 -3
  23. data/lib/kramdown/parser/kramdown/autolink.rb +7 -2
  24. data/lib/kramdown/parser/kramdown/emphasis.rb +3 -2
  25. data/lib/kramdown/parser/kramdown/escaped_chars.rb +1 -1
  26. data/lib/kramdown/parser/kramdown/list.rb +2 -1
  27. data/lib/kramdown/parser/kramdown/math.rb +53 -0
  28. data/lib/kramdown/version.rb +1 -1
  29. data/man/man1/kramdown.1 +189 -0
  30. data/test/testcases/block/08_list/mixed.html +9 -3
  31. data/test/testcases/block/08_list/special_cases.html +49 -0
  32. data/test/testcases/block/08_list/special_cases.text +29 -0
  33. data/test/testcases/block/15_math/normal.html +19 -0
  34. data/test/testcases/block/15_math/normal.text +18 -0
  35. data/test/testcases/span/02_emphasis/errors.html +1 -1
  36. data/test/testcases/span/02_emphasis/nesting.html +4 -0
  37. data/test/testcases/span/02_emphasis/nesting.text +3 -0
  38. data/test/testcases/span/autolinks/url_links.html +3 -0
  39. data/test/testcases/span/autolinks/url_links.text +3 -0
  40. data/test/testcases/span/math/normal.html +5 -0
  41. data/test/testcases/span/math/normal.text +5 -0
  42. metadata +21 -6
  43. data/doc/default.css +0 -293
data/doc/tests.page CHANGED
@@ -39,7 +39,8 @@ BlueCloth and rdiscount:
39
39
  </code>
40
40
  </pre>
41
41
 
42
- And here are some graphs which show the execution times on different Ruby interpreters:
42
+ And here are some graphs which show the execution times of the various kramdown releases on
43
+ different Ruby interpreters:
43
44
 
44
45
  ![ruby 1.8.6]({relocatable: img/graph-ruby-1.8.6.png})
45
46
  ![ruby 1.8.7]({relocatable: img/graph-ruby-1.8.7.png})
@@ -206,14 +206,15 @@ module Kramdown
206
206
  end
207
207
 
208
208
  def convert_a(el, indent, opts)
209
- if el.options[:attr]['href'] =~ /^mailto:/
209
+ do_obfuscation = el.options[:attr]['href'] =~ /^mailto:/
210
+ if do_obfuscation
210
211
  el = Marshal.load(Marshal.dump(el)) # so that the original is not changed
211
212
  href = obfuscate(el.options[:attr]['href'].sub(/^mailto:/, ''))
212
213
  mailto = obfuscate('mailto')
213
214
  el.options[:attr]['href'] = "#{mailto}:#{href}"
214
215
  end
215
216
  res = inner(el, indent, opts)
216
- res = obfuscate(res) if el.options[:obfuscate_text]
217
+ res = obfuscate(res) if do_obfuscation
217
218
  "<a#{options_for_element(el)}>#{res}</a>"
218
219
  end
219
220
 
@@ -258,6 +259,16 @@ module Kramdown
258
259
  "&#{el.value};"
259
260
  end
260
261
 
262
+ def convert_math(el, indent, opts)
263
+ el = Marshal.load(Marshal.dump(el)) # so that the original is not changed
264
+ el.options[:attr] ||= {}
265
+ el.options[:attr]['class'] ||= ''
266
+ el.options[:attr]['class'] += (el.options[:attr]['class'].empty? ? '' : ' ') + 'math'
267
+ type = 'span'
268
+ type = 'div' if el.options[:type] == :block
269
+ "<#{type}#{options_for_element(el)}>#{escape_html(el.value, :text)}</#{type}>#{type == 'div' ? "\n" : ''}"
270
+ end
271
+
261
272
  def convert_root(el, indent, opts)
262
273
  inner(el, indent, opts) << footnote_content
263
274
  end
@@ -268,6 +279,7 @@ module Kramdown
268
279
  text.each_byte do |b|
269
280
  result += (b > 128 ? b.chr : "&#%03d;" % b)
270
281
  end
282
+ result.force_encoding(text.encoding) if RUBY_VERSION >= '1.9'
271
283
  result
272
284
  end
273
285
 
@@ -20,6 +20,8 @@
20
20
  #++
21
21
  #
22
22
 
23
+ require 'set'
24
+
23
25
  module Kramdown
24
26
 
25
27
  module Converter
@@ -35,7 +37,7 @@ module Kramdown
35
37
  super
36
38
  #TODO: set the footnote counter at the beginning of the document
37
39
  @doc.options[:footnote_nr]
38
- @doc.conversion_infos[:packages] = []
40
+ @doc.conversion_infos[:packages] = Set.new
39
41
  end
40
42
 
41
43
  def convert(el, opts = {})
@@ -138,13 +140,16 @@ module Kramdown
138
140
 
139
141
  def convert_html_element(el, opts)
140
142
  @doc.warnings << "Can't convert HTML element"
143
+ ''
141
144
  end
142
145
 
143
146
  def convert_html_text(el, opts)
144
147
  @doc.warnings << "Can't convert HTML text"
148
+ ''
145
149
  end
146
150
 
147
151
  def convert_xml_comment(el, opts)
152
+ @doc.warnings << "Can't convert XML comment/PI"
148
153
  ''
149
154
  end
150
155
  alias :convert_xml_pi :convert_xml_comment
@@ -496,6 +501,19 @@ EOF
496
501
  SMART_QUOTE_SYMS[el.value]
497
502
  end
498
503
 
504
+ def convert_math(el, opts)
505
+ @doc.conversion_infos[:packages] += %w[amssymb amsmath amsthm amsfonts]
506
+ if el.options[:type] == :block
507
+ if el.value =~ /\A\s*\\begin\{/
508
+ el.value
509
+ else
510
+ latex_environment('displaymath', el.value)
511
+ end
512
+ else
513
+ "$#{el.value}$"
514
+ end
515
+ end
516
+
499
517
  ESCAPE_MAP = {
500
518
  "^" => "\\^{}",
501
519
  "\\" => "\\textbackslash{}",
@@ -54,7 +54,7 @@ module Kramdown
54
54
  # The #to_html method is a shortcut for using the Converter::Html class.
55
55
  #
56
56
  # The second argument to the #new method is an options hash for customizing the behaviour of the
57
- # kramdown parser and the converters.
57
+ # used parser and the converter. See Document#new for more information!
58
58
  class Document
59
59
 
60
60
  # The element tree of the document. It is immediately available after the #new method has been
@@ -63,7 +63,7 @@ module Kramdown
63
63
 
64
64
  # The options hash which holds the options for parsing/converting the Kramdown document. It is
65
65
  # possible that these values get changed during the parsing phase.
66
- attr_accessor :options
66
+ attr_reader :options
67
67
 
68
68
  # An array of warning messages. It is filled with warnings during the parsing phase (i.e. in
69
69
  # #new) and the conversion phase.
@@ -73,25 +73,33 @@ module Kramdown
73
73
  attr_reader :parse_infos
74
74
 
75
75
  # Holds conversion information which is dependent on the used converter. A converter clears this
76
- # variable before duing the conversion.
76
+ # variable before doing the conversion.
77
77
  attr_reader :conversion_infos
78
78
 
79
79
 
80
- # Create a new Kramdown document from the string +source+ and use the provided +options+. The
81
- # +source+ is immediately parsed by the kramdown parser sothat after this call the output can be
82
- # generated.
80
+ # Create a new Kramdown document from the string +source+ and use the provided +options+.
81
+ #
82
+ # The special options key <tt>:input</tt> can be used to select the parser that should parse the
83
+ # +source+. It has to be the name of a class in the Kramdown::Parser module. For example, to
84
+ # select the kramdown parser, one would set the <tt>:input</tt> key to +Kramdown+. If this key
85
+ # is not set, it defaults to +Kramdown+.
86
+ #
87
+ # The +source+ is immediately parsed by the selected parser so that after this call the document
88
+ # tree is available and the output can be generated.
83
89
  def initialize(source, options = {})
84
90
  @options = Options.merge(options)
85
91
  @warnings = []
86
92
  @parse_infos = {}
87
93
  @conversion_infos = {}
88
- @tree = Parser::Kramdown.parse(source, self)
94
+ @tree = Parser.const_get((options[:input] || 'kramdown').to_s.capitalize).parse(source, self)
95
+ rescue NameError
96
+ raise Kramdown::Error.new("Invalid input format selected: #{options[:input]}")
89
97
  end
90
98
 
91
99
  # Check if a method is invoked that begins with +to_+ and if so, try to instantiate a converter
92
- # class and use it for converting the document.
100
+ # class (i.e. a class in the Kramdown::Converter module) and use it for converting the document.
93
101
  #
94
- # For example, +to_html+ would instantiate the Converter::Html class.
102
+ # For example, +to_html+ would instantiate the Kramdown::Converter::Html class.
95
103
  def method_missing(id, *attr, &block)
96
104
  if id.to_s =~ /^to_(\w+)$/
97
105
  Converter.const_get($1.capitalize).convert(self)
@@ -85,8 +85,8 @@ module Kramdown
85
85
 
86
86
  BLOCK_PARSERS = [:blank_line, :codeblock, :codeblock_fenced, :blockquote, :table, :atx_header,
87
87
  :setext_header, :horizontal_rule, :list, :definition_list, :link_definition, :block_html,
88
- :footnote_definition, :ald, :block_ial, :extension_block, :eob_marker, :paragraph]
89
- SPAN_PARSERS = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link, :smart_quotes,
88
+ :footnote_definition, :ald, :block_ial, :block_math, :extension_block, :eob_marker, :paragraph]
89
+ SPAN_PARSERS = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link, :smart_quotes, :inline_math,
90
90
  :span_ial, :html_entity, :typographic_syms, :line_break, :escaped_chars]
91
91
 
92
92
  # Adapt the object to allow parsing like specified in the options.
@@ -151,7 +151,7 @@ module Kramdown
151
151
 
152
152
  # Parse all span level elements in the source string.
153
153
  def parse_spans(el, stop_re = nil, parsers = nil, text_type = :text)
154
- @stack.push([@tree, @text_type])
154
+ @stack.push([@tree, @text_type]) unless @tree.nil?
155
155
  @tree, @text_type = el, text_type
156
156
 
157
157
  span_start = @span_start
@@ -284,6 +284,7 @@ module Kramdown
284
284
  require 'kramdown/parser/kramdown/codespan'
285
285
  require 'kramdown/parser/kramdown/emphasis'
286
286
  require 'kramdown/parser/kramdown/smart_quotes'
287
+ require 'kramdown/parser/kramdown/math'
287
288
 
288
289
  end
289
290
 
@@ -24,14 +24,19 @@ module Kramdown
24
24
  module Parser
25
25
  class Kramdown
26
26
 
27
- AUTOLINK_START = /<((mailto|https?|ftps?):.*?|\S*?@\S*?)>/
27
+ if RUBY_VERSION == '1.8.5'
28
+ ACHARS = '\x80-\xFF'
29
+ else
30
+ ACHARS = ''
31
+ end
32
+ AUTOLINK_START = /<((mailto|https?|ftps?):.+?|[-.\w#{ACHARS}]+@[-\w#{ACHARS}]+(\.[-\w#{ACHARS}]+)*\.[a-z]+)>/u
28
33
 
29
34
  # Parse the autolink at the current location.
30
35
  def parse_autolink
31
36
  @src.pos += @src.matched_size
32
37
  href = @src[1]
33
38
  href= "mailto:#{href}" if @src[2].nil?
34
- el = Element.new(:a, nil, {:attr => {'href' => href}, :obfuscate_text => (@src[2].nil? || @src[2] == 'mailto')})
39
+ el = Element.new(:a, nil, {:attr => {'href' => href}})
35
40
  add_text(@src[1].sub(/^mailto:/, ''), el)
36
41
  @tree.children << el
37
42
  end
@@ -33,7 +33,8 @@ module Kramdown
33
33
  type = (result =~ /_/ ? '_' : '*')
34
34
  reset_pos = @src.pos
35
35
 
36
- if (type == '_' && @src.pre_match =~ /[[:alpha:]]\z/ && @src.check(/[[:alpha:]]/)) || @src.check(/\s/)
36
+ if (type == '_' && @src.pre_match =~ /[[:alpha:]]\z/ && @src.check(/[[:alpha:]]/)) || @src.check(/\s/) ||
37
+ @tree.type == element || @stack.any? {|el, _| el.type == element}
37
38
  add_text(result)
38
39
  return
39
40
  end
@@ -50,7 +51,7 @@ module Kramdown
50
51
  end
51
52
 
52
53
  found, el, stop_re = sub_parse.call(result, element)
53
- if !found && element == :strong
54
+ if !found && element == :strong && @tree.type != :em
54
55
  @src.pos = reset_pos - 1
55
56
  found, el, stop_re = sub_parse.call(type, :em)
56
57
  end
@@ -24,7 +24,7 @@ module Kramdown
24
24
  module Parser
25
25
  class Kramdown
26
26
 
27
- ESCAPED_CHARS = /\\([\\.*_+`()\[\]{}#!:|"'-])/
27
+ ESCAPED_CHARS = /\\([\\.*_+`()\[\]{}#!:|"'\$-])/
28
28
 
29
29
  # Parse the backslash-escaped character at the current location.
30
30
  def parse_escaped_chars
@@ -112,7 +112,8 @@ module Kramdown
112
112
  next if it.children.size == 0
113
113
 
114
114
  if it.children.first.type == :p && (it.children.length < 2 || it.children[1].type != :blank ||
115
- (it == list.children.last && it.children.length == 2 && !eob_found))
115
+ (it == list.children.last && it.children.length == 2 && !eob_found)) &&
116
+ (list.children.last != it || list.children.size == 1 || list.children[0..-2].any? {|cit| cit.children.first.type != :p})
116
117
  text = it.children.shift.children.first
117
118
  text.value += "\n" if !it.children.empty? && it.children[0].type != :blank
118
119
  it.children.unshift(text)
@@ -0,0 +1,53 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ module Kramdown
24
+ module Parser
25
+ class Kramdown
26
+
27
+ BLOCK_MATH_START = /^#{OPT_SPACE}(\\)?\$\$(.*?)\$\$\s*?\n/m
28
+
29
+ # Parse the math block at the current location.
30
+ def parse_block_math
31
+ if @src[1]
32
+ @src.scan(/^#{OPT_SPACE}\\/)
33
+ return false
34
+ end
35
+ @src.pos += @src.matched_size
36
+ @tree.children << Element.new(:math, @src[2], :type => :block)
37
+ true
38
+ end
39
+ define_parser(:block_math, BLOCK_MATH_START)
40
+
41
+
42
+ INLINE_MATH_START = /\$\$(.*?)\$\$/
43
+
44
+ # Parse the inline math at the current location.
45
+ def parse_inline_math
46
+ @src.pos += @src.matched_size
47
+ @tree.children << Element.new(:math, @src[1], :type => :inline)
48
+ end
49
+ define_parser(:inline_math, INLINE_MATH_START, '\$')
50
+
51
+ end
52
+ end
53
+ end
@@ -23,6 +23,6 @@
23
23
  module Kramdown
24
24
 
25
25
  # The kramdown version.
26
- VERSION = '0.5.0'
26
+ VERSION = '0.6.0'
27
27
 
28
28
  end
@@ -0,0 +1,189 @@
1
+ .TH "KRAMDOWN" 1 "February 2010"
2
+ .SH NAME
3
+ kramdown \- a fast, pure-Ruby Markdown-superset converter
4
+ .SH SYNOPSIS
5
+ .B kramdown
6
+ [\fIoptions\fR]
7
+ [\fIFILE\fR ...]
8
+ .SH DESCRIPTION
9
+ kramdown parses a superset of Markdown and converts it to different output formats. It is supports
10
+ standard Markdown (with some minor modifications) and various extensions like tables and definition
11
+ lists.
12
+
13
+ If \fIFILE\fR is not specified, kramdown reads from the standard input. The result is written to the
14
+ standard output.
15
+
16
+ There are two sets of options that kramdown accepts: The first one includes the options that are
17
+ used directly by the kramdown binary. The second set of options controls how kramdown parses and
18
+ converts its input.
19
+ .SH OPTIONS
20
+ .TP
21
+ .B \-f, \-\-format ARG
22
+ Specify the output format. Available output formats: html (this is the default) or latex.
23
+ .TP
24
+ .B \-v, \-\-version
25
+ Show the version of kramdown.
26
+ .TP
27
+ .B \-h, \-\-help
28
+ Show the help.
29
+
30
+ .SH KRAMDOWN OPTIONS
31
+
32
+ .TP
33
+ .B \-\-coderay_line_numbers ARG
34
+
35
+ Defines how and if line numbers should be shown
36
+
37
+ The possible values are :table, :inline, :list or nil. If this option is
38
+ nil, no line numbers are shown.
39
+
40
+ Default: :inline
41
+ Used by: HTML converter
42
+
43
+
44
+ .TP
45
+ .B \-\-[no\-]parse_block_html
46
+
47
+ Process kramdown syntax in block HTML tags
48
+
49
+ If this option is `true`, the kramdown parser processes the content of
50
+ block HTML tags as text containing block level elements. Since this is
51
+ not wanted normally, the default is `false`. It is normally better to
52
+ selectively enable kramdown processing via the markdown attribute.
53
+
54
+ Default: false
55
+ Used by: kramdown parser
56
+
57
+
58
+ .TP
59
+ .B \-\-coderay_line_number_start ARG
60
+
61
+ The start value for the line numbers
62
+
63
+ Default: 1
64
+ Used by: HTML converter
65
+
66
+
67
+ .TP
68
+ .B \-\-[no\-]parse_span_html
69
+
70
+ Process kramdown syntax in span HTML tags
71
+
72
+ If this option is `true`, the kramdown parser processes the content of
73
+ span HTML tags as text containing span level elements.
74
+
75
+ Default: true
76
+ Used by: kramdown parser
77
+
78
+
79
+ .TP
80
+ .B \-\-coderay_tab_width ARG
81
+
82
+ The tab width used in highlighted code
83
+
84
+ Used by: HTML converter
85
+
86
+
87
+ .TP
88
+ .B \-\-footnote_nr ARG
89
+
90
+ The number of the first footnote
91
+
92
+ This option can be used to specify the number that is used for the first
93
+ footnote.
94
+
95
+ Default: 1
96
+ Used by: HTML converter
97
+
98
+
99
+ .TP
100
+ .B \-\-coderay_bold_every ARG
101
+
102
+ Defines how often a line number should be made bold
103
+
104
+ Default: 10
105
+ Used by: HTML converter
106
+
107
+
108
+ .TP
109
+ .B \-\-filter_html ARG
110
+
111
+ An array of HTML tags that should be filtered from the output
112
+
113
+ The value can either be specified as array or as a space separated
114
+ string (which will be converted to an array). All HTML tags that are
115
+ listed in the array will be filtered from the output, i.e. only their
116
+ contents is used. This applies only to HTML tags found in the initial
117
+ document.
118
+
119
+ Default: []
120
+ Used by: HTML converter
121
+
122
+
123
+ .TP
124
+ .B \-\-coderay_css ARG
125
+
126
+ Defines how the highlighted code gets styled
127
+
128
+ Possible values are :class (CSS classes are applied to the code
129
+ elements, one must supply the needed CSS file) or :style (default CSS
130
+ styles are directly applied to the code elements).
131
+
132
+ Default: style
133
+ Used by: HTML converter
134
+
135
+
136
+ .TP
137
+ .B \-\-template ARG
138
+
139
+ The name of an ERB template file that should be used to wrap the output
140
+
141
+ This is used to wrap the output in an environment so that the output can
142
+ be used as a stand-alone document. For example, an HTML template would
143
+ provide the needed header and body tags so that the whole output is a
144
+ valid HTML file. If no template is specified, the output will be just
145
+ the converted text.
146
+
147
+ When resolving the template file, the given template name is used first.
148
+ If such a file is not found, the converter extension is appended. If the
149
+ file still cannot be found, the templates name is interpreted as a
150
+ template name that is provided by kramdown (without the converter
151
+ extension).
152
+
153
+ kramdown provides a default template named 'default' for each converter.
154
+
155
+ Default: ''
156
+ Used by: all converters
157
+
158
+
159
+ .TP
160
+ .B \-\-coderay_wrap ARG
161
+
162
+ Defines how the highlighted code should be wrapped
163
+
164
+ The possible values are :span, :div or nil.
165
+
166
+ Default: :div
167
+ Used by: HTML converter
168
+
169
+
170
+ .TP
171
+ .B \-\-[no\-]auto_ids
172
+
173
+ Use automatic header ID generation
174
+
175
+ If this option is `true`, ID values for all headers are automatically
176
+ generated if no ID is explicitly specified.
177
+
178
+ Default: true
179
+ Used by: kramdown parser
180
+
181
+
182
+ .SH SEE ALSO
183
+ The kramdown website, http://kramdown.rubyforge.org/ for more information, especially on the support
184
+ input syntax.
185
+ .SH AUTHOR
186
+ kramdown was written by Thomas Leitner <t_leitner@gmx.at>.
187
+ .PP
188
+ This manual page was written by Thomas Leitner <t_leitner@gmx.at>.
189
+