syntaxi 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/syntaxi.rb +274 -0
- metadata +49 -0
data/lib/syntaxi.rb
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'syntax/convertors/html'
|
2
|
+
|
3
|
+
# Syntaxi is a class for formatting code blocks in your HTML. It can:
|
4
|
+
# * Add line numbers
|
5
|
+
# * Wrap long lines automatically
|
6
|
+
# * Perform syntax coloring using Jamis Buck's Syntax gem
|
7
|
+
#
|
8
|
+
# == How to Write your Code Block
|
9
|
+
#
|
10
|
+
# In order for Syntaxi to do its magic, you'll need to write your code blocks
|
11
|
+
# like this:
|
12
|
+
#
|
13
|
+
# [code lang="ruby"]
|
14
|
+
# def foo
|
15
|
+
# puts 'bar'
|
16
|
+
# end
|
17
|
+
# [/code]
|
18
|
+
#
|
19
|
+
# The square bracket syntax allows Syntaxi to work seamlessly in HTML,
|
20
|
+
# Markdown, and Textile alike. The +lang+ attribute specifies the language
|
21
|
+
# of the code block.
|
22
|
+
#
|
23
|
+
# == How to Process the Text
|
24
|
+
#
|
25
|
+
# Having Syntaxi format your code containing the special code blocks is easy.
|
26
|
+
# Lets say your text is stored in +text+. To format this text simply do the
|
27
|
+
# following:
|
28
|
+
#
|
29
|
+
# text = Syntaxi.new(text).process
|
30
|
+
#
|
31
|
+
# == Syntax coloring
|
32
|
+
#
|
33
|
+
# If the +lang+ attribute you specified in your opening code block tag
|
34
|
+
# is recognized by Jamis Buck's Syntax gem, the block will have syntax coloring
|
35
|
+
# applied to it automatically. See the documentation for Syntax to learn
|
36
|
+
# more about how to style the different spans it produces.
|
37
|
+
#
|
38
|
+
# == Line Numbers
|
39
|
+
#
|
40
|
+
# Syntaxi can also add line numbers to your code blocks. It can do this in two
|
41
|
+
# different ways:
|
42
|
+
# * Inline line numbering will add line numbers at the beginning of each line.
|
43
|
+
# * Floating line numbering will create a <div> to contain the line numbers and
|
44
|
+
# float that <div> left, so that selecting text from the code block will
|
45
|
+
# select only the code, and not the line numbers.
|
46
|
+
#
|
47
|
+
# By default, line numbering is set to +inline+. To change the line number
|
48
|
+
# method, simply call line_number_method= like so:
|
49
|
+
#
|
50
|
+
# Syntaxi.line_number_method = 'floating'
|
51
|
+
#
|
52
|
+
# Valid values are 'none', 'inline', and 'floating'
|
53
|
+
#
|
54
|
+
# == Line Wrap
|
55
|
+
#
|
56
|
+
# Because your code blocks will often have lines that are longer than the
|
57
|
+
# available width, Syntaxi can wrap long lines for you. If possible the line
|
58
|
+
# break will done on a space. No line numbers will appear on the wrapped
|
59
|
+
# portions of long lines (but subsequent lines will still have the right
|
60
|
+
# line numbers).
|
61
|
+
#
|
62
|
+
# By default, line wrap is enabled and wraps on column 60. To disable line
|
63
|
+
# wrap, simply call wrap_enabled= with +false+:
|
64
|
+
#
|
65
|
+
# Syntaxi.wrap_enabled = false
|
66
|
+
#
|
67
|
+
# To change the column on which to wrap, call wrap_at_column= like this:
|
68
|
+
#
|
69
|
+
# Syntaxi.wrap_at_column = 70
|
70
|
+
#
|
71
|
+
# == Where to set the Options
|
72
|
+
#
|
73
|
+
# Since the configuration options are stored as class variables, you need only change
|
74
|
+
# them once, and all future instances of Syntaxi will use the new values.
|
75
|
+
# If your entire application will use the same values, simply set the values
|
76
|
+
# to your liking at the beginning of execution. In Ruby on Rails, an ideal
|
77
|
+
# place to do this is in [RAILS_ROOT]/config/environment.rb.
|
78
|
+
class Syntaxi
|
79
|
+
|
80
|
+
# Specifies the line numbering method
|
81
|
+
# one of [none|floating|inline]
|
82
|
+
@@line_number_method = 'inline'
|
83
|
+
|
84
|
+
# Sets the line number method. Valid values are 'none', 'floating', or
|
85
|
+
# 'inline'. Default is +'inline'+
|
86
|
+
#
|
87
|
+
# See Syntaxi class documentation for more information.
|
88
|
+
def self.line_number_method=(meth)
|
89
|
+
%w{none floating inline}.include?(meth) || raise("Invalid Line Number Method. Must be one of [none|floating|inline].")
|
90
|
+
@@line_number_method = meth
|
91
|
+
end
|
92
|
+
|
93
|
+
# specifies whether or not to wrap long lines
|
94
|
+
@@wrap_enabled = true
|
95
|
+
|
96
|
+
# Sets whether or not to wrap long lines. Defaults is +true+
|
97
|
+
#
|
98
|
+
# See Syntaxi class documentation for more information.
|
99
|
+
def self.wrap_enabled=(enabled)
|
100
|
+
@@wrap_enabled = enabled
|
101
|
+
end
|
102
|
+
|
103
|
+
# Specifies the column on which to wrap if line wrap is enabled
|
104
|
+
@@wrap_at_column = 60
|
105
|
+
|
106
|
+
# Sets the column on which to wrap if line wrap is enabled. Defaults to
|
107
|
+
# +65+
|
108
|
+
#
|
109
|
+
# See Syntaxi class documentation for more information.
|
110
|
+
def self.wrap_at_column=(col)
|
111
|
+
@@wrap_at_column = col
|
112
|
+
end
|
113
|
+
|
114
|
+
# Instance variable to hold the code
|
115
|
+
@text
|
116
|
+
|
117
|
+
def initialize(text) #:nodoc:
|
118
|
+
@text = text
|
119
|
+
end
|
120
|
+
|
121
|
+
# Processes the text that this object was initialized with according to the
|
122
|
+
# configuration parameters.
|
123
|
+
def process
|
124
|
+
# pick out any existing <code> blocks and replace with a placeholder
|
125
|
+
ignores = {}
|
126
|
+
ignore_index = 0
|
127
|
+
@text.gsub!(/<code.*?code>/m){
|
128
|
+
ignore_index += 1
|
129
|
+
ignores[ignore_index] = $&
|
130
|
+
"<!--syntaxi-code-ignore-block-" + ignore_index.to_s + "-->"
|
131
|
+
}
|
132
|
+
|
133
|
+
# format the specified sections
|
134
|
+
@text.gsub!(/\[code.+?lang\s?=\s?['"](.*?)['"].*?\](.*?)\[\/code\]/m){
|
135
|
+
language = $1
|
136
|
+
code = $2
|
137
|
+
|
138
|
+
# fix any spacy weirdness
|
139
|
+
code = code.sub(/^\s*\n*/, '')
|
140
|
+
code = code.gsub(/\t/, ' ')
|
141
|
+
code = code.gsub(/\r\n/, "\n")
|
142
|
+
|
143
|
+
# count the number of lines in this code block for later
|
144
|
+
line_count = code.split("\n").length
|
145
|
+
|
146
|
+
# do line wrapping if required
|
147
|
+
code = wrap_long_lines(code, line_count) if @@wrap_enabled
|
148
|
+
|
149
|
+
# do the syntax coloring
|
150
|
+
code = Syntax::Convertors::HTML.for_syntax(language).convert(code, false)
|
151
|
+
|
152
|
+
# do the line numbering
|
153
|
+
code =
|
154
|
+
case @@line_number_method
|
155
|
+
when 'none'
|
156
|
+
add_no_line_numbers(code)
|
157
|
+
when 'floating'
|
158
|
+
add_floating_line_numbers(code, line_count)
|
159
|
+
when 'inline'
|
160
|
+
add_inline_line_numbers(code, line_count)
|
161
|
+
end
|
162
|
+
|
163
|
+
# return the code to the gsub
|
164
|
+
code
|
165
|
+
}
|
166
|
+
|
167
|
+
# put the existing <code> blocks back in
|
168
|
+
@text.gsub!(/<!--syntaxi-code-ignore-block-(\d+?)-->/) {
|
169
|
+
ignores[$1.to_i]
|
170
|
+
}
|
171
|
+
|
172
|
+
# return all the processed text
|
173
|
+
@text
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
# No line numbering required, so just wrap the code block
|
179
|
+
def add_no_line_numbers(code) #:nodoc:
|
180
|
+
code.gsub!(/\a/, '')
|
181
|
+
"<pre><code>" + code + "</code></pre>"
|
182
|
+
end
|
183
|
+
|
184
|
+
# Inline line numbers are just numbers at the beginning of the actual line
|
185
|
+
# followed by some spaces.
|
186
|
+
def add_inline_line_numbers(code, lines) #:nodoc:
|
187
|
+
i = 0
|
188
|
+
out = ''
|
189
|
+
width = lines.to_s.length
|
190
|
+
code.each_line do |line|
|
191
|
+
if line =~ /\a/
|
192
|
+
out += line.sub(/\a/, '')
|
193
|
+
else
|
194
|
+
i += 1
|
195
|
+
out += "<span class=\"line_number\">" + i.to_s.rjust(width) + "</span>" + " " + line
|
196
|
+
end
|
197
|
+
end
|
198
|
+
"<pre><code>" + out + "</code></pre>"
|
199
|
+
end
|
200
|
+
|
201
|
+
# Floating line numbers are created by floating the line numbers left. This
|
202
|
+
# makes is possible to select the code in the web browser without also
|
203
|
+
# selecting the line numbers. Very useful, but can act strangely in some
|
204
|
+
# browsers, so use with caution
|
205
|
+
def add_floating_line_numbers(code, lines) #:nodoc:
|
206
|
+
i = 0
|
207
|
+
out_numbers = '<pre style="overflow: hidden;"><code class="line_number" style="float: left; margin-right: 1em">'
|
208
|
+
out_code = '<code>'
|
209
|
+
width = lines.to_s.length
|
210
|
+
code.each_line do |line|
|
211
|
+
if line =~ /\a/
|
212
|
+
out_numbers += " \n"
|
213
|
+
out_code += line.sub(/\a/, '')
|
214
|
+
else
|
215
|
+
i += 1
|
216
|
+
out_numbers += i.to_s.rjust(width).gsub(/ /, ' ') + "\n"
|
217
|
+
out_code += line.sub(/^ */) {
|
218
|
+
$& ? $&.gsub(/ /, ' ') : ''
|
219
|
+
}
|
220
|
+
end
|
221
|
+
end
|
222
|
+
out_numbers.chomp + '</code>' + out_code + '</code></pre>'
|
223
|
+
end
|
224
|
+
|
225
|
+
# Wrap long lines using intelligent line wrap (indent wrapped lines to match
|
226
|
+
# the indent of the line being wrapped)
|
227
|
+
def wrap_long_lines(code, lines) #:nodoc:
|
228
|
+
out = ''
|
229
|
+
line_wrap_indicator = "\a" # bell character is not modified by Syntax
|
230
|
+
line_num_width = lines.to_s.length # for inline line numbering
|
231
|
+
|
232
|
+
code.each_line do |line|
|
233
|
+
if line.length > @@wrap_at_column
|
234
|
+
|
235
|
+
# determine proper indent
|
236
|
+
line =~ /^\s*/
|
237
|
+
if @@line_number_method == 'inline'
|
238
|
+
indent = ' ' + (' ' * ($&.length + line_num_width))
|
239
|
+
else
|
240
|
+
indent = ' ' * $&.length
|
241
|
+
end
|
242
|
+
|
243
|
+
# split this line up into mutliple lines. break on spaces if possible
|
244
|
+
first_line = true
|
245
|
+
max_line_length = @@wrap_at_column
|
246
|
+
while line
|
247
|
+
if line.length < max_line_length
|
248
|
+
# last part
|
249
|
+
out += line_wrap_indicator + indent + line
|
250
|
+
line = nil
|
251
|
+
elsif i = line.rindex(/\s/, max_line_length)
|
252
|
+
# long part with a space in it
|
253
|
+
out += line_wrap_indicator + indent unless first_line
|
254
|
+
out += line[0, i + 1] + "\n"
|
255
|
+
line = line[i + 1, line.length]
|
256
|
+
else
|
257
|
+
# long part with no space in it
|
258
|
+
out += line_wrap_indicator + indent unless first_line
|
259
|
+
out += line[0, max_line_length] + "\n"
|
260
|
+
line = line[max_line_length, line.length]
|
261
|
+
end
|
262
|
+
# not the first line anymore
|
263
|
+
first_line = false
|
264
|
+
max_line_length = @@wrap_at_column - indent.length
|
265
|
+
end
|
266
|
+
|
267
|
+
else
|
268
|
+
out += line
|
269
|
+
end
|
270
|
+
end
|
271
|
+
out
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: syntaxi
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.5.0
|
7
|
+
date: 2005-12-12 00:00:00 -08:00
|
8
|
+
summary: "Syntaxi formats code blocks in text (line number, line wrap, syntax color)"
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: tom@cube6media.com
|
12
|
+
homepage: http://syntaxi.rubyforge.org
|
13
|
+
rubyforge_project: syntaxi
|
14
|
+
description:
|
15
|
+
autorequire: syntaxi
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Tom Werner
|
31
|
+
files:
|
32
|
+
- lib/syntaxi.rb
|
33
|
+
test_files: []
|
34
|
+
rdoc_options: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
requirements: []
|
39
|
+
dependencies:
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: syntax
|
42
|
+
version_requirement:
|
43
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
44
|
+
requirements:
|
45
|
+
-
|
46
|
+
- "="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 1.0.0
|
49
|
+
version:
|