wallyqs-org-ruby 0.6.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/History.txt +41 -11
  2. data/README.rdoc +55 -50
  3. data/bin/org-ruby +11 -5
  4. data/lib/org-ruby.rb +20 -27
  5. data/lib/org-ruby/headline.rb +0 -10
  6. data/lib/org-ruby/html_output_buffer.rb +224 -143
  7. data/lib/org-ruby/html_symbol_replace.rb +359 -340
  8. data/lib/org-ruby/line.rb +91 -30
  9. data/lib/org-ruby/output_buffer.rb +147 -139
  10. data/lib/org-ruby/parser.rb +45 -111
  11. data/lib/org-ruby/regexp_helper.rb +52 -57
  12. data/lib/org-ruby/textile_output_buffer.rb +90 -37
  13. data/lib/org-ruby/textile_symbol_replace.rb +360 -341
  14. metadata +39 -200
  15. data/.bnsignore +0 -18
  16. data/.gitignore +0 -2
  17. data/Gemfile +0 -7
  18. data/Gemfile.lock +0 -36
  19. data/Rakefile +0 -33
  20. data/TAGS +0 -167
  21. data/announcement.txt +0 -24
  22. data/org-ruby.gemspec +0 -40
  23. data/spec/data/freeform-example.org +0 -113
  24. data/spec/data/freeform.org +0 -111
  25. data/spec/data/hyp-planning.org +0 -335
  26. data/spec/data/remember.org +0 -53
  27. data/spec/headline_spec.rb +0 -65
  28. data/spec/html_examples/advanced-code.html +0 -81
  29. data/spec/html_examples/advanced-code.org +0 -106
  30. data/spec/html_examples/advanced-lists.html +0 -31
  31. data/spec/html_examples/advanced-lists.org +0 -31
  32. data/spec/html_examples/block_code.html +0 -28
  33. data/spec/html_examples/block_code.org +0 -35
  34. data/spec/html_examples/blockcomment.html +0 -3
  35. data/spec/html_examples/blockcomment.org +0 -15
  36. data/spec/html_examples/blockquote.html +0 -7
  37. data/spec/html_examples/blockquote.org +0 -13
  38. data/spec/html_examples/center.html +0 -6
  39. data/spec/html_examples/center.org +0 -7
  40. data/spec/html_examples/code-comment.html +0 -18
  41. data/spec/html_examples/code-comment.org +0 -22
  42. data/spec/html_examples/code-syntax.html +0 -98
  43. data/spec/html_examples/code-syntax.org +0 -99
  44. data/spec/html_examples/comment-trees.html +0 -4
  45. data/spec/html_examples/comment-trees.org +0 -13
  46. data/spec/html_examples/custom-seq-todo.html +0 -15
  47. data/spec/html_examples/custom-seq-todo.org +0 -24
  48. data/spec/html_examples/custom-todo.html +0 -15
  49. data/spec/html_examples/custom-todo.org +0 -24
  50. data/spec/html_examples/custom-typ-todo.html +0 -15
  51. data/spec/html_examples/custom-typ-todo.org +0 -24
  52. data/spec/html_examples/deflist.html +0 -6
  53. data/spec/html_examples/deflist.org +0 -6
  54. data/spec/html_examples/entities.html +0 -4
  55. data/spec/html_examples/entities.org +0 -11
  56. data/spec/html_examples/escape-pre.html +0 -6
  57. data/spec/html_examples/escape-pre.org +0 -6
  58. data/spec/html_examples/export-exclude-only.html +0 -13
  59. data/spec/html_examples/export-exclude-only.org +0 -81
  60. data/spec/html_examples/export-keywords.html +0 -4
  61. data/spec/html_examples/export-keywords.org +0 -18
  62. data/spec/html_examples/export-tags.html +0 -8
  63. data/spec/html_examples/export-tags.org +0 -82
  64. data/spec/html_examples/export-title.html +0 -2
  65. data/spec/html_examples/export-title.org +0 -4
  66. data/spec/html_examples/footnotes.html +0 -10
  67. data/spec/html_examples/footnotes.org +0 -7
  68. data/spec/html_examples/html-literal.html +0 -2
  69. data/spec/html_examples/html-literal.org +0 -6
  70. data/spec/html_examples/inline-formatting.html +0 -20
  71. data/spec/html_examples/inline-formatting.org +0 -33
  72. data/spec/html_examples/inline-images.html +0 -10
  73. data/spec/html_examples/inline-images.org +0 -15
  74. data/spec/html_examples/link-features.html +0 -8
  75. data/spec/html_examples/link-features.org +0 -19
  76. data/spec/html_examples/lists.html +0 -23
  77. data/spec/html_examples/lists.org +0 -47
  78. data/spec/html_examples/metadata-comment.html +0 -27
  79. data/spec/html_examples/metadata-comment.org +0 -30
  80. data/spec/html_examples/only-list.html +0 -5
  81. data/spec/html_examples/only-list.org +0 -3
  82. data/spec/html_examples/only-table.html +0 -6
  83. data/spec/html_examples/only-table.org +0 -5
  84. data/spec/html_examples/skip-header.html +0 -3
  85. data/spec/html_examples/skip-header.org +0 -28
  86. data/spec/html_examples/skip-table.html +0 -4
  87. data/spec/html_examples/skip-table.org +0 -19
  88. data/spec/html_examples/subsupscript-nil.html +0 -3
  89. data/spec/html_examples/subsupscript-nil.org +0 -6
  90. data/spec/html_examples/subsupscript.html +0 -3
  91. data/spec/html_examples/subsupscript.org +0 -5
  92. data/spec/html_examples/tables.html +0 -35
  93. data/spec/html_examples/tables.org +0 -50
  94. data/spec/html_examples/text.html +0 -2
  95. data/spec/html_examples/text.org +0 -16
  96. data/spec/line_spec.rb +0 -155
  97. data/spec/output_buffer_spec.rb +0 -19
  98. data/spec/parser_spec.rb +0 -152
  99. data/spec/regexp_helper_spec.rb +0 -57
  100. data/spec/spec_helper.rb +0 -20
  101. data/spec/textile_examples/block_code.org +0 -35
  102. data/spec/textile_examples/block_code.textile +0 -29
  103. data/spec/textile_examples/blockquote.org +0 -13
  104. data/spec/textile_examples/blockquote.textile +0 -11
  105. data/spec/textile_examples/center.org +0 -7
  106. data/spec/textile_examples/center.textile +0 -6
  107. data/spec/textile_examples/footnotes.org +0 -7
  108. data/spec/textile_examples/footnotes.textile +0 -8
  109. data/spec/textile_examples/keywords.org +0 -13
  110. data/spec/textile_examples/keywords.textile +0 -11
  111. data/spec/textile_examples/links.org +0 -11
  112. data/spec/textile_examples/links.textile +0 -10
  113. data/spec/textile_examples/lists.org +0 -36
  114. data/spec/textile_examples/lists.textile +0 -20
  115. data/spec/textile_examples/single-space-plain-list.org +0 -13
  116. data/spec/textile_examples/single-space-plain-list.textile +0 -10
  117. data/spec/textile_examples/tables.org +0 -50
  118. data/spec/textile_examples/tables.textile +0 -40
  119. data/spec/textile_output_buffer_spec.rb +0 -21
  120. data/tasks/test_case.rake +0 -49
  121. data/test/test_orgmode_parser.rb +0 -0
  122. data/util/gen-special-replace.el +0 -37
