RedCloth 3.0.4 → 4.0.0

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

Potentially problematic release.


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

Files changed (63) hide show
  1. data/CHANGELOG +17 -0
  2. data/COPYING +18 -0
  3. data/README +156 -0
  4. data/Rakefile +238 -0
  5. data/bin/redcloth +27 -2
  6. data/ext/redcloth_scan/extconf.rb +9 -0
  7. data/ext/redcloth_scan/redcloth.h +149 -0
  8. data/ext/redcloth_scan/redcloth_attributes.c +650 -0
  9. data/ext/redcloth_scan/redcloth_attributes.rl +78 -0
  10. data/ext/redcloth_scan/redcloth_common.rl +113 -0
  11. data/ext/redcloth_scan/redcloth_inline.c +5102 -0
  12. data/ext/redcloth_scan/redcloth_inline.rl +282 -0
  13. data/ext/redcloth_scan/redcloth_scan.c +9300 -0
  14. data/ext/redcloth_scan/redcloth_scan.rl +523 -0
  15. data/extras/mingw-rbconfig.rb +176 -0
  16. data/extras/ragel_profiler.rb +73 -0
  17. data/lib/redcloth.rb +22 -1128
  18. data/lib/redcloth/formatters/base.rb +50 -0
  19. data/lib/redcloth/formatters/html.rb +342 -0
  20. data/lib/redcloth/formatters/latex.rb +227 -0
  21. data/lib/redcloth/formatters/latex_entities.yml +2414 -0
  22. data/lib/redcloth/textile_doc.rb +105 -0
  23. data/lib/redcloth/version.rb +18 -0
  24. data/test/basic.yml +794 -0
  25. data/test/code.yml +195 -0
  26. data/test/definitions.yml +71 -0
  27. data/test/extra_whitespace.yml +64 -0
  28. data/test/filter_html.yml +177 -0
  29. data/test/filter_pba.yml +12 -0
  30. data/test/helper.rb +108 -0
  31. data/test/html.yml +271 -0
  32. data/test/images.yml +202 -0
  33. data/{tests → test}/instiki.yml +14 -15
  34. data/test/links.yml +214 -0
  35. data/test/lists.yml +283 -0
  36. data/test/poignant.yml +89 -0
  37. data/test/sanitize_html.yml +42 -0
  38. data/test/table.yml +267 -0
  39. data/test/test_custom_tags.rb +46 -0
  40. data/test/test_extensions.rb +31 -0
  41. data/test/test_formatters.rb +15 -0
  42. data/test/test_parser.rb +68 -0
  43. data/test/test_restrictions.rb +41 -0
  44. data/test/textism.yml +480 -0
  45. data/test/threshold.yml +772 -0
  46. data/test/validate_fixtures.rb +73 -0
  47. metadata +94 -60
  48. data/doc/CHANGELOG +0 -160
  49. data/doc/COPYING +0 -25
  50. data/doc/README +0 -106
  51. data/doc/REFERENCE +0 -216
  52. data/doc/make.rb +0 -359
  53. data/run-tests.rb +0 -28
  54. data/setup.rb +0 -1376
  55. data/tests/code.yml +0 -105
  56. data/tests/hard_breaks.yml +0 -26
  57. data/tests/images.yml +0 -171
  58. data/tests/links.yml +0 -155
  59. data/tests/lists.yml +0 -77
  60. data/tests/markdown.yml +0 -218
  61. data/tests/poignant.yml +0 -64
  62. data/tests/table.yml +0 -198
  63. data/tests/textism.yml +0 -406
