syntaxi 0.5.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/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:
|