@@ -1,17 +1,47 @@
1
- == 0.6.1 / 2012-02-25
1
+ == 0.8.0 / 2013-02-10
2
2
 
3
- * Major Enhancements
4
- * Added encoding directive to support Ruby 1.9.2
5
- * Included .org support for Tilt templates (thanks to crnixon)
6
- * #+BEGIN/END_SRC lang code blocks are embedded in code tags with class that specifies the coding language
7
- * CodeRay is used to give code syntax highlight support to #+BEGIN/END_SRC blocks
3
+ * A lot of refactoring work and bugfixes contributed by vonavi (many thanks!)
4
+ * Raw HTML is supported with #+html
5
+ * Code indentation for code blocks is fixed now
6
+ * Support for definition lists is improved
7
+ * Bugfix for when including headlines in center and quote blocks.
8
+ * Indentation of HTML output improved
9
+ * Improvements to entities support for Textile and HTML outputs
8
10
 
9
- * Minor Enhancements
10
- * Angle links in org-mode are embedded in anchor tags on html output
11
- * Headlines with the COMMENT keyword, and the PROPERTIES drawer are not exported
11
+ == 0.7.2 / 2012-10-07
12
12
 
13
- * Bug fixes
14
- * Fixed bug with InlineExampleRegexp when a colon is at the beginning of a block
13
+ * Many fixes to the regular expressions used for emphasis, contributed by [[http://github.com/vonavi][vonavi]]
14
+ * Bug fix for when a table starts with a headline, thanks to [[http://github/til][til]]
15
+ * Asterisk can be used for definition lists too
16
+ * Use text lexer as default option for Pygments and Coderay when no language is specified
17
+
18
+ == 0.7.1 / 2012-08-04
19
+
20
+ * Make source code blocks from lisp dialects use Pygments scheme lexer
21
+ * Bugfix: Make Coderay fallback to text lexer when unsupported lang is set
22
+
23
+ == 0.7.0 / 2012-07-08
24
+
25
+ * Highlight source code blocks using Pygments or CodeRay when available
26
+
27
+ == 0.6.4 / 2012-07-08
28
+
29
+ * Fixed lists behavior when code fragments, tables and examples were present
30
+ * Remove code tags with lang class and use instead src-:lang like org-exporter
31
+ * Fixed property drawers to consider properties with hyphens like :noweb-ref:
32
+
33
+ == 0.6.3 / 2012-05-22
34
+
35
+ * Minor enhancement: Correct handling of .org URIs in HTML markup routine (thanks, rayl)
36
+
37
+ == 0.6.1 / 2012-04-14
38
+
39
+ * Added encoding directive to support Ruby 1.9.2
40
+ * Headlines with the COMMENT keyword, and the PROPERTIES drawer are not exported
41
+ * Angle links in org-mode are embedded in anchor tags on html output
42
+ * #+BEGIN/END_SRC lang code blocks are embedded in code tags with class that specifies the coding language
43
+ * Fixed bug in code blocks when a colon was at the beginning
44
+ * More than five dashes create an horizontal rule in html output
15
45
 
16
46
  == 0.6.0 / 2011-09-03
17
47
 
@@ -1,67 +1,72 @@
1
- org-ruby
2
- by Brian Dewey
3
- http://github.com/bdewey/org-ruby
1
+ = org-ruby
2
+ <em>Originally by Brian Dewey</em> (http://github.com/bdewey/org-ruby)
4
3
 
5
- == DESCRIPTION:
4
+ {<img src="https://secure.travis-ci.org/wallyqs/org-ruby.png?branch=master" alt="Build Status" />}[http://travis-ci.org/wallyqs/org-ruby]
6
5
 
7
- This gem contains Ruby routines for parsing org-mode files.The most
8
- significant thing this library does today is convert org-mode files to
9
- HTML or textile. Currently, you cannot do much to customize the
10
- conversion. The supplied textile conversion is optimized for
11
- extracting "content" from the orgfile as opposed to "metadata."
6
+ An {org-mode}[http://orgmode.org] parser written in Ruby. The most significant thing this library does today is convert org-mode files to HTML or Textile.
7
+ Currently, you cannot do much to customize the conversion. The supplied textile conversion is optimized for extracting
8
+ “content” from the orgfile as opposed to “metadata.”
12
9
 
13
- == FEATURES/PROBLEMS:
10
+ == Installation
14
11
 
15
- * Converts org-mode files to HTML or Textile
16
- * Supports tables, block quotes, and block code
17
- * Supports bold, italic, underline, strikethrough, and code inline formatting.
18
- * Supports hyperlinks that are in double-brackets
19
- * Supports +.org+ views in Rails through Tilt.
20
- * Upcoming: Handle export options specified in the org buffer.
21
-
22
- == SYNOPSIS:
12
+ gem install org-ruby
23
13
 
24
- From the command line:
25
-
26
- org-ruby sample.org
27
-
28
- ...will output a HTML version of sample.org.
29
-
30
- org-ruby --translate textile sample.org
31
-
32
- ...will output a textile version of sample.org.
14
+ == Usage
33
15
 
34
16
  From Ruby code:
35
17
 
36
- Orgmode::Parser.new(data)
18
+ require 'org-ruby'
37
19
 
38
- ...will construct a new +Parser+ object.
20
+ # Renders HTML
21
+ Orgmode::Parser.new("* Hello world!).to_html
22
+ # => "<h1>Hello world!</h1>\n"
39
23
 
40
- == INSTALL:
24
+ # Renders Textile
25
+ Orgmode::Parser.new("* Hello world!).to_textile
26
+ # => "h1. Hello world!\n"
41
27
 
42
- sudo gem install org-ruby
28
+ It can also be used from the command line:
43
29
 
44
- == LICENSE:
30
+ org-ruby sample.org --translate html
45
31
 
46
- (The MIT License)
32
+ ...will output a HTML version of sample.org.
47
33
 
48
- Copyright (c) 2009 Brian Dewey
34
+ org-ruby --translate textile sample.org
49
35
 
50
- Permission is hereby granted, free of charge, to any person obtaining
51
- a copy of this software and associated documentation files (the
52
- 'Software'), to deal in the Software without restriction, including
53
- without limitation the rights to use, copy, modify, merge, publish,
54
- distribute, sublicense, and/or sell copies of the Software, and to
55
- permit persons to whom the Software is furnished to do so, subject to
56
- the following conditions:
36
+ ...will output a textile version of sample.org.
57
37
 
58
- The above copyright notice and this permission notice shall be
59
- included in all copies or substantial portions of the Software.
38
+ == Features
60
39
 
61
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
62
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
63
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
64
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
65
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
66
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
67
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40
+ * Converts org-mode files to HTML or Textile
41
+ * Supports tables, block quotes, code blocks, and html blocks
42
+ * Supports bold, italic, underline, strikethrough, and code inline formatting.
43
+ * Supports hyperlinks that are in double-brackets
44
+ * Supports definition lists
45
+ * Supports footnotes
46
+ * Supports +.org+ views in Rails through Tilt.
47
+ * Code syntax highlight of code blocks using Pygments.rb or Coderay when available
48
+
49
+ == License
50
+
51
+ (The MIT License)
52
+
53
+ Copyright (c) 2009 Brian Dewey
54
+
55
+ Permission is hereby granted, free of charge, to any person obtaining
56
+ a copy of this software and associated documentation files (the
57
+ 'Software'), to deal in the Software without restriction, including
58
+ without limitation the rights to use, copy, modify, merge, publish,
59
+ distribute, sublicense, and/or sell copies of the Software, and to
60
+ permit persons to whom the Software is furnished to do so, subject to
61
+ the following conditions:
62
+
63
+ The above copyright notice and this permission notice shall be
64
+ included in all copies or substantial portions of the Software.
65
+
66
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
67
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
68
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
69
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
70
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
71
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
72
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,11 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- require File.expand_path(
4
- File.join(File.dirname(__FILE__), %w[.. lib org-ruby]))
2
+ require 'org-ruby'
5
3
  require 'optparse'
6
4
 
7
- # Put your code here
8
-
9
5
  options = {}
10
6
  options_parser = OptionParser.new do |opts|
11
7
  options[:help] = false
@@ -25,10 +21,20 @@ options_parser = OptionParser.new do |opts|
25
21
  "Translate the ORG file to the specified format.") do |v|
26
22
  options[:format] = v
27
23
  end
24
+
25
+ opts.on("-v", "--version", "Print version") do |v|
26
+ options[:version] = true
27
+ end
28
28
  end
29
29
 
30
30
  begin
31
31
  options_parser.parse!
32
+
33
+ if options[:version]
34
+ puts OrgRuby::VERSION
35
+ exit
36
+ end
37
+
32
38
  if (ARGV.length == 0) then
33
39
  puts options_parser
34
40
  else
@@ -1,14 +1,27 @@
1
- unless defined? ::OrgRuby
1
+ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
2
2
 
3
- # Default to UTF-8 in Ruby 1.9 rather than ASCII
4
- if defined? Encoding and Encoding.respond_to? 'default_external='
5
- Encoding.default_external = Encoding.default_internal = Encoding::UTF_8
6
- end
3
+ # internal requires
4
+ require 'org-ruby/parser'
5
+ require 'org-ruby/regexp_helper'
6
+ require 'org-ruby/line'
7
+ require 'org-ruby/headline'
8
+ require 'org-ruby/output_buffer'
9
+
10
+ # HTML exporter
11
+ require 'org-ruby/html_output_buffer'
12
+ require 'org-ruby/html_symbol_replace'
13
+
14
+ # Textile exporter
15
+ require 'org-ruby/textile_output_buffer'
16
+ require 'org-ruby/textile_symbol_replace'
17
+
18
+ # Tilt support
19
+ require 'org-ruby/tilt'
7
20
 
8
21
  module OrgRuby
9
22
 
10
23
  # :stopdoc:
11
- VERSION = '0.6.1'
24
+ VERSION = '0.8.0'
12
25
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
13
26
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
14
27
  # :startdoc:
@@ -19,22 +32,6 @@ module OrgRuby
19
32
  VERSION
20
33
  end
21
34
 
22
- # Returns the library path for the module. If any arguments are given,
23
- # they will be joined to the end of the libray path using
24
- # <tt>File.join</tt>.
25
- #
26
- def self.libpath( *args )
27
- args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
28
- end
29
-
30
- # Returns the lpath for the module. If any arguments are given,
31
- # they will be joined to the end of the path using
32
- # <tt>File.join</tt>.
33
- #
34
- def self.path( *args )
35
- args.empty? ? PATH : ::File.join(PATH, args.flatten)
36
- end
37
-
38
35
  # Utility method used to require all files ending in .rb that lie in the
39
36
  # directory below this file that has the same name as the filename passed
40
37
  # in. Optionally, a specific _directory_ name can be passed in such that
@@ -48,8 +45,4 @@ module OrgRuby
48
45
  Dir.glob(search_me).sort.each {|rb| require rb}
49
46
  end
50
47
 
51
- end # module OrgmodeParser
52
-
53
- OrgRuby.require_all_libs_relative_to(__FILE__)
54
-
55
- end # unless defined?
48
+ end
@@ -1,5 +1,3 @@
1
- require OrgRuby.libpath(*%w[org-ruby line])
2
-
3
1
  module Orgmode
4
2
 
5
3
  # Represents a headline in an orgmode file.
@@ -47,7 +45,6 @@ module Orgmode
47
45
  def initialize(line, parser = nil, offset=0)
48
46
  super(line, parser)
49
47
  @body_lines = []
50
- @body_lines << self # Make @body_lines contain the headline?
51
48
  @tags = []
52
49
  @export_state = :exclude
53
50
  if (@line =~ LineRegexp) then
@@ -87,13 +84,6 @@ module Orgmode
87
84
  :"heading#{@level}"
88
85
  end
89
86
 
90
- # Converts this headline and its body to textile.
91
- def to_textile
92
- output = "h#{@level}. #{@headline_text}\n"
93
- output << Line.to_textile(@body_lines[1..-1])
94
- output
95
- end
96
-
97
87
  ######################################################################
98
88
  private
99
89
 
@@ -1,10 +1,12 @@
1
- require OrgRuby.libpath(*%w[org-ruby html_symbol_replace])
2
- require OrgRuby.libpath(*%w[org-ruby output_buffer])
3
-
4
1
  begin
5
- require 'coderay'
2
+ require 'pygments'
6
3
  rescue LoadError
7
- # CodeRay is not supported
4
+ # Pygments is not supported so we try instead with CodeRay
5
+ begin
6
+ require 'coderay'
7
+ rescue LoadError
8
+ # No code syntax highlighting
9
+ end
8
10
  end
9
11
 
10
12
  module Orgmode
@@ -13,12 +15,19 @@ module Orgmode
13
15
 
14
16
  HtmlBlockTag = {
15
17
  :paragraph => "p",
16
- :ordered_list => "li",
17
- :unordered_list => "li",
18
+ :ordered_list => "ol",
19
+ :unordered_list => "ul",
20
+ :list_item => "li",
21
+ :definition_list => "dl",
18
22
  :definition_term => "dt",
19
23
  :definition_descr => "dd",
24
+ :table => "table",
20
25
  :table_row => "tr",
21
- :table_header => "tr",
26
+ :quote => "blockquote",
27
+ :example => "pre",
28
+ :src => "pre",
29
+ :inline_example => "pre",
30
+ :center => "div",
22
31
  :heading1 => "h1",
23
32
  :heading2 => "h2",
24
33
  :heading3 => "h3",
@@ -27,18 +36,6 @@ module Orgmode
27
36
  :heading6 => "h6"
28
37
  }
29
38
 
30
- ModeTag = {
31
- :unordered_list => "ul",
32
- :ordered_list => "ol",
33
- :definition_list => "dl",
34
- :table => "table",
35
- :blockquote => "blockquote",
36
- :example => "pre",
37
- :src => "pre",
38
- :inline_example => "pre",
39
- :center => "div"
40
- }
41
-
42
39
  attr_reader :options
43
40
 
44
41
  def initialize(output, opts = {})
@@ -48,118 +45,160 @@ module Orgmode
48
45
  else
49
46
  @title_decoration = ""
50
47
  end
48
+ @buffer_tag = "HTML"
51
49
  @options = opts
50
+ @new_paragraph = :start
52
51
  @footnotes = {}
52
+ @unclosed_tags = []
53
53
  @logger.debug "HTML export options: #{@options.inspect}"
54
54
  end
55
55
 
56
56
  # Output buffer is entering a new mode. Use this opportunity to
57
- # write out one of the block tags in the ModeTag constant to put
58
- # this information in the HTML stream.
59
- def push_mode(mode)
60
- if ModeTag[mode] then
61
- output_indentation
62
- css_class = ""
63
- css_class = " class=\"src\"" if mode == :src
64
- css_class = " class=\"example\"" if (mode == :example || mode == :inline_example)
65
- css_class = " style=\"text-align: center\"" if mode == :center
66
- @logger.debug "#{mode}: <#{ModeTag[mode]}#{css_class}>\n"
67
- @output << "<#{ModeTag[mode]}#{css_class}>\n" unless mode == :table and skip_tables?
68
- # Special case to add code tags to src blogs and specify language
69
- if mode == :src
70
- @logger.debug "<code class=\"#{@block_lang}\">\n"
71
- @output << "<code class=\"#{@block_lang}\">\n"
57
+ # write out one of the block tags in the HtmlBlockTag constant to
58
+ # put this information in the HTML stream.
59
+ def push_mode(mode, indent)
60
+ super(mode)
61
+ @list_indent_stack.push(indent)
62
+
63
+ if HtmlBlockTag[mode]
64
+ unless ((mode_is_table?(mode) and skip_tables?) or
65
+ (mode == :src and defined? Pygments))
66
+ css_class = case
67
+ when (mode == :src and @block_lang.empty?)
68
+ " class=\"src\""
69
+ when (mode == :src and not @block_lang.empty?)
70
+ " class=\"src src-#{@block_lang}\""
71
+ when (mode == :example || mode == :inline_example)
72
+ " class=\"example\""
73
+ when mode == :center
74
+ " style=\"text-align: center\""
75
+ else
76
+ @title_decoration
77
+ end
78
+
79
+ add_paragraph unless @new_paragraph == :start
80
+ @new_paragraph = true
81
+
82
+ @logger.debug "#{mode}: <#{HtmlBlockTag[mode]}#{css_class}>"
83
+ @output << "<#{HtmlBlockTag[mode]}#{css_class}>"
84
+ # Entering a new mode obliterates the title decoration
85
+ @title_decoration = ""
72
86
  end
73
- # Entering a new mode obliterates the title decoration
74
- @title_decoration = ""
75
87
  end
76
- super(mode)
77
88
  end
78
89
 
79
90
  # We are leaving a mode. Close any tags that were opened when
80
91
  # entering this mode.
81
92
  def pop_mode(mode = nil)
82
93
  m = super(mode)
83
- if ModeTag[m] then
84
- output_indentation
85
- if mode == :src
86
- @logger.debug "</code>\n"
87
- @output << "</code>\n"
94
+ if HtmlBlockTag[m]
95
+ unless ((mode_is_table?(m) and skip_tables?) or
96
+ (m == :src and defined? Pygments))
97
+ add_paragraph if @new_paragraph
98
+ @new_paragraph = true
99
+ @logger.debug "</#{HtmlBlockTag[m]}>"
100
+ @output << "</#{HtmlBlockTag[m]}>"
88
101
  end
89
- @logger.debug "</#{ModeTag[m]}>\n"
90
- @output << "</#{ModeTag[m]}>\n" unless mode == :table and skip_tables?
91
102
  end
103
+ @list_indent_stack.pop
92
104
  end
93
105
 
94
106
  def flush!
95
- if mode_is_code(@buffer_mode) then
96
- # Only colorize #+BEGIN_SRC blocks with a specified language,
97
- # CodeRay already escapes the html once
98
- if @buffer_mode == :src and @block_lang != "" and defined?(CodeRay)
99
- @logger.debug "Applying syntax coloring for: #{@block_lang}"
107
+ return false if @buffer.empty?
108
+ case
109
+ when preserve_whitespace?
110
+ strip_code_block! if mode_is_code? current_mode
100
111
 
101
- # Also suppress CodeRay warning message when it cannot find the language alias
112
+ # NOTE: CodeRay and Pygments already escape the html once, so
113
+ # no need to escape_string!(@buffer)
114
+ case
115
+ when (current_mode == :src and defined? Pygments)
116
+ lang = normalize_lang @block_lang
117
+ @output << "\n" unless @new_paragraph == :start
118
+
119
+ begin
120
+ @buffer = Pygments.highlight(@buffer, :lexer => lang)
121
+ rescue
122
+ # Not supported lexer from Pygments, we fallback on using the text lexer
123
+ @buffer = Pygments.highlight(@buffer, :lexer => 'text')
124
+ end
125
+ when (current_mode == :src and defined? CodeRay)
126
+ lang = normalize_lang @block_lang
127
+
128
+ # CodeRay might throw a warning when unsupported lang is set,
129
+ # then fallback to using the text lexer
102
130
  silence_warnings do
103
- @buffer = CodeRay.scan(@buffer, @block_lang.to_s).html(:wrap => nil, :css => :style)
131
+ begin
132
+ @buffer = CodeRay.scan(@buffer, lang).html(:wrap => nil, :css => :style)
133
+ rescue ArgumentError
134
+ @buffer = CodeRay.scan(@buffer, 'text').html(:wrap => nil, :css => :style)
135
+ end
104
136
  end
137
+ when (current_mode == :html or current_mode == :raw_text)
138
+ @buffer.gsub!(/\A\n/, "") if @new_paragraph == :start
139
+ @new_paragraph = true
105
140
  else
106
- escape_buffer!
141
+ escape_string! @buffer
107
142
  end
108
143
 
109
- # Whitespace is significant in :code mode. Always output the buffer
110
- # and do not do any additional translation.
144
+ # Whitespace is significant in :code mode. Always output the
145
+ # buffer and do not do any additional translation.
111
146
  @logger.debug "FLUSH CODE ==========> #{@buffer.inspect}"
147
+ @output << @buffer
148
+
149
+ when (mode_is_table? current_mode and skip_tables?)
150
+ @logger.debug "SKIP ==========> #{current_mode}"
112
151
 
113
- @output << @buffer << "\n"
114
152
  else
115
- escape_buffer!
116
- if @buffer.length > 0 and @output_type == :definition_list then
117
- unless buffer_mode_is_table? and skip_tables?
118
- output_indentation
119
- d = @buffer.split("::", 2)
120
- @output << "<#{HtmlBlockTag[:definition_term]}#{@title_decoration}>" << inline_formatting(d[0].strip) \
121
- << "</#{HtmlBlockTag[:definition_term]}>"
122
- if d.length > 1 then
123
- @output << "<#{HtmlBlockTag[:definition_descr]}#{@title_decoration}>" << inline_formatting(d[1].strip) \
124
- << "</#{HtmlBlockTag[:definition_descr]}>\n"
125
- else
126
- @output << "\n"
127
- end
128
- @title_decoration = ""
129
- end
130
- elsif @buffer.length > 0 then
131
- unless buffer_mode_is_table? and skip_tables?
132
- @logger.debug "FLUSH ==========> #{@buffer_mode}"
133
- output_indentation
134
- @output << "<#{HtmlBlockTag[@output_type]}#{@title_decoration}>"
135
- if (@buffered_lines[0].kind_of?(Headline)) then
136
- headline = @buffered_lines[0]
137
- raise "Cannot be more than one headline!" if @buffered_lines.length > 1
138
- if @options[:export_heading_number] then
139
- level = headline.level
140
- heading_number = get_next_headline_number(level)
141
- output << "<span class=\"heading-number heading-number-#{level}\">#{heading_number} </span>"
142
- end
143
- if @options[:export_todo] and headline.keyword then
144
- keyword = headline.keyword
145
- output << "<span class=\"todo-keyword #{keyword}\">#{keyword} </span>"
146
- end
147
- end
148
- @output << inline_formatting(@buffer)
149
- @output << "</#{HtmlBlockTag[@output_type]}>\n"
150
- @title_decoration = ""
153
+ @buffer.lstrip!
154
+ @new_paragraph = nil
155
+ @logger.debug "FLUSH ==========> #{current_mode}"
156
+
157
+ case current_mode
158
+ when :definition_term
159
+ d = @buffer.split(/\A(.*[ \t]+|)::(|[ \t]+.*?)$/, 4)
160
+ d[1] = d[1].strip
161
+ unless d[1].empty?
162
+ @output << inline_formatting(d[1])
151
163
  else
152
- @logger.debug "SKIP ==========> #{@buffer_mode}"
164
+ @output << "???"
153
165
  end
166
+ indent = @list_indent_stack.last
167
+ pop_mode
168
+
169
+ @new_paragraph = :start
170
+ push_mode(:definition_descr, indent)
171
+ @output << inline_formatting(d[2].strip + d[3])
172
+ @new_paragraph = nil
173
+
174
+ when :horizontal_rule
175
+ add_paragraph unless @new_paragraph == :start
176
+ @new_paragraph = true
177
+ @output << "<hr />"
178
+
179
+ else
180
+ @output << inline_formatting(@buffer)
154
181
  end
155
182
  end
156
- clear_accumulation_buffer!
183
+ @buffer = ""
184
+ end
185
+
186
+ def add_line_attributes headline
187
+ if @options[:export_heading_number] then
188
+ level = headline.level
189
+ heading_number = get_next_headline_number(level)
190
+ @output << "<span class=\"heading-number heading-number-#{level}\">#{heading_number}</span> "
191
+ end
192
+ if @options[:export_todo] and headline.keyword then
193
+ keyword = headline.keyword
194
+ @output << "<span class=\"todo-keyword #{keyword}\">#{keyword}</span> "
195
+ end
157
196
  end
158
197
 
159
198
  def output_footnotes!
160
199
  return false unless @options[:export_footnotes] and not @footnotes.empty?
161
200
 
162
- @output << "<div id=\"footnotes\">\n<h2 class=\"footnotes\">Footnotes: </h2>\n<div id=\"text-footnotes\">\n"
201
+ @output << "\n<div id=\"footnotes\">\n<h2 class=\"footnotes\">Footnotes:</h2>\n<div id=\"text-footnotes\">\n"
163
202
 
164
203
  @footnotes.each do |name, defi|
165
204
  @output << "<p class=\"footnote\"><sup><a class=\"footnum\" name=\"fn.#{name}\" href=\"#fnr.#{name}\">#{name}</a></sup>" \
@@ -167,11 +206,15 @@ module Orgmode
167
206
  << "</p>\n"
168
207
  end
169
208
 
170
- @output << "</div>\n</div>\n"
209
+ @output << "</div>\n</div>"
171
210
 
172
211
  return true
173
212
  end
174
213
 
214
+ # Test if we're in an output mode in which whitespace is significant.
215
+ def preserve_whitespace?
216
+ super or current_mode == :html
217
+ end
175
218
 
176
219
  ######################################################################
177
220
  private
@@ -180,84 +223,116 @@ module Orgmode
180
223
  @options[:skip_tables]
181
224
  end
182
225
 
183
- def buffer_mode_is_table?
184
- @buffer_mode == :table
226
+ def mode_is_table?(mode)
227
+ (mode == :table or mode == :table_row or
228
+ mode == :table_separator or mode == :table_header)
185
229
  end
186
230
 
187
231
  # Escapes any HTML content in the output accumulation buffer @buffer.
188
- def escape_buffer!
189
- @buffer.gsub!(/&/, "&amp;")
190
- @buffer.gsub!(/</, "&lt;")
191
- @buffer.gsub!(/>/, "&gt;")
232
+ def escape_string! str
233
+ str.gsub!(/&/, "&amp;")
234
+ # Escapes the left and right angular brackets but construction
235
+ # @<text> which is formatted to <text>
236
+ str.gsub! /<([^<>\n]*)/ do |match|
237
+ if $`[-1..-1] == "@" and $'[0..0] == ">" then $&
238
+ else "&lt;#{$1}"
239
+ end
240
+ end
241
+ str.gsub! /([^<>\n]*)>/ do |match|
242
+ if $`[-2..-1] == "@<" then $&
243
+ else "#{$1}&gt;"
244
+ end
245
+ end
246
+ str.gsub!(/@(<[^<>\n]*>)/, "\\1")
192
247
  end
193
248
 
194
- def output_indentation
195
- indent = " " * (@mode_stack.length - 1)
196
- @output << indent
249
+ def buffer_indentation
250
+ indent = " " * @list_indent_stack.length
251
+ @buffer << indent
252
+ end
253
+
254
+ def add_paragraph
255
+ indent = " " * (@list_indent_stack.length - 1)
256
+ @output << "\n" << indent
197
257
  end
198
258
 
199
259
  Tags = {
200
- "*" => { :open => "<b>", :close => "</b>" },
201
- "/" => { :open => "<i>", :close => "</i>" },
202
- "_" => { :open => "<span style=\"text-decoration:underline;\">",
203
- :close => "</span>" },
204
- "=" => { :open => "<code>", :close => "</code>" },
205
- "~" => { :open => "<code>", :close => "</code>" },
206
- "+" => { :open => "<del>", :close => "</del>" }
260
+ "*" => { :open => "b", :close => "b" },
261
+ "/" => { :open => "i", :close => "i" },
262
+ "_" => { :open => "span style=\"text-decoration:underline;\"",
263
+ :close => "span" },
264
+ "=" => { :open => "code", :close => "code" },
265
+ "~" => { :open => "code", :close => "code" },
266
+ "+" => { :open => "del", :close => "del" }
207
267
  }
208
268
 
209
269
  # Applies inline formatting rules to a string.
210
270
  def inline_formatting(str)
211
- str.rstrip!
212
- str = @re_help.rewrite_emphasis(str) do |marker, s|
213
- "#{Tags[marker][:open]}#{s}#{Tags[marker][:close]}"
271
+ @re_help.rewrite_emphasis str do |marker, s|
272
+ "@<#{Tags[marker][:open]}>#{s}@</#{Tags[marker][:close]}>"
214
273
  end
215
274
  if @options[:use_sub_superscripts] then
216
- str = @re_help.rewrite_subp(str) do |type, text|
275
+ @re_help.rewrite_subp str do |type, text|
217
276
  if type == "_" then
218
- "<sub>#{text}</sub>"
277
+ "@<sub>#{text}@</sub>"
219
278
  elsif type == "^" then
220
- "<sup>#{text}</sup>"
279
+ "@<sup>#{text}@</sup>"
221
280
  end
222
281
  end
223
282
  end
224
- str = @re_help.rewrite_images(str) do |link|
225
- "<a href=\"#{link}\"><img src=\"#{link}\" /></a>"
226
- end
227
- str = @re_help.rewrite_links(str) do |link, text|
228
- text ||= link
229
- link = link.sub(/^file:(.*)::(.*?)$/) do
230
-
283
+ @re_help.rewrite_links str do |link, defi|
284
+ [link, defi].compact.each do |text|
231
285
  # We don't support search links right now. Get rid of it.
286
+ text.sub!(/\A(file:[^\s]+)::[^\s]*?\Z/, "\\1")
287
+ text.sub!(/\A(file:[^\s]+)\.org\Z/i, "\\1.html")
288
+ text.sub!(/\Afile:(?=[^\s]+\Z)/, "")
289
+ end
290
+
291
+ # We don't add a description for images in links, because its
292
+ # empty value forces the image to be inlined.
293
+ defi ||= link unless link =~ @re_help.org_image_file_regexp
232
294
 
233
- "file:#{$1}"
295
+ if defi =~ @re_help.org_image_file_regexp
296
+ defi = "@<img src=\"#{defi}\" alt=\"#{defi}\" />"
234
297
  end
235
- link = link.sub(/^file:/i, "") # will default to HTTP
236
- link = link.sub(/\.org$/i, ".html")
237
- text = text.gsub(/([^\]]*\.(jpg|jpeg|gif|png))/xi) do |img_link|
238
- "<img src=\"#{img_link}\" />"
298
+
299
+ if defi
300
+ "@<a href=\"#{link}\">#{defi}@</a>"
301
+ else
302
+ "@<img src=\"#{link}\" alt=\"#{link}\" />"
239
303
  end
240
- "<a href=\"#{link}\">#{text}</a>"
241
304
  end
242
- if (@output_type == :table_row) then
243
- str.gsub!(/^\|\s*/, "<td>")
244
- str.gsub!(/\s*\|$/, "</td>")
245
- str.gsub!(/\s*\|\s*/, "</td><td>")
305
+ if @output_type == :table_row
306
+ str.gsub!(/^\|\s*/, "@<td>")
307
+ str.gsub!(/\s*\|$/, "@</td>")
308
+ str.gsub!(/\s*\|\s*/, "@</td>@<td>")
246
309
  end
247
- if (@output_type == :table_header) then
248
- str.gsub!(/^\|\s*/, "<th>")
249
- str.gsub!(/\s*\|$/, "</th>")
250
- str.gsub!(/\s*\|\s*/, "</th><th>")
310
+ if @output_type == :table_header
311
+ str.gsub!(/^\|\s*/, "@<th>")
312
+ str.gsub!(/\s*\|$/, "@</th>")
313
+ str.gsub!(/\s*\|\s*/, "@</th>@<th>")
251
314
  end
252
315
  if @options[:export_footnotes] then
253
- str = @re_help.rewrite_footnote(str) do |name, defi|
316
+ @re_help.rewrite_footnote str do |name, defi|
254
317
  # TODO escape name for url?
255
318
  @footnotes[name] = defi if defi
256
- "<sup><a class=\"footref\" name=\"fnr.#{name}\" href=\"#fn.#{name}\">#{name}</a></sup>"
319
+ "@<sup>@<a class=\"footref\" name=\"fnr.#{name}\" href=\"#fn.#{name}\">#{name}@</a>@</sup>"
257
320
  end
258
321
  end
259
- Orgmode.special_symbols_to_html(str)
260
- str
322
+ escape_string! str
323
+ Orgmode.special_symbols_to_html str
324
+ str = @re_help.restore_code_snippets str
325
+ end
326
+
327
+ def normalize_lang(lang)
328
+ case lang
329
+ when 'emacs-lisp', 'common-lisp', 'lisp'
330
+ 'scheme'
331
+ when ''
332
+ 'text'
333
+ else
334
+ lang
335
+ end
261
336
  end
262
337
 
263
338
  # Helper method taken from Rails
@@ -269,5 +344,11 @@ module Orgmode
269
344
  ensure
270
345
  $VERBOSE = warn_level
271
346
  end
347
+
348
+ def strip_code_block!
349
+ strip_regexp = Regexp.new("^" + " " * @code_block_indent)
350
+ @buffer.gsub!(strip_regexp, "")
351
+ @code_block_indent = nil
352
+ end
272
353
  end # class HtmlOutputBuffer
273
354
  end # module Orgmode