org-ruby 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +10 -0
- data/README.rdoc +55 -51
- data/lib/org-ruby.rb +1 -1
- data/lib/org-ruby/headline.rb +0 -1
- data/lib/org-ruby/html_output_buffer.rb +201 -214
- data/lib/org-ruby/html_symbol_replace.rb +359 -340
- data/lib/org-ruby/line.rb +79 -24
- data/lib/org-ruby/output_buffer.rb +144 -146
- data/lib/org-ruby/parser.rb +37 -122
- data/lib/org-ruby/regexp_helper.rb +49 -49
- data/lib/org-ruby/textile_output_buffer.rb +91 -44
- data/lib/org-ruby/textile_symbol_replace.rb +360 -341
- metadata +3 -14
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 0.8.0 / 2013-02-10
|
2
|
+
|
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
|
10
|
+
|
1
11
|
== 0.7.2 / 2012-10-07
|
2
12
|
|
3
13
|
* Many fixes to the regular expressions used for emphasis, contributed by [[http://github.com/vonavi][vonavi]]
|
data/README.rdoc
CHANGED
@@ -1,68 +1,72 @@
|
|
1
|
-
org-ruby
|
2
|
-
|
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
|
-
|
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
|
-
|
8
|
-
|
9
|
-
|
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
|
-
==
|
10
|
+
== Installation
|
14
11
|
|
15
|
-
|
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
|
-
* Code syntax highlight of code blocks using Pygments.rb or Coderay when available
|
21
|
-
* Upcoming: Handle export options specified in the org buffer.
|
22
|
-
|
23
|
-
== SYNOPSIS:
|
24
|
-
|
25
|
-
From the command line:
|
26
|
-
|
27
|
-
org-ruby sample.org
|
28
|
-
|
29
|
-
...will output a HTML version of sample.org.
|
30
|
-
|
31
|
-
org-ruby --translate textile sample.org
|
12
|
+
gem install org-ruby
|
32
13
|
|
33
|
-
|
14
|
+
== Usage
|
34
15
|
|
35
16
|
From Ruby code:
|
36
17
|
|
37
|
-
|
18
|
+
require 'org-ruby'
|
19
|
+
|
20
|
+
# Renders HTML
|
21
|
+
Orgmode::Parser.new("* Hello world!).to_html
|
22
|
+
# => "<h1>Hello world!</h1>\n"
|
38
23
|
|
39
|
-
|
24
|
+
# Renders Textile
|
25
|
+
Orgmode::Parser.new("* Hello world!).to_textile
|
26
|
+
# => "h1. Hello world!\n"
|
40
27
|
|
41
|
-
|
28
|
+
It can also be used from the command line:
|
42
29
|
|
43
|
-
|
30
|
+
org-ruby sample.org --translate html
|
44
31
|
|
45
|
-
|
32
|
+
...will output a HTML version of sample.org.
|
46
33
|
|
47
|
-
|
34
|
+
org-ruby --translate textile sample.org
|
48
35
|
|
49
|
-
|
36
|
+
...will output a textile version of sample.org.
|
50
37
|
|
51
|
-
|
52
|
-
a copy of this software and associated documentation files (the
|
53
|
-
'Software'), to deal in the Software without restriction, including
|
54
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
55
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
56
|
-
permit persons to whom the Software is furnished to do so, subject to
|
57
|
-
the following conditions:
|
38
|
+
== Features
|
58
39
|
|
59
|
-
|
60
|
-
|
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
|
61
48
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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.
|
data/lib/org-ruby.rb
CHANGED
data/lib/org-ruby/headline.rb
CHANGED
@@ -15,12 +15,19 @@ module Orgmode
|
|
15
15
|
|
16
16
|
HtmlBlockTag = {
|
17
17
|
:paragraph => "p",
|
18
|
-
:ordered_list => "
|
19
|
-
:unordered_list => "
|
18
|
+
:ordered_list => "ol",
|
19
|
+
:unordered_list => "ul",
|
20
|
+
:list_item => "li",
|
21
|
+
:definition_list => "dl",
|
20
22
|
:definition_term => "dt",
|
21
23
|
:definition_descr => "dd",
|
24
|
+
:table => "table",
|
22
25
|
:table_row => "tr",
|
23
|
-
:
|
26
|
+
:quote => "blockquote",
|
27
|
+
:example => "pre",
|
28
|
+
:src => "pre",
|
29
|
+
:inline_example => "pre",
|
30
|
+
:center => "div",
|
24
31
|
:heading1 => "h1",
|
25
32
|
:heading2 => "h2",
|
26
33
|
:heading3 => "h3",
|
@@ -29,18 +36,6 @@ module Orgmode
|
|
29
36
|
:heading6 => "h6"
|
30
37
|
}
|
31
38
|
|
32
|
-
ModeTag = {
|
33
|
-
:unordered_list => "ul",
|
34
|
-
:ordered_list => "ol",
|
35
|
-
:definition_list => "dl",
|
36
|
-
:table => "table",
|
37
|
-
:blockquote => "blockquote",
|
38
|
-
:example => "pre",
|
39
|
-
:src => "pre",
|
40
|
-
:inline_example => "pre",
|
41
|
-
:center => "div"
|
42
|
-
}
|
43
|
-
|
44
39
|
attr_reader :options
|
45
40
|
|
46
41
|
def initialize(output, opts = {})
|
@@ -50,167 +45,160 @@ module Orgmode
|
|
50
45
|
else
|
51
46
|
@title_decoration = ""
|
52
47
|
end
|
48
|
+
@buffer_tag = "HTML"
|
53
49
|
@options = opts
|
50
|
+
@new_paragraph = :start
|
54
51
|
@footnotes = {}
|
55
52
|
@unclosed_tags = []
|
56
53
|
@logger.debug "HTML export options: #{@options.inspect}"
|
57
54
|
end
|
58
55
|
|
59
56
|
# Output buffer is entering a new mode. Use this opportunity to
|
60
|
-
# write out one of the block tags in the
|
61
|
-
# this information in the HTML stream.
|
62
|
-
def push_mode(mode)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
css_class = " class=\"example\"" if (mode == :example || mode == :inline_example)
|
69
|
-
css_class = " style=\"text-align: center\"" if mode == :center
|
70
|
-
|
71
|
-
unless ((mode == :table and skip_tables?) or
|
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
|
72
65
|
(mode == :src and defined? Pygments))
|
73
|
-
|
74
|
-
|
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 = ""
|
75
86
|
end
|
76
|
-
# Entering a new mode obliterates the title decoration
|
77
|
-
@title_decoration = ""
|
78
87
|
end
|
79
|
-
super(mode)
|
80
88
|
end
|
81
89
|
|
82
90
|
# We are leaving a mode. Close any tags that were opened when
|
83
91
|
# entering this mode.
|
84
92
|
def pop_mode(mode = nil)
|
85
93
|
m = super(mode)
|
86
|
-
if
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
close_floating_li_tags
|
94
|
-
end
|
95
|
-
|
96
|
-
unless ((mode == :table and skip_tables?) or
|
97
|
-
(mode == :src and defined? Pygments))
|
98
|
-
@logger.debug "</#{ModeTag[m]}>\n"
|
99
|
-
@output << "</#{ModeTag[m]}>\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]}>"
|
100
101
|
end
|
101
|
-
|
102
|
-
# In case it was a sublist, close it here
|
103
|
-
close_last_li_tag_maybe
|
104
102
|
end
|
103
|
+
@list_indent_stack.pop
|
105
104
|
end
|
106
105
|
|
107
106
|
def flush!
|
108
|
-
if
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
107
|
+
return false if @buffer.empty?
|
108
|
+
case
|
109
|
+
when preserve_whitespace?
|
110
|
+
strip_code_block! if mode_is_code? current_mode
|
111
|
+
|
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
|
114
127
|
|
115
|
-
#
|
116
|
-
|
128
|
+
# CodeRay might throw a warning when unsupported lang is set,
|
129
|
+
# then fallback to using the text lexer
|
130
|
+
silence_warnings do
|
117
131
|
begin
|
118
|
-
@buffer =
|
119
|
-
rescue
|
120
|
-
|
121
|
-
@buffer = Pygments.highlight(@buffer, :lexer => 'text')
|
122
|
-
end
|
123
|
-
elsif defined? CodeRay
|
124
|
-
# CodeRay might throw a warning when unsupported lang is set,
|
125
|
-
# then fallback to using the text lexer
|
126
|
-
silence_warnings do
|
127
|
-
begin
|
128
|
-
@buffer = CodeRay.scan(@buffer, lang).html(:wrap => nil, :css => :style)
|
129
|
-
rescue ArgumentError
|
130
|
-
@buffer = CodeRay.scan(@buffer, 'text').html(:wrap => nil, :css => :style)
|
131
|
-
end
|
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)
|
132
135
|
end
|
133
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
|
134
140
|
else
|
135
|
-
|
141
|
+
escape_string! @buffer
|
136
142
|
end
|
137
143
|
|
138
|
-
|
144
|
+
# Whitespace is significant in :code mode. Always output the
|
145
|
+
# buffer and do not do any additional translation.
|
146
|
+
@logger.debug "FLUSH CODE ==========> #{@buffer.inspect}"
|
139
147
|
@output << @buffer
|
140
|
-
elsif mode_is_code(@buffer_mode) then
|
141
|
-
escape_buffer!
|
142
148
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
@output << @buffer << "\n"
|
149
|
+
when (mode_is_table? current_mode and skip_tables?)
|
150
|
+
@logger.debug "SKIP ==========> #{current_mode}"
|
151
|
+
|
147
152
|
else
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
@output << "<#{HtmlBlockTag[:definition_descr]}#{@title_decoration}>" << inline_formatting(d[1].strip) \
|
159
|
-
<< "</#{HtmlBlockTag[:definition_descr]}>\n"
|
160
|
-
else
|
161
|
-
@output << "\n"
|
162
|
-
end
|
163
|
-
@title_decoration = ""
|
164
|
-
end
|
165
|
-
elsif @buffer.length > 0 then
|
166
|
-
unless buffer_mode_is_table? and skip_tables?
|
167
|
-
@logger.debug "FLUSH ==========> #{@buffer_mode}"
|
168
|
-
output_indentation
|
169
|
-
if ((@buffered_lines[0].plain_list?) and
|
170
|
-
(@unclosed_tags.count == @list_indent_stack.count))
|
171
|
-
@output << @unclosed_tags.pop
|
172
|
-
output_indentation
|
173
|
-
end
|
174
|
-
@output << "<#{HtmlBlockTag[@output_type]}#{@title_decoration}>"
|
175
|
-
if (@buffered_lines[0].kind_of?(Headline)) then
|
176
|
-
headline = @buffered_lines[0]
|
177
|
-
raise "Cannot be more than one headline!" if @buffered_lines.length > 1
|
178
|
-
if @options[:export_heading_number] then
|
179
|
-
level = headline.level
|
180
|
-
heading_number = get_next_headline_number(level)
|
181
|
-
output << "<span class=\"heading-number heading-number-#{level}\">#{heading_number} </span>"
|
182
|
-
end
|
183
|
-
if @options[:export_todo] and headline.keyword then
|
184
|
-
keyword = headline.keyword
|
185
|
-
output << "<span class=\"todo-keyword #{keyword}\">#{keyword} </span>"
|
186
|
-
end
|
187
|
-
end
|
188
|
-
@output << inline_formatting(@buffer)
|
189
|
-
|
190
|
-
# Only close the list when it is the last element from that list,
|
191
|
-
# or when starting another list
|
192
|
-
if (@output_type == :unordered_list or
|
193
|
-
@output_type == :ordered_list or
|
194
|
-
@output_type == :definition_list) and
|
195
|
-
(not @list_indent_stack.empty?)
|
196
|
-
@unclosed_tags.push("</#{HtmlBlockTag[@output_type]}>\n")
|
197
|
-
@output << "\n"
|
198
|
-
else
|
199
|
-
@output << "</#{HtmlBlockTag[@output_type]}>\n"
|
200
|
-
end
|
201
|
-
@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])
|
202
163
|
else
|
203
|
-
@
|
164
|
+
@output << "???"
|
204
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)
|
205
181
|
end
|
206
182
|
end
|
207
|
-
|
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
|
208
196
|
end
|
209
197
|
|
210
198
|
def output_footnotes!
|
211
199
|
return false unless @options[:export_footnotes] and not @footnotes.empty?
|
212
200
|
|
213
|
-
@output << "<div id=\"footnotes\">\n<h2 class=\"footnotes\">Footnotes
|
201
|
+
@output << "\n<div id=\"footnotes\">\n<h2 class=\"footnotes\">Footnotes:</h2>\n<div id=\"text-footnotes\">\n"
|
214
202
|
|
215
203
|
@footnotes.each do |name, defi|
|
216
204
|
@output << "<p class=\"footnote\"><sup><a class=\"footnum\" name=\"fn.#{name}\" href=\"#fnr.#{name}\">#{name}</a></sup>" \
|
@@ -218,11 +206,15 @@ module Orgmode
|
|
218
206
|
<< "</p>\n"
|
219
207
|
end
|
220
208
|
|
221
|
-
@output << "</div>\n</div
|
209
|
+
@output << "</div>\n</div>"
|
222
210
|
|
223
211
|
return true
|
224
212
|
end
|
225
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
|
226
218
|
|
227
219
|
######################################################################
|
228
220
|
private
|
@@ -231,116 +223,105 @@ module Orgmode
|
|
231
223
|
@options[:skip_tables]
|
232
224
|
end
|
233
225
|
|
234
|
-
def
|
235
|
-
|
226
|
+
def mode_is_table?(mode)
|
227
|
+
(mode == :table or mode == :table_row or
|
228
|
+
mode == :table_separator or mode == :table_header)
|
236
229
|
end
|
237
230
|
|
238
|
-
|
239
|
-
|
231
|
+
# Escapes any HTML content in the output accumulation buffer @buffer.
|
232
|
+
def escape_string! str
|
233
|
+
str.gsub!(/&/, "&")
|
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 "<#{$1}"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
str.gsub! /([^<>\n]*)>/ do |match|
|
242
|
+
if $`[-2..-1] == "@<" then $&
|
243
|
+
else "#{$1}>"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
str.gsub!(/@(<[^<>\n]*>)/, "\\1")
|
240
247
|
end
|
241
248
|
|
242
|
-
|
243
|
-
|
244
|
-
@buffer
|
245
|
-
@buffer.gsub!(/</, "<")
|
246
|
-
@buffer.gsub!(/>/, ">")
|
249
|
+
def buffer_indentation
|
250
|
+
indent = " " * @list_indent_stack.length
|
251
|
+
@buffer << indent
|
247
252
|
end
|
248
253
|
|
249
|
-
def
|
250
|
-
indent = " " * (@
|
251
|
-
@output << indent
|
254
|
+
def add_paragraph
|
255
|
+
indent = " " * (@list_indent_stack.length - 1)
|
256
|
+
@output << "\n" << indent
|
252
257
|
end
|
253
258
|
|
254
259
|
Tags = {
|
255
|
-
"*" => { :open => "
|
256
|
-
"/" => { :open => "
|
257
|
-
"_" => { :open => "
|
258
|
-
:close => "
|
259
|
-
"=" => { :open => "
|
260
|
-
"~" => { :open => "
|
261
|
-
"+" => { :open => "
|
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" }
|
262
267
|
}
|
263
268
|
|
264
269
|
# Applies inline formatting rules to a string.
|
265
270
|
def inline_formatting(str)
|
266
|
-
str
|
267
|
-
|
268
|
-
"#{Tags[marker][:open]}#{s}#{Tags[marker][:close]}"
|
271
|
+
@re_help.rewrite_emphasis str do |marker, s|
|
272
|
+
"@<#{Tags[marker][:open]}>#{s}@</#{Tags[marker][:close]}>"
|
269
273
|
end
|
270
274
|
if @options[:use_sub_superscripts] then
|
271
|
-
|
275
|
+
@re_help.rewrite_subp str do |type, text|
|
272
276
|
if type == "_" then
|
273
|
-
"
|
277
|
+
"@<sub>#{text}@</sub>"
|
274
278
|
elsif type == "^" then
|
275
|
-
"
|
279
|
+
"@<sup>#{text}@</sup>"
|
276
280
|
end
|
277
281
|
end
|
278
282
|
end
|
279
|
-
|
280
|
-
|
281
|
-
end
|
282
|
-
str = @re_help.rewrite_links(str) do |link, text|
|
283
|
-
text ||= link
|
284
|
-
link = link.sub(/^file:(.*)::(.*?)$/) do
|
285
|
-
|
283
|
+
@re_help.rewrite_links str do |link, defi|
|
284
|
+
[link, defi].compact.each do |text|
|
286
285
|
# We don't support search links right now. Get rid of it.
|
287
|
-
|
288
|
-
"
|
289
|
-
|
290
|
-
if link.match(/^file:.*\.org$/)
|
291
|
-
link = link.sub(/\.org$/i, ".html")
|
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)/, "")
|
292
289
|
end
|
293
290
|
|
294
|
-
|
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
|
295
294
|
|
296
|
-
|
297
|
-
"
|
295
|
+
if defi =~ @re_help.org_image_file_regexp
|
296
|
+
defi = "@<img src=\"#{defi}\" alt=\"#{defi}\" />"
|
297
|
+
end
|
298
|
+
|
299
|
+
if defi
|
300
|
+
"@<a href=\"#{link}\">#{defi}@</a>"
|
301
|
+
else
|
302
|
+
"@<img src=\"#{link}\" alt=\"#{link}\" />"
|
298
303
|
end
|
299
|
-
"<a href=\"#{link}\">#{text}</a>"
|
300
304
|
end
|
301
|
-
if
|
302
|
-
str.gsub!(/^\|\s*/, "
|
303
|
-
str.gsub!(/\s*\|$/, "
|
304
|
-
str.gsub!(/\s*\|\s*/, "
|
305
|
+
if @output_type == :table_row
|
306
|
+
str.gsub!(/^\|\s*/, "@<td>")
|
307
|
+
str.gsub!(/\s*\|$/, "@</td>")
|
308
|
+
str.gsub!(/\s*\|\s*/, "@</td>@<td>")
|
305
309
|
end
|
306
|
-
if
|
307
|
-
str.gsub!(/^\|\s*/, "
|
308
|
-
str.gsub!(/\s*\|$/, "
|
309
|
-
str.gsub!(/\s*\|\s*/, "
|
310
|
+
if @output_type == :table_header
|
311
|
+
str.gsub!(/^\|\s*/, "@<th>")
|
312
|
+
str.gsub!(/\s*\|$/, "@</th>")
|
313
|
+
str.gsub!(/\s*\|\s*/, "@</th>@<th>")
|
310
314
|
end
|
311
315
|
if @options[:export_footnotes] then
|
312
|
-
|
316
|
+
@re_help.rewrite_footnote str do |name, defi|
|
313
317
|
# TODO escape name for url?
|
314
318
|
@footnotes[name] = defi if defi
|
315
|
-
"
|
316
|
-
end
|
317
|
-
end
|
318
|
-
Orgmode.special_symbols_to_html(str)
|
319
|
-
str
|
320
|
-
end
|
321
|
-
|
322
|
-
def close_floating_li_tags
|
323
|
-
unless @final_list_node
|
324
|
-
unless @unclosed_tags.empty?
|
325
|
-
@output << " " << @unclosed_tags.pop
|
326
|
-
output_indentation
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
@final_list_node = false
|
331
|
-
end
|
332
|
-
|
333
|
-
def close_last_li_tag_maybe
|
334
|
-
if (@list_indent_stack.count < @unclosed_tags.count) and not
|
335
|
-
(@list_indent_stack.empty? and @unclosed_tags.empty?)
|
336
|
-
output_indentation
|
337
|
-
@output << @unclosed_tags.pop
|
338
|
-
if (@list_indent_stack.count == @unclosed_tags.count) and not
|
339
|
-
(@list_indent_stack.empty? and @unclosed_tags.empty?)
|
340
|
-
@final_list_node = true
|
341
|
-
pop_mode
|
319
|
+
"@<sup>@<a class=\"footref\" name=\"fnr.#{name}\" href=\"#fn.#{name}\">#{name}@</a>@</sup>"
|
342
320
|
end
|
343
321
|
end
|
322
|
+
escape_string! str
|
323
|
+
Orgmode.special_symbols_to_html str
|
324
|
+
str = @re_help.restore_code_snippets str
|
344
325
|
end
|
345
326
|
|
346
327
|
def normalize_lang(lang)
|
@@ -363,5 +344,11 @@ module Orgmode
|
|
363
344
|
ensure
|
364
345
|
$VERBOSE = warn_level
|
365
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
|
366
353
|
end # class HtmlOutputBuffer
|
367
354
|
end # module Orgmode
|