@@ -0,0 +1,176 @@
1
+
2
+ # This rbconfig.rb corresponds to a Ruby installation for win32 cross-compiled
3
+ # with mingw under i686-linux. It can be used to cross-compile extensions for
4
+ # win32 using said toolchain.
5
+ #
6
+ # This file assumes that a cross-compiled mingw32 build (compatible with the
7
+ # mswin32 builds) is installed under $HOME/ruby-mingw32.
8
+
9
+ module Config
10
+ #RUBY_VERSION == "1.8.5" or
11
+ # raise "ruby lib version (1.8.5) doesn't match executable version (#{RUBY_VERSION})"
12
+
13
+ mingw32 = ENV['MINGW32_RUBY'] || "#{ENV["HOME"]}/ruby-mingw32"
14
+ mingwpre = ENV['MINGW32_PREFIX']
15
+ TOPDIR = File.dirname(__FILE__).chomp!("/lib/ruby/1.8/i386-mingw32")
16
+ DESTDIR = '' unless defined? DESTDIR
17
+ CONFIG = {}
18
+ CONFIG["DESTDIR"] = DESTDIR
19
+ CONFIG["INSTALL"] = "/usr/bin/install -c"
20
+ CONFIG["prefix"] = (TOPDIR || DESTDIR + mingw32)
21
+ CONFIG["EXEEXT"] = ".exe"
22
+ CONFIG["ruby_install_name"] = "ruby"
23
+ CONFIG["RUBY_INSTALL_NAME"] = "ruby"
24
+ CONFIG["RUBY_SO_NAME"] = "msvcrt-ruby18"
25
+ CONFIG["SHELL"] = "/bin/sh"
26
+ CONFIG["PATH_SEPARATOR"] = ":"
27
+ CONFIG["PACKAGE_NAME"] = ""
28
+ CONFIG["PACKAGE_TARNAME"] = ""
29
+ CONFIG["PACKAGE_VERSION"] = ""
30
+ CONFIG["PACKAGE_STRING"] = ""
31
+ CONFIG["PACKAGE_BUGREPORT"] = ""
32
+ CONFIG["exec_prefix"] = "$(prefix)"
33
+ CONFIG["bindir"] = "$(exec_prefix)/bin"
34
+ CONFIG["sbindir"] = "$(exec_prefix)/sbin"
35
+ CONFIG["libexecdir"] = "$(exec_prefix)/libexec"
36
+ CONFIG["datadir"] = "$(prefix)/share"
37
+ CONFIG["sysconfdir"] = "$(prefix)/etc"
38
+ CONFIG["sharedstatedir"] = "$(prefix)/com"
39
+ CONFIG["localstatedir"] = "$(prefix)/var"
40
+ CONFIG["libdir"] = "$(exec_prefix)/lib"
41
+ CONFIG["includedir"] = "$(prefix)/include"
42
+ CONFIG["oldincludedir"] = "/usr/include"
43
+ CONFIG["infodir"] = "$(prefix)/info"
44
+ CONFIG["mandir"] = "$(prefix)/man"
45
+ CONFIG["build_alias"] = "i686-linux"
46
+ CONFIG["host_alias"] = "#{mingwpre}"
47
+ CONFIG["target_alias"] = "i386-mingw32"
48
+ CONFIG["ECHO_C"] = ""
49
+ CONFIG["ECHO_N"] = "-n"
50
+ CONFIG["ECHO_T"] = ""
51
+ CONFIG["LIBS"] = "-lwsock32 "
52
+ CONFIG["MAJOR"] = "1"
53
+ CONFIG["MINOR"] = "8"
54
+ CONFIG["TEENY"] = "4"
55
+ CONFIG["build"] = "i686-pc-linux"
56
+ CONFIG["build_cpu"] = "i686"
57
+ CONFIG["build_vendor"] = "pc"
58
+ CONFIG["build_os"] = "linux"
59
+ CONFIG["host"] = "i586-pc-mingw32msvc"
60
+ CONFIG["host_cpu"] = "i586"
61
+ CONFIG["host_vendor"] = "pc"
62
+ CONFIG["host_os"] = "mingw32msvc"
63
+ CONFIG["target"] = "i386-pc-mingw32"
64
+ CONFIG["target_cpu"] = "i386"
65
+ CONFIG["target_vendor"] = "pc"
66
+ CONFIG["target_os"] = "mingw32"
67
+ CONFIG["CC"] = "#{mingwpre}-gcc"
68
+ CONFIG["CFLAGS"] = "-g "
69
+ CONFIG["LDFLAGS"] = ""
70
+ CONFIG["CPPFLAGS"] = ""
71
+ CONFIG["OBJEXT"] = "o"
72
+ CONFIG["CPP"] = "#{mingwpre}-gcc -E"
73
+ CONFIG["EGREP"] = "grep -E"
74
+ CONFIG["GNU_LD"] = "yes"
75
+ CONFIG["CPPOUTFILE"] = "-o conftest.i"
76
+ CONFIG["OUTFLAG"] = "-o "
77
+ CONFIG["YACC"] = "bison -y"
78
+ CONFIG["RANLIB"] = "#{mingwpre}-ranlib"
79
+ CONFIG["AR"] = "#{mingwpre}-ar"
80
+ CONFIG["NM"] = "#{mingwpre}-nm"
81
+ CONFIG["WINDRES"] = "#{mingwpre}-windres"
82
+ CONFIG["DLLWRAP"] = "#{mingwpre}-dllwrap"
83
+ CONFIG["OBJDUMP"] = "#{mingwpre}-objdump"
84
+ CONFIG["LN_S"] = "ln -s"
85
+ CONFIG["SET_MAKE"] = ""
86
+ CONFIG["INSTALL_PROGRAM"] = "$(INSTALL)"
87
+ CONFIG["INSTALL_SCRIPT"] = "$(INSTALL)"
88
+ CONFIG["INSTALL_DATA"] = "$(INSTALL) -m 644"
89
+ CONFIG["RM"] = "rm -f"
90
+ CONFIG["CP"] = "cp"
91
+ CONFIG["MAKEDIRS"] = "mkdir -p"
92
+ CONFIG["LIBOBJS"] = " fileblocks$(U).o crypt$(U).o flock$(U).o acosh$(U).o win32$(U).o"
93
+ CONFIG["ALLOCA"] = ""
94
+ CONFIG["DLDFLAGS"] = " -Wl,--enable-auto-import,--export-all"
95
+ CONFIG["ARCH_FLAG"] = ""
96
+ CONFIG["STATIC"] = ""
97
+ CONFIG["CCDLFLAGS"] = ""
98
+ CONFIG["LDSHARED"] = "#{mingwpre}-gcc -shared -s"
99
+ CONFIG["DLEXT"] = "so"
100
+ CONFIG["DLEXT2"] = "dll"
101
+ CONFIG["LIBEXT"] = "a"
102
+ CONFIG["LINK_SO"] = ""
103
+ CONFIG["LIBPATHFLAG"] = " -L\"%s\""
104
+ CONFIG["RPATHFLAG"] = ""
105
+ CONFIG["LIBPATHENV"] = ""
106
+ CONFIG["TRY_LINK"] = ""
107
+ CONFIG["STRIP"] = "strip"
108
+ CONFIG["EXTSTATIC"] = ""
109
+ CONFIG["setup"] = "Setup"
110
+ CONFIG["MINIRUBY"] = "ruby -rfake"
111
+ CONFIG["PREP"] = "fake.rb"
112
+ CONFIG["RUNRUBY"] = "$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`"
113
+ CONFIG["EXTOUT"] = ".ext"
114
+ CONFIG["ARCHFILE"] = ""
115
+ CONFIG["RDOCTARGET"] = ""
116
+ CONFIG["XCFLAGS"] = " -DRUBY_EXPORT"
117
+ CONFIG["XLDFLAGS"] = " -Wl,--stack,0x02000000 -L."
118
+ CONFIG["LIBRUBY_LDSHARED"] = "#{mingwpre}-gcc -shared -s"
119
+ CONFIG["LIBRUBY_DLDFLAGS"] = " -Wl,--enable-auto-import,--export-all -Wl,--out-implib=$(LIBRUBY)"
120
+ CONFIG["rubyw_install_name"] = "rubyw"
121
+ CONFIG["RUBYW_INSTALL_NAME"] = "rubyw"
122
+ CONFIG["LIBRUBY_A"] = "lib$(RUBY_SO_NAME)-static.a"
123
+ CONFIG["LIBRUBY_SO"] = "$(RUBY_SO_NAME).dll"
124
+ CONFIG["LIBRUBY_ALIASES"] = ""
125
+ CONFIG["LIBRUBY"] = "lib$(LIBRUBY_SO).a"
126
+ CONFIG["LIBRUBYARG"] = "$(LIBRUBYARG_SHARED)"
127
+ CONFIG["LIBRUBYARG_STATIC"] = "-l$(RUBY_SO_NAME)-static"
128
+ CONFIG["LIBRUBYARG_SHARED"] = "-l$(RUBY_SO_NAME)"
129
+ CONFIG["SOLIBS"] = "$(LIBS)"
130
+ CONFIG["DLDLIBS"] = ""
131
+ CONFIG["ENABLE_SHARED"] = "yes"
132
+ CONFIG["MAINLIBS"] = ""
133
+ CONFIG["COMMON_LIBS"] = "m"
134
+ CONFIG["COMMON_MACROS"] = ""
135
+ CONFIG["COMMON_HEADERS"] = "windows.h winsock.h"
136
+ CONFIG["EXPORT_PREFIX"] = ""
137
+ CONFIG["MINIOBJS"] = "dmydln.o"
138
+ CONFIG["MAKEFILES"] = "Makefile GNUmakefile"
139
+ CONFIG["arch"] = "i386-mingw32"
140
+ CONFIG["sitearch"] = "i386-msvcrt"
141
+ CONFIG["sitedir"] = "$(prefix)/lib/ruby/site_ruby"
142
+ CONFIG["configure_args"] = "'--host=#{mingwpre}' '--target=i386-mingw32' '--build=i686-linux' '--prefix=#{mingw32}' 'build_alias=i686-linux' 'host_alias=#{mingwpre}' 'target_alias=i386-mingw32'"
143
+ CONFIG["NROFF"] = "/usr/bin/nroff"
144
+ CONFIG["MANTYPE"] = "doc"
145
+ CONFIG["LTLIBOBJS"] = " fileblocks$(U).lo crypt$(U).lo flock$(U).lo acosh$(U).lo win32$(U).lo"
146
+ CONFIG["ruby_version"] = "$(MAJOR).$(MINOR)"
147
+ CONFIG["rubylibdir"] = "$(libdir)/ruby/$(ruby_version)"
148
+ CONFIG["archdir"] = "$(rubylibdir)/$(arch)"
149
+ CONFIG["sitelibdir"] = "$(sitedir)/$(ruby_version)"
150
+ CONFIG["sitearchdir"] = "$(sitelibdir)/$(sitearch)"
151
+ CONFIG["topdir"] = File.dirname(__FILE__)
152
+ MAKEFILE_CONFIG = {}
153
+ CONFIG.each{|k,v| MAKEFILE_CONFIG[k] = v.dup}
154
+ def Config::expand(val, config = CONFIG)
155
+ val.gsub!(/\$\$|\$\(([^()]+)\)|\$\{([^{}]+)\}/) do |var|
156
+ if !(v = $1 || $2)
157
+ '$'
158
+ elsif key = config[v = v[/\A[^:]+(?=(?::(.*?)=(.*))?\z)/]]
159
+ pat, sub = $1, $2
160
+ config[v] = false
161
+ Config::expand(key, config)
162
+ config[v] = key
163
+ key = key.gsub(/#{Regexp.quote(pat)}(?=\s|\z)/n) {sub} if pat
164
+ key
165
+ else
166
+ var
167
+ end
168
+ end
169
+ val
170
+ end
171
+ CONFIG.each_value do |val|
172
+ Config::expand(val)
173
+ end
174
+ end
175
+ RbConfig = Config # compatibility for ruby-1.9
176
+ CROSS_COMPILING = nil unless defined? CROSS_COMPILING
@@ -0,0 +1,73 @@
1
+ class RagelProfiler
2
+ MEM_CONVERSION = 1024
3
+
4
+ COMMANDS = { :compile => %w(ragel rlgen-cd gcc-4.0 gnumake cc1),
5
+ :test => %w(ruby) }
6
+
7
+ FIELDS = %w(compile_time compile_max_rss test_time test_max_rss ext_so_size)
8
+
9
+ @@results = {}
10
+
11
+ def initialize(name)
12
+ @name = name
13
+ @@results[name] = []
14
+ end
15
+
16
+ def measure(type)
17
+ raise "not a valid type" unless COMMANDS.keys.include?(type)
18
+ regex = COMMANDS[type].map {|c| Regexp.escape(c) }.join("|")
19
+ t = Thread.new do
20
+ Thread.current[:max] = 0
21
+ loop do
22
+ Thread.current[:max] = [run(regex), Thread.current[:max]].max
23
+ sleep 0.5
24
+ end
25
+ end
26
+ begin_time = Time.now
27
+ yield
28
+ total_time = Time.now - begin_time
29
+
30
+ t.kill
31
+ store_result(type, "time", total_time)
32
+ store_result(type, "max_rss", t[:max])
33
+ end
34
+
35
+ def ext_size(ext_so)
36
+ store_result(:ext_so, "size", File.size(ext_so) / MEM_CONVERSION)
37
+ end
38
+
39
+ def self.results
40
+ out = []
41
+ out << "name\t" + FIELDS.join("\t")
42
+ @@results.each do |name, results|
43
+ out << [name, results ].flatten.join("\t")
44
+ end
45
+ out.join("\n")
46
+ end
47
+
48
+ private
49
+
50
+ def store_result(type, metric, value)
51
+ index = FIELDS.index("#{type.to_s}_#{metric}")
52
+ @@results[@name][index] = "%.2f" % value
53
+ end
54
+
55
+ def run(ps_regex)
56
+ ps_command = "ps axucww"
57
+ ps_output = `#{ps_command}`
58
+ fields = ps_output.to_a.first.downcase.split
59
+ memory_index = fields.index("rss")
60
+ pid_index = fields.index("pid")
61
+ ppid_index = fields.index("ppid")
62
+ total = ps_output.grep(/(#{ps_regex})\s+$/i).map do |com|
63
+ Float(com.split[memory_index]).abs
64
+ end.inject(0) { |s,v| s += v }
65
+ if total
66
+ return total/MEM_CONVERSION
67
+ else
68
+ STDERR.puts "Command not found. No processes found matching #{ps_regex}."
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -1,1130 +1,24 @@
1
- # vim:ts=4:sw=4:
2
- # = RedCloth - Textile and Markdown Hybrid for Ruby
3
- #
4
- # Homepage:: http://whytheluckystiff.net/ruby/redcloth/
5
- # Author:: why the lucky stiff (http://whytheluckystiff.net/)
6
- # Copyright:: (cc) 2004 why the lucky stiff (and his puppet organizations.)
7
- # License:: BSD
8
- #
9
- # (see http://hobix.com/textile/ for a Textile Reference.)
10
- #
11
- # Based on (and also inspired by) both:
12
- #
13
- # PyTextile: http://diveintomark.org/projects/textile/textile.py.txt
14
- # Textism for PHP: http://www.textism.com/tools/textile/
15
- #
16
- #
17
-
18
- # = RedCloth
19
- #
20
- # RedCloth is a Ruby library for converting Textile and/or Markdown
21
- # into HTML. You can use either format, intermingled or separately.
22
- # You can also extend RedCloth to honor your own custom text stylings.
23
- #
24
- # RedCloth users are encouraged to use Textile if they are generating
25
- # HTML and to use Markdown if others will be viewing the plain text.
26
- #
27
- # == What is Textile?
28
- #
29
- # Textile is a simple formatting style for text
30
- # documents, loosely based on some HTML conventions.
31
- #
32
- # == Sample Textile Text
33
- #
34
- # h2. This is a title
35
- #
36
- # h3. This is a subhead
37
- #
38
- # This is a bit of paragraph.
39
- #
40
- # bq. This is a blockquote.
41
- #
42
- # = Writing Textile
43
- #
44
- # A Textile document consists of paragraphs. Paragraphs
45
- # can be specially formatted by adding a small instruction
46
- # to the beginning of the paragraph.
47
- #
48
- # h[n]. Header of size [n].
49
- # bq. Blockquote.
50
- # # Numeric list.
51
- # * Bulleted list.
52
- #
53
- # == Quick Phrase Modifiers
54
- #
55
- # Quick phrase modifiers are also included, to allow formatting
56
- # of small portions of text within a paragraph.
57
- #
58
- # \_emphasis\_
59
- # \_\_italicized\_\_
60
- # \*strong\*
61
- # \*\*bold\*\*
62
- # ??citation??
63
- # -deleted text-
64
- # +inserted text+
65
- # ^superscript^
66
- # ~subscript~
67
- # @code@
68
- # %(classname)span%
69
- #
70
- # ==notextile== (leave text alone)
71
- #
72
- # == Links
73
- #
74
- # To make a hypertext link, put the link text in "quotation
75
- # marks" followed immediately by a colon and the URL of the link.
76
- #
77
- # Optional: text in (parentheses) following the link text,
78
- # but before the closing quotation mark, will become a Title
79
- # attribute for the link, visible as a tool tip when a cursor is above it.
80
- #
81
- # Example:
82
- #
83
- # "This is a link (This is a title) ":http://www.textism.com
84
- #
85
- # Will become:
86
- #
87
- # <a href="http://www.textism.com" title="This is a title">This is a link</a>
88
- #
89
- # == Images
90
- #
91
- # To insert an image, put the URL for the image inside exclamation marks.
92
- #
93
- # Optional: text that immediately follows the URL in (parentheses) will
94
- # be used as the Alt text for the image. Images on the web should always
95
- # have descriptive Alt text for the benefit of readers using non-graphical
96
- # browsers.
97
- #
98
- # Optional: place a colon followed by a URL immediately after the
99
- # closing ! to make the image into a link.
100
- #
101
- # Example:
102
- #
103
- # !http://www.textism.com/common/textist.gif(Textist)!
104
- #
105
- # Will become:
106
- #
107
- # <img src="http://www.textism.com/common/textist.gif" alt="Textist" />
108
- #
109
- # With a link:
110
- #
111
- # !/common/textist.gif(Textist)!:http://textism.com
112
- #
113
- # Will become:
114
- #
115
- # <a href="http://textism.com"><img src="/common/textist.gif" alt="Textist" /></a>
116
- #
117
- # == Defining Acronyms
118
- #
119
- # HTML allows authors to define acronyms via the tag. The definition appears as a
120
- # tool tip when a cursor hovers over the acronym. A crucial aid to clear writing,
121
- # this should be used at least once for each acronym in documents where they appear.
122
- #
123
- # To quickly define an acronym in Textile, place the full text in (parentheses)
124
- # immediately following the acronym.
125
- #
126
- # Example:
127
- #
128
- # ACLU(American Civil Liberties Union)
129
- #
130
- # Will become:
131
- #
132
- # <acronym title="American Civil Liberties Union">ACLU</acronym>
133
- #
134
- # == Adding Tables
135
- #
136
- # In Textile, simple tables can be added by seperating each column by
137
- # a pipe.
138
- #
139
- # |a|simple|table|row|
140
- # |And|Another|table|row|
141
- #
142
- # Attributes are defined by style definitions in parentheses.
143
- #
144
- # table(border:1px solid black).
145
- # (background:#ddd;color:red). |{}| | | |
146
- #
147
- # == Using RedCloth
148
- #
149
- # RedCloth is simply an extension of the String class, which can handle
150
- # Textile formatting. Use it like a String and output HTML with its
151
- # RedCloth#to_html method.
152
- #
153
- # doc = RedCloth.new "
154
- #
155
- # h2. Test document
156
- #
157
- # Just a simple test."
158
- #
159
- # puts doc.to_html
160
- #
161
- # By default, RedCloth uses both Textile and Markdown formatting, with
162
- # Textile formatting taking precedence. If you want to turn off Markdown
163
- # formatting, to boost speed and limit the processor:
164
- #
165
- # class RedCloth::Textile.new( str )
166
-
167
- class RedCloth < String
168
-
169
- VERSION = '3.0.4'
170
- DEFAULT_RULES = [:textile, :markdown]
171
-
172
- #
173
- # Two accessor for setting security restrictions.
174
- #
175
- # This is a nice thing if you're using RedCloth for
176
- # formatting in public places (e.g. Wikis) where you
177
- # don't want users to abuse HTML for bad things.
178
- #
179
- # If +:filter_html+ is set, HTML which wasn't
180
- # created by the Textile processor will be escaped.
181
- #
182
- # If +:filter_styles+ is set, it will also disable
183
- # the style markup specifier. ('{color: red}')
184
- #
185
- attr_accessor :filter_html, :filter_styles
186
-
187
- #
188
- # Accessor for toggling hard breaks.
189
- #
190
- # If +:hard_breaks+ is set, single newlines will
191
- # be converted to HTML break tags. This is the
192
- # default behavior for traditional RedCloth.
193
- #
194
- attr_accessor :hard_breaks
195
-
196
- # Accessor for toggling lite mode.
197
- #
198
- # In lite mode, block-level rules are ignored. This means
199
- # that tables, paragraphs, lists, and such aren't available.
200
- # Only the inline markup for bold, italics, entities and so on.
201
- #
202
- # r = RedCloth.new( "And then? She *fell*!", [:lite_mode] )
203
- # r.to_html
204
- # #=> "And then? She <strong>fell</strong>!"
205
- #
206
- attr_accessor :lite_mode
207
-
208
- #
209
- # Accessor for toggling span caps.
210
- #
211
- # Textile places `span' tags around capitalized
212
- # words by default, but this wreaks havoc on Wikis.
213
- # If +:no_span_caps+ is set, this will be
214
- # suppressed.
215
- #
216
- attr_accessor :no_span_caps
217
-
218
- #
219
- # Establishes the markup predence. Available rules include:
220
- #
221
- # == Textile Rules
222
- #
223
- # The following textile rules can be set individually. Or add the complete
224
- # set of rules with the single :textile rule, which supplies the rule set in
225
- # the following precedence:
226
- #
227
- # refs_textile:: Textile references (i.e. [hobix]http://hobix.com/)
228
- # block_textile_table:: Textile table block structures
229
- # block_textile_lists:: Textile list structures
230
- # block_textile_prefix:: Textile blocks with prefixes (i.e. bq., h2., etc.)
231
- # inline_textile_image:: Textile inline images
232
- # inline_textile_link:: Textile inline links
233
- # inline_textile_span:: Textile inline spans
234
- # glyphs_textile:: Textile entities (such as em-dashes and smart quotes)
235
- #
236
- # == Markdown
237
- #
238
- # refs_markdown:: Markdown references (for example: [hobix]: http://hobix.com/)
239
- # block_markdown_setext:: Markdown setext headers
240
- # block_markdown_atx:: Markdown atx headers
241
- # block_markdown_rule:: Markdown horizontal rules
242
- # block_markdown_bq:: Markdown blockquotes
243
- # block_markdown_lists:: Markdown lists
244
- # inline_markdown_link:: Markdown links
245
- attr_accessor :rules
246
-
247
- # Returns a new RedCloth object, based on _string_ and
248
- # enforcing all the included _restrictions_.
249
- #
250
- # r = RedCloth.new( "h1. A <b>bold</b> man", [:filter_html] )
251
- # r.to_html
252
- # #=>"<h1>A &lt;b&gt;bold&lt;/b&gt; man</h1>"
253
- #
254
- def initialize( string, restrictions = [] )
255
- restrictions.each { |r| method( "#{ r }=" ).call( true ) }
256
- super( string )
257
- end
258
-
259
- #
260
- # Generates HTML from the Textile contents.
261
- #
262
- # r = RedCloth.new( "And then? She *fell*!" )
263
- # r.to_html( true )
264
- # #=>"And then? She <strong>fell</strong>!"
265
- #
266
- def to_html( *rules )
267
- rules = DEFAULT_RULES if rules.empty?
268
- # make our working copy
269
- text = self.dup
270
-
271
- @urlrefs = {}
272
- @shelf = []
273
- textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists,
274
- :block_textile_prefix, :inline_textile_image, :inline_textile_link,
275
- :inline_textile_code, :inline_textile_span, :glyphs_textile]
276
- markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,
277
- :block_markdown_bq, :block_markdown_lists,
278
- :inline_markdown_reflink, :inline_markdown_link]
279
- @rules = rules.collect do |rule|
280
- case rule
281
- when :markdown
282
- markdown_rules
283
- when :textile
284
- textile_rules
285
- else
286
- rule
287
- end
288
- end.flatten
289
-
290
- # standard clean up
291
- incoming_entities text
292
- clean_white_space text
293
-
294
- # start processor
295
- @pre_list = []
296
- rip_offtags text
297
- no_textile text
298
- hard_break text
299
- unless @lite_mode
300
- refs text
301
- blocks text
302
- end
303
- inline text
304
- smooth_offtags text
305
-
306
- retrieve text
307
-
308
- text.gsub!( /<\/?notextile>/, '' )
309
- text.gsub!( /x%x%/, '&#38;' )
310
- clean_html text if filter_html
311
- text.strip!
312
- text
313
-
314
- end
315
-
316
- #######
317
- private
318
- #######
319
- #
320
- # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
321
- # (from PyTextile)
322
- #
323
- TEXTILE_TAGS =
324
-
325
- [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
326
- [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
327
- [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
328
- [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
329
- [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
330
-
331
- collect! do |a, b|
332
- [a.chr, ( b.zero? and "" or "&#{ b };" )]
333
- end
334
-
335
- #
336
- # Regular expressions to convert to HTML.
337
- #
338
- A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/
339
- A_VLGN = /[\-^~]/
340
- C_CLAS = '(?:\([^)]+\))'
341
- C_LNGE = '(?:\[[^\]]+\])'
342
- C_STYL = '(?:\{[^}]+\})'
343
- S_CSPN = '(?:\\\\\d+)'
344
- S_RSPN = '(?:/\d+)'
345
- A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
346
- S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)"
347
- C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
348
- # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
349
- PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
350
- PUNCT_NOQ = Regexp::quote( '!"#$&\',./:;=?@\\`|' )
351
- PUNCT_Q = Regexp::quote( '*-_+^~%' )
352
- HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(?=\s|<|$)'
353
-
354
- # Text markup tags, don't conflict with block tags
355
- SIMPLE_HTML_TAGS = [
356
- 'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code',
357
- 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'a', 'img', 'br',
358
- 'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo'
359
- ]
360
-
361
- QTAGS = [
362
- ['**', 'b'],
363
- ['*', 'strong'],
364
- ['??', 'cite', :limit],
365
- ['-', 'del', :limit],
366
- ['__', 'i'],
367
- ['_', 'em', :limit],
368
- ['%', 'span', :limit],
369
- ['+', 'ins', :limit],
370
- ['^', 'sup'],
371
- ['~', 'sub']
372
- ]
373
- QTAGS.collect! do |rc, ht, rtype|
374
- rcq = Regexp::quote rc
375
- re =
376
- case rtype
377
- when :limit
378
- /(\W)
379
- (#{rcq})
380
- (#{C})
381
- (?::(\S+?))?
382
- (\S.*?\S|\S)
383
- #{rcq}
384
- (?=\W)/x
385
- else
386
- /(#{rcq})
387
- (#{C})
388
- (?::(\S+))?
389
- (\S.*?\S|\S)
390
- #{rcq}/xm
391
- end
392
- [rc, ht, re, rtype]
393
- end
394
-
395
- # Elements to handle
396
- GLYPHS = [
397
- # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
398
- [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1&#8217;' ], # single closing
399
- [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing
400
- [ /\'/, '&#8216;' ], # single opening
401
- [ /</, '&lt;' ], # less-than
402
- [ />/, '&gt;' ], # greater-than
403
- # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
404
- [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1&#8221;' ], # double closing
405
- [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
406
- [ /"/, '&#8220;' ], # double opening
407
- [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
408
- [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
409
- [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps
410
- [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
411
- [ /\s->\s/, ' &rarr; ' ], # right arrow
412
- [ /\s-\s/, ' &#8211; ' ], # en dash
413
- [ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
414
- [ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
415
- [ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
416
- [ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
417
- ]
418
-
419
- H_ALGN_VALS = {
420
- '<' => 'left',
421
- '=' => 'center',
422
- '>' => 'right',
423
- '<>' => 'justify'
424
- }
425
-
426
- V_ALGN_VALS = {
427
- '^' => 'top',
428
- '-' => 'middle',
429
- '~' => 'bottom'
430
- }
431
-
432
- #
433
- # Flexible HTML escaping
434
- #
435
- def htmlesc( str, mode )
436
- str.gsub!( '&', '&amp;' )
437
- str.gsub!( '"', '&quot;' ) if mode != :NoQuotes
438
- str.gsub!( "'", '&#039;' ) if mode == :Quotes
439
- str.gsub!( '<', '&lt;')
440
- str.gsub!( '>', '&gt;')
441
- end
442
-
443
- # Search and replace for Textile glyphs (quotes, dashes, other symbols)
444
- def pgl( text )
445
- GLYPHS.each do |re, resub, tog|
446
- next if tog and method( tog ).call
447
- text.gsub! re, resub
448
- end
449
- end
450
-
451
- # Parses Textile attribute lists and builds an HTML attribute string
452
- def pba( text_in, element = "" )
453
-
454
- return '' unless text_in
455
-
456
- style = []
457
- text = text_in.dup
458
- if element == 'td'
459
- colspan = $1 if text =~ /\\(\d+)/
460
- rowspan = $1 if text =~ /\/(\d+)/
461
- style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
462
- end
463
-
464
- style << "#{ $1 };" if not filter_styles and
465
- text.sub!( /\{([^}]*)\}/, '' )
466
-
467
- lang = $1 if
468
- text.sub!( /\[([^)]+?)\]/, '' )
469
-
470
- cls = $1 if
471
- text.sub!( /\(([^()]+?)\)/, '' )
472
-
473
- style << "padding-left:#{ $1.length }em;" if
474
- text.sub!( /([(]+)/, '' )
475
-
476
- style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' )
477
-
478
- style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN
479
-
480
- cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/
481
-
482
- atts = ''
483
- atts << " style=\"#{ style.join }\"" unless style.empty?
484
- atts << " class=\"#{ cls }\"" unless cls.to_s.empty?
485
- atts << " lang=\"#{ lang }\"" if lang
486
- atts << " id=\"#{ id }\"" if id
487
- atts << " colspan=\"#{ colspan }\"" if colspan
488
- atts << " rowspan=\"#{ rowspan }\"" if rowspan
489
-
490
- atts
491
- end
492
-
493
- TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)(\n\n|\Z)/m
494
-
495
- # Parses a Textile table block, building HTML from the result.
496
- def block_textile_table( text )
497
- text.gsub!( TABLE_RE ) do |matches|
498
-
499
- tatts, fullrow = $~[1..2]
500
- tatts = pba( tatts, 'table' )
501
- tatts = shelve( tatts ) if tatts
502
- rows = []
503
-
504
- fullrow.
505
- split( /\|$/m ).
506
- delete_if { |x| x.empty? }.
507
- each do |row|
508
-
509
- ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
510
-
511
- cells = []
512
- row.split( '|' ).each do |cell|
513
- ctyp = 'd'
514
- ctyp = 'h' if cell =~ /^_/
515
-
516
- catts = ''
517
- catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. ?)(.*)/
518
-
519
- unless cell.strip.empty?
520
- catts = shelve( catts ) if catts
521
- cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
522
- end
523
- end
524
- ratts = shelve( ratts ) if ratts
525
- rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
526
- end
527
- "\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
528
- end
529
- end
530
-
531
- LISTS_RE = /^([#*]+?#{C} .*?)$(?![^#*])/m
532
- LISTS_CONTENT_RE = /^([#*]+)(#{A}#{C}) (.*)$/m
533
-
534
- # Parses Textile lists and generates HTML
535
- def block_textile_lists( text )
536
- text.gsub!( LISTS_RE ) do |match|
537
- lines = match.split( /\n/ )
538
- last_line = -1
539
- depth = []
540
- lines.each_with_index do |line, line_id|
541
- if line =~ LISTS_CONTENT_RE
542
- tl,atts,content = $~[1..3]
543
- if depth.last
544
- if depth.last.length > tl.length
545
- (depth.length - 1).downto(0) do |i|
546
- break if depth[i].length == tl.length
547
- lines[line_id - 1] << "</li>\n\t</#{ lT( depth[i] ) }l>\n\t"
548
- depth.pop
549
- end
550
- end
551
- if depth.last and depth.last.length == tl.length
552
- lines[line_id - 1] << '</li>'
553
- end
554
- end
555
- unless depth.last == tl
556
- depth << tl
557
- atts = pba( atts )
558
- atts = shelve( atts ) if atts
559
- lines[line_id] = "\t<#{ lT(tl) }l#{ atts }>\n\t<li>#{ content }"
560
- else
561
- lines[line_id] = "\t\t<li>#{ content }"
562
- end
563
- last_line = line_id
564
-
565
- else
566
- last_line = line_id
567
- end
568
- if line_id - last_line > 1 or line_id == lines.length - 1
569
- depth.delete_if do |v|
570
- lines[last_line] << "</li>\n\t</#{ lT( v ) }l>"
571
- end
572
- end
573
- end
574
- lines.join( "\n" )
575
- end
576
- end
577
-
578
- CODE_RE = /(\W)
579
- @
580
- (?:\|(\w+?)\|)?
581
- (.+?)
582
- @
583
- (?=\W)/x
584
-
585
- def inline_textile_code( text )
586
- text.gsub!( CODE_RE ) do |m|
587
- before,lang,code,after = $~[1..4]
588
- lang = " lang=\"#{ lang }\"" if lang
589
- rip_offtags( "#{ before }<code#{ lang }>#{ code }</code>#{ after }" )
590
- end
591
- end
592
-
593
- def lT( text )
594
- text =~ /\#$/ ? 'o' : 'u'
595
- end
596
-
597
- def hard_break( text )
598
- text.gsub!( /(.)\n(?!\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
599
- end
600
-
601
- BLOCKS_GROUP_RE = /\n{2,}(?! )/m
602
-
603
- def blocks( text, deep_code = false )
604
- text.replace( text.split( BLOCKS_GROUP_RE ).collect do |blk|
605
- plain = blk !~ /\A[#*> ]/
606
-
607
- # skip blocks that are complex HTML
608
- if blk =~ /^<\/?(\w+).*>/ and not SIMPLE_HTML_TAGS.include? $1
609
- blk
610
- else
611
- # search for indentation levels
612
- blk.strip!
613
- if blk.empty?
614
- blk
615
- else
616
- code_blk = nil
617
- blk.gsub!( /((?:\n(?:\n^ +[^\n]*)+)+)/m ) do |iblk|
618
- flush_left iblk
619
- blocks iblk, plain
620
- iblk.gsub( /^(\S)/, "\t\\1" )
621
- if plain
622
- code_blk = iblk; ""
623
- else
624
- iblk
625
- end
626
- end
627
-
628
- block_applied = 0
629
- @rules.each do |rule_name|
630
- block_applied += 1 if ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) )
631
- end
632
- if block_applied.zero?
633
- if deep_code
634
- blk = "\t<pre><code>#{ blk }</code></pre>"
635
- else
636
- blk = "\t<p>#{ blk }</p>"
637
- end
638
- end
639
- # hard_break blk
640
- blk + "\n#{ code_blk }"
641
- end
642
- end
643
-
644
- end.join( "\n\n" ) )
645
- end
646
-
647
- def textile_bq( tag, atts, cite, content )
648
- cite, cite_title = check_refs( cite )
649
- cite = " cite=\"#{ cite }\"" if cite
650
- atts = shelve( atts ) if atts
651
- "\t<blockquote#{ cite }>\n\t\t<p#{ atts }>#{ content }</p>\n\t</blockquote>"
652
- end
653
-
654
- def textile_p( tag, atts, cite, content )
655
- atts = shelve( atts ) if atts
656
- "\t<#{ tag }#{ atts }>#{ content }</#{ tag }>"
657
- end
658
-
659
- alias textile_h1 textile_p
660
- alias textile_h2 textile_p
661
- alias textile_h3 textile_p
662
- alias textile_h4 textile_p
663
- alias textile_h5 textile_p
664
- alias textile_h6 textile_p
665
-
666
- def textile_fn_( tag, num, atts, cite, content )
667
- atts << " id=\"fn#{ num }\""
668
- content = "<sup>#{ num }</sup> #{ content }"
669
- atts = shelve( atts ) if atts
670
- "\t<p#{ atts }>#{ content }</p>"
671
- end
672
-
673
- BLOCK_RE = /^(([a-z]+)(\d*))(#{A}#{C})\.(?::(\S+))? (.*)$/m
674
-
675
- def block_textile_prefix( text )
676
- if text =~ BLOCK_RE
677
- tag,tagpre,num,atts,cite,content = $~[1..6]
678
- atts = pba( atts )
679
-
680
- # pass to prefix handler
681
- if respond_to? "textile_#{ tag }", true
682
- text.gsub!( $&, method( "textile_#{ tag }" ).call( tag, atts, cite, content ) )
683
- elsif respond_to? "textile_#{ tagpre }_", true
684
- text.gsub!( $&, method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content ) )
685
- end
686
- end
687
- end
688
-
689
- SETEXT_RE = /\A(.+?)\n([=-])[=-]* *$/m
690
- def block_markdown_setext( text )
691
- if text =~ SETEXT_RE
692
- tag = if $2 == "="; "h1"; else; "h2"; end
693
- blk, cont = "<#{ tag }>#{ $1 }</#{ tag }>", $'
694
- blocks cont
695
- text.replace( blk + cont )
696
- end
697
- end
698
-
699
- ATX_RE = /\A(\#{1,6}) # $1 = string of #'s
700
- [ ]*
701
- (.+?) # $2 = Header text
702
- [ ]*
703
- \#* # optional closing #'s (not counted)
704
- $/x
705
- def block_markdown_atx( text )
706
- if text =~ ATX_RE
707
- tag = "h#{ $1.length }"
708
- blk, cont = "<#{ tag }>#{ $2 }</#{ tag }>\n\n", $'
709
- blocks cont
710
- text.replace( blk + cont )
711
- end
712
- end
713
-
714
- MARKDOWN_BQ_RE = /\A(^ *> ?.+$(.+\n)*\n*)+/m
715
-
716
- def block_markdown_bq( text )
717
- text.gsub!( MARKDOWN_BQ_RE ) do |blk|
718
- blk.gsub!( /^ *> ?/, '' )
719
- flush_left blk
720
- blocks blk
721
- blk.gsub!( /^(\S)/, "\t\\1" )
722
- "<blockquote>\n#{ blk }\n</blockquote>\n\n"
723
- end
724
- end
725
-
726
- MARKDOWN_RULE_RE = /^(#{
727
- ['*', '-', '_'].collect { |ch| '( ?' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' )
728
- })$/
729
-
730
- def block_markdown_rule( text )
731
- text.gsub!( MARKDOWN_RULE_RE ) do |blk|
732
- "<hr />"
733
- end
734
- end
735
-
736
- # XXX TODO XXX
737
- def block_markdown_lists( text )
738
- end
739
-
740
- def inline_textile_span( text )
741
- QTAGS.each do |qtag_rc, ht, qtag_re, rtype|
742
- text.gsub!( qtag_re ) do |m|
743
-
744
- case rtype
745
- when :limit
746
- sta,qtag,atts,cite,content = $~[1..5]
747
- else
748
- qtag,atts,cite,content = $~[1..4]
749
- sta = ''
750
- end
751
- atts = pba( atts )
752
- atts << " cite=\"#{ cite }\"" if cite
753
- atts = shelve( atts ) if atts
754
-
755
- "#{ sta }<#{ ht }#{ atts }>#{ content }</#{ ht }>"
756
-
757
- end
758
- end
759
- end
760
-
761
- LINK_RE = /
762
- ([\s\[{(]|[#{PUNCT}])? # $pre
763
- " # start
764
- (#{C}) # $atts
765
- ([^"]+?) # $text
766
- \s?
767
- (?:\(([^)]+?)\)(?="))? # $title
768
- ":
769
- (\S+?) # $url
770
- (\/)? # $slash
771
- ([^\w\/;]*?) # $post
772
- (?=<|\s|$)
773
- /x
774
-
775
- def inline_textile_link( text )
776
- text.gsub!( LINK_RE ) do |m|
777
- pre,atts,text,title,url,slash,post = $~[1..7]
778
-
779
- url, url_title = check_refs( url )
780
- title ||= url_title
781
-
782
- atts = pba( atts )
783
- atts = " href=\"#{ url }#{ slash }\"#{ atts }"
784
- atts << " title=\"#{ title }\"" if title
785
- atts = shelve( atts ) if atts
786
-
787
- "#{ pre }<a#{ atts }>#{ text }</a>#{ post }"
788
- end
789
- end
790
-
791
- MARKDOWN_REFLINK_RE = /
792
- \[([^\[\]]+)\] # $text
793
- [ ]? # opt. space
794
- (?:\n[ ]*)? # one optional newline followed by spaces
795
- \[(.*?)\] # $id
796
- /x
797
-
798
- def inline_markdown_reflink( text )
799
- text.gsub!( MARKDOWN_REFLINK_RE ) do |m|
800
- text, id = $~[1..2]
801
-
802
- if id.empty?
803
- url, title = check_refs( text )
804
- else
805
- url, title = check_refs( id )
806
- end
807
-
808
- atts = " href=\"#{ url }\""
809
- atts << " title=\"#{ title }\"" if title
810
- atts = shelve( atts )
811
-
812
- "<a#{ atts }>#{ text }</a>"
813
- end
814
- end
815
-
816
- MARKDOWN_LINK_RE = /
817
- \[([^\[\]]+)\] # $text
818
- \( # open paren
819
- [ \t]* # opt space
820
- <?(.+?)>? # $href
821
- [ \t]* # opt space
822
- (?: # whole title
823
- (['"]) # $quote
824
- (.*?) # $title
825
- \3 # matching quote
826
- )? # title is optional
827
- \)
828
- /x
829
-
830
- def inline_markdown_link( text )
831
- text.gsub!( MARKDOWN_LINK_RE ) do |m|
832
- text, url, quote, title = $~[1..4]
833
-
834
- atts = " href=\"#{ url }\""
835
- atts << " title=\"#{ title }\"" if title
836
- atts = shelve( atts )
837
-
838
- "<a#{ atts }>#{ text }</a>"
839
- end
840
- end
841
-
842
- TEXTILE_REFS_RE = /(^ *)\[([^\n]+?)\](#{HYPERLINK})(?=\s|$)/
843
- MARKDOWN_REFS_RE = /(^ *)\[([^\n]+?)\]:\s+<?(#{HYPERLINK})>?(?:\s+"((?:[^"]|\\")+)")?(?=\s|$)/m
844
-
845
- def refs( text )
846
- @rules.each do |rule_name|
847
- method( rule_name ).call( text ) if rule_name.to_s.match /^refs_/
848
- end
849
- end
850
-
851
- def refs_textile( text )
852
- text.gsub!( TEXTILE_REFS_RE ) do |m|
853
- flag, url = $~[2..3]
854
- @urlrefs[flag.downcase] = [url, nil]
855
- nil
856
- end
857
- end
858
-
859
- def refs_markdown( text )
860
- text.gsub!( MARKDOWN_REFS_RE ) do |m|
861
- flag, url = $~[2..3]
862
- title = $~[6]
863
- @urlrefs[flag.downcase] = [url, title]
864
- nil
865
- end
866
- end
867
-
868
- def check_refs( text )
869
- ret = @urlrefs[text.downcase] if text
870
- ret || [text, nil]
871
- end
872
-
873
- IMAGE_RE = /
874
- (<p>|.|^) # start of line?
875
- \! # opening
876
- (\<|\=|\>)? # optional alignment atts
877
- (#{C}) # optional style,class atts
878
- (?:\. )? # optional dot-space
879
- ([^\s(!]+?) # presume this is the src
880
- \s? # optional space
881
- (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title
882
- \! # closing
883
- (?::#{ HYPERLINK })? # optional href
884
- /x
885
-
886
- def inline_textile_image( text )
887
- text.gsub!( IMAGE_RE ) do |m|
888
- stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]
889
- atts = pba( atts )
890
- atts = " src=\"#{ url }\"#{ atts }"
891
- atts << " title=\"#{ title }\"" if title
892
- atts << " alt=\"#{ title }\""
893
- # size = @getimagesize($url);
894
- # if($size) $atts.= " $size[3]";
895
-
896
- href, alt_title = check_refs( href ) if href
897
- url, url_title = check_refs( url )
898
-
899
- out = ''
900
- out << "<a#{ shelve( " href=\"#{ href }\"" ) }>" if href
901
- out << "<img#{ shelve( atts ) } />"
902
- out << "</a>#{ href_a1 }#{ href_a2 }" if href
903
-
904
- if algn
905
- algn = h_align( algn )
906
- if stln == "<p>"
907
- out = "<p style=\"float:#{ algn }\">#{ out }"
908
- else
909
- out = "#{ stln }<div style=\"float:#{ algn }\">#{ out }</div>"
910
- end
911
- else
912
- out = stln + out
913
- end
914
-
915
- out
916
- end
917
- end
918
-
919
- def shelve( val )
920
- @shelf << val
921
- " :redsh##{ @shelf.length }:"
922
- end
923
-
924
- def retrieve( text )
925
- @shelf.each_with_index do |r, i|
926
- text.gsub!( " :redsh##{ i + 1 }:", r )
927
- end
928
- end
929
-
930
- def incoming_entities( text )
931
- ## turn any incoming ampersands into a dummy character for now.
932
- ## This uses a negative lookahead for alphanumerics followed by a semicolon,
933
- ## implying an incoming html entity, to be skipped
934
-
935
- text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
936
- end
937
-
938
- def no_textile( text )
939
- text.gsub!( /(^|\s)==([^=]+.*?)==(\s|$)?/,
940
- '\1<notextile>\2</notextile>\3' )
941
- text.gsub!( /^ *==([^=]+.*?)==/m,
942
- '\1<notextile>\2</notextile>\3' )
943
- end
944
-
945
- def clean_white_space( text )
946
- # normalize line breaks
947
- text.gsub!( /\r\n/, "\n" )
948
- text.gsub!( /\r/, "\n" )
949
- text.gsub!( /\t/, ' ' )
950
- text.gsub!( /^ +$/, '' )
951
- text.gsub!( /\n{3,}/, "\n\n" )
952
- text.gsub!( /"$/, "\" " )
953
-
954
- # if entire document is indented, flush
955
- # to the left side
956
- flush_left text
957
- end
958
-
959
- def flush_left( text )
960
- indt = 0
961
- if text =~ /^ /
962
- while text !~ /^ {#{indt}}\S/
963
- indt += 1
964
- end unless text.empty?
965
- if indt.nonzero?
966
- text.gsub!( /^ {#{indt}}/, '' )
967
- end
968
- end
969
- end
970
-
971
- def footnote_ref( text )
972
- text.gsub!( /\b\[([0-9]+?)\](\s)?/,
973
- '<sup><a href="#fn\1">\1</a></sup>\2' )
974
- end
975
-
976
- OFFTAGS = /(code|pre|kbd|notextile)/
977
- OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }|\Z)/mi
978
- OFFTAG_OPEN = /<#{ OFFTAGS }/
979
- OFFTAG_CLOSE = /<\/?#{ OFFTAGS }/
980
- HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m
981
- ALLTAG_MATCH = /(<\/?\w[^\n]*?>)|.*?(?=<\/?\w[^\n]*?>|$)/m
982
-
983
- def glyphs_textile( text, level = 0 )
984
- if text !~ HASTAG_MATCH
985
- pgl text
986
- footnote_ref text
987
- else
988
- codepre = 0
989
- text.gsub!( ALLTAG_MATCH ) do |line|
990
- ## matches are off if we're between <code>, <pre> etc.
991
- if $1
992
- if line =~ OFFTAG_OPEN
993
- codepre += 1
994
- elsif line =~ OFFTAG_CLOSE
995
- codepre -= 1
996
- codepre = 0 if codepre < 0
997
- end
998
- elsif codepre.zero?
999
- glyphs_textile( line, level + 1 )
1000
- else
1001
- htmlesc( line, :NoQuotes )
1002
- end
1003
- # p [level, codepre, line]
1004
-
1005
- line
1006
- end
1007
- end
1008
- end
1009
-
1010
- def rip_offtags( text )
1011
- if text =~ /<.*>/
1012
- ## strip and encode <pre> content
1013
- codepre, used_offtags = 0, {}
1014
- text.gsub!( OFFTAG_MATCH ) do |line|
1015
- if $3
1016
- offtag, aftertag = $4, $5
1017
- codepre += 1
1018
- used_offtags[offtag] = true
1019
- if codepre - used_offtags.length > 0
1020
- htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
1021
- @pre_list.last << line
1022
- line = ""
1023
- else
1024
- htmlesc( aftertag, :NoQuotes ) if aftertag and not used_offtags['notextile']
1025
- line = "<redpre##{ @pre_list.length }>"
1026
- @pre_list << "#{ $3 }#{ aftertag }"
1027
- end
1028
- elsif $1 and codepre > 0
1029
- if codepre - used_offtags.length > 0
1030
- htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
1031
- @pre_list.last << line
1032
- line = ""
1033
- end
1034
- codepre -= 1 unless codepre.zero?
1035
- used_offtags = {} if codepre.zero?
1036
- end
1037
- line
1038
- end
1039
- end
1040
- text
1041
- end
1042
-
1043
- def smooth_offtags( text )
1044
- unless @pre_list.empty?
1045
- ## replace <pre> content
1046
- text.gsub!( /<redpre#(\d+)>/ ) { @pre_list[$1.to_i] }
1047
- end
1048
- end
1049
-
1050
- def inline( text )
1051
- [/^inline_/, /^glyphs_/].each do |meth_re|
1052
- @rules.each do |rule_name|
1053
- method( rule_name ).call( text ) if rule_name.to_s.match( meth_re )
1054
- end
1055
- end
1056
- end
1057
-
1058
- def h_align( text )
1059
- H_ALGN_VALS[text]
1060
- end
1061
-
1062
- def v_align( text )
1063
- V_ALGN_VALS[text]
1064
- end
1065
-
1066
- def textile_popup_help( name, windowW, windowH )
1067
- ' <a target="_blank" href="http://hobix.com/textile/#' + helpvar + '" onclick="window.open(this.href, \'popupwindow\', \'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\'); return false;">' + name + '</a><br />'
1068
- end
1069
-
1070
- # HTML cleansing stuff
1071
- BASIC_TAGS = {
1072
- 'a' => ['href', 'title'],
1073
- 'img' => ['src', 'alt', 'title'],
1074
- 'br' => [],
1075
- 'i' => nil,
1076
- 'u' => nil,
1077
- 'b' => nil,
1078
- 'pre' => nil,
1079
- 'kbd' => nil,
1080
- 'code' => ['lang'],
1081
- 'cite' => nil,
1082
- 'strong' => nil,
1083
- 'em' => nil,
1084
- 'ins' => nil,
1085
- 'sup' => nil,
1086
- 'sub' => nil,
1087
- 'del' => nil,
1088
- 'table' => nil,
1089
- 'tr' => nil,
1090
- 'td' => ['colspan', 'rowspan'],
1091
- 'th' => nil,
1092
- 'ol' => nil,
1093
- 'ul' => nil,
1094
- 'li' => nil,
1095
- 'p' => nil,
1096
- 'h1' => nil,
1097
- 'h2' => nil,
1098
- 'h3' => nil,
1099
- 'h4' => nil,
1100
- 'h5' => nil,
1101
- 'h6' => nil,
1102
- 'blockquote' => ['cite']
1103
- }
1104
-
1105
- def clean_html( text, tags = BASIC_TAGS )
1106
- text.gsub!( /<!\[CDATA\[/, '' )
1107
- text.gsub!( /<(\/*)(\w+)([^>]*)>/ ) do
1108
- raw = $~
1109
- tag = raw[2].downcase
1110
- if tags.has_key? tag
1111
- pcs = [tag]
1112
- tags[tag].each do |prop|
1113
- ['"', "'", ''].each do |q|
1114
- q2 = ( q != '' ? q : '\s' )
1115
- if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i
1116
- attrv = $1
1117
- next if prop == 'src' and attrv =~ %r{^(?!http)\w+:}
1118
- pcs << "#{prop}=\"#{$1.gsub('"', '\\"')}\""
1119
- break
1120
- end
1121
- end
1122
- end if tags[tag]
1123
- "<#{raw[1]}#{pcs.join " "}>"
1124
- else
1125
- " "
1126
- end
1127
- end
1128
- end
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'redcloth_scan'
4
+ require 'redcloth/version'
5
+ require 'redcloth/textile_doc'
6
+ require 'redcloth/formatters/base'
7
+ require 'redcloth/formatters/html'
8
+ require 'redcloth/formatters/latex'
9
+
10
+ module RedCloth
11
+
12
+ # A convenience method for creating a new TextileDoc. See
13
+ # RedCloth::TextileDoc.
14
+ def self.new( *args, &block )
15
+ RedCloth::TextileDoc.new( *args, &block )
16
+ end
17
+
18
+ # Include extension modules (if any) in TextileDoc.
19
+ def self.include(*args)
20
+ RedCloth::TextileDoc.send(:include, *args)
21
+ end
22
+
1129
23
  end
1130
24