syntaxi 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/syntaxi.rb +274 -0
  2. metadata +49 -0
@@ -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 += "&nbsp;\n"
213
+ out_code += line.sub(/\a/, '')
214
+ else
215
+ i += 1
216
+ out_numbers += i.to_s.rjust(width).gsub(/ /, '&nbsp;') + "\n"
217
+ out_code += line.sub(/^ */) {
218
+ $& ? $&.gsub(/ /, '&nbsp;') : ''
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: