pygments.rb 0.2.13 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +1 -0
  2. data/README.md +45 -19
  3. data/Rakefile +21 -11
  4. data/bench.rb +15 -48
  5. data/cache-lexers.rb +8 -0
  6. data/lexers +0 -0
  7. data/lib/pygments.rb +3 -6
  8. data/lib/pygments/mentos.py +343 -0
  9. data/lib/pygments/popen.rb +383 -0
  10. data/lib/pygments/version.rb +1 -1
  11. data/pygments.rb.gemspec +5 -4
  12. data/test/test_data.c +2581 -0
  13. data/test/test_data.py +514 -0
  14. data/test/test_data_generated +2582 -0
  15. data/test/test_pygments.rb +208 -84
  16. data/vendor/pygments-main/pygments/lexers/_mapping.py +1 -1
  17. data/vendor/pygments-main/pygments/lexers/shell.py +1 -1
  18. data/vendor/simplejson/.gitignore +10 -0
  19. data/vendor/simplejson/.travis.yml +5 -0
  20. data/vendor/simplejson/CHANGES.txt +291 -0
  21. data/vendor/simplejson/LICENSE.txt +19 -0
  22. data/vendor/simplejson/MANIFEST.in +5 -0
  23. data/vendor/simplejson/README.rst +19 -0
  24. data/vendor/simplejson/conf.py +179 -0
  25. data/vendor/simplejson/index.rst +628 -0
  26. data/vendor/simplejson/scripts/make_docs.py +18 -0
  27. data/vendor/simplejson/setup.py +104 -0
  28. data/vendor/simplejson/simplejson/__init__.py +510 -0
  29. data/vendor/simplejson/simplejson/_speedups.c +2745 -0
  30. data/vendor/simplejson/simplejson/decoder.py +425 -0
  31. data/vendor/simplejson/simplejson/encoder.py +567 -0
  32. data/vendor/simplejson/simplejson/ordered_dict.py +119 -0
  33. data/vendor/simplejson/simplejson/scanner.py +77 -0
  34. data/vendor/simplejson/simplejson/tests/__init__.py +67 -0
  35. data/vendor/simplejson/simplejson/tests/test_bigint_as_string.py +55 -0
  36. data/vendor/simplejson/simplejson/tests/test_check_circular.py +30 -0
  37. data/vendor/simplejson/simplejson/tests/test_decimal.py +66 -0
  38. data/vendor/simplejson/simplejson/tests/test_decode.py +83 -0
  39. data/vendor/simplejson/simplejson/tests/test_default.py +9 -0
  40. data/vendor/simplejson/simplejson/tests/test_dump.py +67 -0
  41. data/vendor/simplejson/simplejson/tests/test_encode_basestring_ascii.py +46 -0
  42. data/vendor/simplejson/simplejson/tests/test_encode_for_html.py +32 -0
  43. data/vendor/simplejson/simplejson/tests/test_errors.py +34 -0
  44. data/vendor/simplejson/simplejson/tests/test_fail.py +91 -0
  45. data/vendor/simplejson/simplejson/tests/test_float.py +19 -0
  46. data/vendor/simplejson/simplejson/tests/test_indent.py +86 -0
  47. data/vendor/simplejson/simplejson/tests/test_item_sort_key.py +20 -0
  48. data/vendor/simplejson/simplejson/tests/test_namedtuple.py +121 -0
  49. data/vendor/simplejson/simplejson/tests/test_pass1.py +76 -0
  50. data/vendor/simplejson/simplejson/tests/test_pass2.py +14 -0
  51. data/vendor/simplejson/simplejson/tests/test_pass3.py +20 -0
  52. data/vendor/simplejson/simplejson/tests/test_recursion.py +67 -0
  53. data/vendor/simplejson/simplejson/tests/test_scanstring.py +117 -0
  54. data/vendor/simplejson/simplejson/tests/test_separators.py +42 -0
  55. data/vendor/simplejson/simplejson/tests/test_speedups.py +20 -0
  56. data/vendor/simplejson/simplejson/tests/test_tuple.py +49 -0
  57. data/vendor/simplejson/simplejson/tests/test_unicode.py +109 -0
  58. data/vendor/simplejson/simplejson/tool.py +39 -0
  59. metadata +80 -22
  60. data/ext/extconf.rb +0 -14
  61. data/ext/pygments.c +0 -466
  62. data/lib/pygments/c.rb +0 -54
  63. data/lib/pygments/ffi.rb +0 -155
  64. data/vendor/.gitignore +0 -1
data/.gitignore CHANGED
@@ -3,3 +3,4 @@ ext/Makefile
3
3
  lib/pygments_ext.*
4
4
  tmp
5
5
  pkg
6
+ *.pyc
data/README.md CHANGED
@@ -1,14 +1,23 @@
1
1
  # pygments.rb
2
2
 
3
- A ruby wrapper for the python [pygments syntax highlighter](http://pygments.org/).
3
+ A Ruby wrapper for the Python [pygments syntax highlighter](http://pygments.org/).
4
4
 
5
- This library replaces [github/albino](https://github.com/github/albino).
6
- Instead of shelling out to `pygmentize`, it embeds the python
7
- interpreter inside ruby via FFI. This avoids the cost of setting up the
8
- python VM on every invocation and speeds up code highlighting from ruby by 10-15x.
5
+ pygments.rb works by talking over a simple pipe to a long-lived
6
+ Python child process. This library replaces [github/albino](https://github.com/github/albino),
7
+ as well as a version of pygments.rb that used an embedded Python
8
+ interpreter.
9
+
10
+ Each Ruby process that runs has its own 'personal Python';
11
+ for example, 4 Unicorn workers will have one Python process each.
12
+ If a Python process dies, a new one will be spawned on the next
13
+ pygments.rb request.
9
14
 
10
15
  ## usage
11
16
 
17
+ ``` ruby
18
+ require 'pygments'
19
+ ```
20
+
12
21
  ``` ruby
13
22
  Pygments.highlight(File.read(__FILE__), :lexer => 'ruby')
14
23
  ```
@@ -20,29 +29,34 @@ options hash:
20
29
  Pygments.highlight('code', :options => {:encoding => 'utf-8'})
21
30
  ```
22
31
 
23
- To use a formatter other than html, specify it explicitly:
32
+ pygments.rb defaults to using an HTML formatter.
33
+ To use a formatter other than `html`, specify it explicitly
34
+ like so:
24
35
 
25
36
  ``` ruby
26
37
  Pygments.highlight('code', :formatter => 'bbcode')
27
38
  Pygments.highlight('code', :formatter => 'terminal')
28
39
  ```
29
40
 
30
- To generate CSS for html formatted code, use the css method:
41
+ To generate CSS for HTML formatted code, use the `#css` method:
31
42
 
32
43
  ``` ruby
33
44
  Pygments.css
34
45
  Pygments.css('.highlight')
35
46
  ```
36
47
 
37
- To use a custom python installation (like in ArchLinux), tell
38
- RubyPython where python lives:
48
+ Other Pygments high-level API methods are also available.
49
+ These methods return arrays detailing all the available lexers, formatters,
50
+ and styles.
39
51
 
40
52
  ``` ruby
41
- RubyPython.configure :python_exe => 'python2.7'
53
+ Pygments.lexers
54
+ Pygments.formatters
55
+ Pygments.styles
42
56
  ```
43
57
 
44
58
  To use a custom pygments installation, specify the path to
45
- Pygments.start:
59
+ `Pygments#start`:
46
60
 
47
61
  ``` ruby
48
62
  Pygments.start("/path/to/pygments")
@@ -50,12 +64,24 @@ Pygments.start("/path/to/pygments")
50
64
 
51
65
  ## benchmarks
52
66
 
53
- $ ruby -rubygems bench.rb 50
54
- user system total real
55
- albino 0.050000 0.050000 12.830000 ( 13.180806)
56
- pygments::c 1.000000 0.010000 1.010000 ( 1.009348)
57
- pygments::ffi + reload 11.350000 1.240000 12.590000 ( 12.692320)
58
- pygments::ffi 1.130000 0.010000 1.140000 ( 1.171589)
59
67
 
60
- To run `bench.rb`, use a git checkout. The C extension is not included
61
- in gem releases.
68
+ $ ruby bench.rb 50
69
+ Benchmarking....
70
+ Size: 698 bytes
71
+ Iterations: 50
72
+ user system total real
73
+ pygments popen 0.010000 0.010000 0.020000 ( 0.460370)
74
+ pygments popen (process already started) 0.010000 0.000000 0.010000 ( 0.272975)
75
+ pygments popen (process already started 2) 0.000000 0.000000 0.000000 ( 0.273589)
76
+
77
+ $ ruby bench.rb 10
78
+ Benchmarking....
79
+ Size: 15523 bytes
80
+ Iterations: 10
81
+ user system total real
82
+ pygments popen 0.000000 0.000000 0.000000 ( 0.819419)
83
+ pygments popen (process already started) 0.010000 0.000000 0.010000 ( 0.676515)
84
+ pygments popen (process already started 2) 0.000000 0.010000 0.010000 ( 0.674189)
85
+
86
+
87
+
data/Rakefile CHANGED
@@ -1,3 +1,6 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
1
4
  task :default => :test
2
5
 
3
6
  # ==========================================================
@@ -10,16 +13,6 @@ require 'rake/gempackagetask'
10
13
  Rake::GemPackageTask.new(GEMSPEC) do |pkg|
11
14
  end
12
15
 
13
- # ==========================================================
14
- # Ruby Extension
15
- # ==========================================================
16
-
17
- require 'rake/extensiontask'
18
- Rake::ExtensionTask.new('pygments_ext', GEMSPEC) do |ext|
19
- ext.ext_dir = 'ext'
20
- end
21
- task :build => :compile
22
-
23
16
  # ==========================================================
24
17
  # Testing
25
18
  # ==========================================================
@@ -29,7 +22,24 @@ Rake::TestTask.new 'test' do |t|
29
22
  t.test_files = FileList['test/test_*.rb']
30
23
  t.ruby_opts = ['-rubygems']
31
24
  end
32
- task :test => :build
25
+
26
+ # ==========================================================
27
+ # Benchmarking
28
+ # ==========================================================
29
+
30
+ task :bench do
31
+ sh "ruby bench.rb"
32
+ end
33
+
34
+ # ==========================================================
35
+ # Cache lexers
36
+ # # ==========================================================
37
+
38
+ # Write all the lexers to a file for easy lookup
39
+ task :lexers do
40
+ sh "ruby cache-lexers.rb"
41
+ end
42
+
33
43
 
34
44
  # ==========================================================
35
45
  # Vendor
data/bench.rb CHANGED
@@ -1,55 +1,22 @@
1
- $:.unshift('lib')
2
-
1
+ require File.join(File.dirname(__FILE__), '/lib/pygments.rb')
3
2
  require 'benchmark'
4
- require 'pygments/c'
5
- require 'pygments/ffi'
6
- require 'rubygems'
7
- require 'albino'
8
3
 
9
- num = ARGV[0] ? ARGV[0].to_i : 25
10
- code = File.read(__FILE__)
4
+ include Benchmark
5
+ # number of iterations
6
+ num = ARGV[0] ? ARGV[0].to_i : 10
11
7
 
12
- albino, pygments, ffi =
13
- Albino.new(code, :ruby, :html).colorize,
14
- Pygments::C.highlight(code, :lexer => 'ruby'),
15
- Pygments::FFI.highlight(code, :lexer => 'ruby')
8
+ # we can also repeat the code itself
9
+ repeats = ARGV[1] ? ARGV[1].to_i : 1
16
10
 
17
- unless albino == pygments and pygments == ffi
18
- raise "incompatible implementations (#{albino.size} != #{pygments.size} != #{ffi.size})"
19
- end
11
+ code = File.open('test/test_data.py').read.to_s * repeats
20
12
 
21
- Benchmark.bm(25) do |x|
22
- x.report('albino') do
23
- num.times do
24
- Albino.new(code, :ruby, :html).colorize
25
- end
26
- end
27
- x.report('pygments::c') do
28
- num.times do
29
- Pygments::C.highlight(code, :lexer => 'ruby')
30
- end
31
- end
32
- x.report('pygments::ffi + reload') do
33
- num.times do
34
- Pygments::FFI.start
35
- Pygments::FFI.highlight(code, :lexer => 'ruby')
36
- Pygments::FFI.stop
37
- end
38
- end
39
- Pygments::FFI.start
40
- x.report('pygments::ffi') do
41
- num.times do
42
- Pygments::FFI.highlight(code, :lexer => 'ruby')
43
- end
44
- end
45
- end
13
+ puts "Benchmarking....\n"
14
+ puts "Size: " + code.bytesize.to_s + " bytes\n"
15
+ puts "Iterations: " + num.to_s + "\n"
46
16
 
47
- __END__
48
-
49
- $ ruby -rubygems bench.rb 50
50
- user system total real
51
- albino 0.050000 0.050000 12.830000 ( 13.180806)
52
- pygments::c 1.000000 0.010000 1.010000 ( 1.009348)
53
- pygments::ffi + reload 11.350000 1.240000 12.590000 ( 12.692320)
54
- pygments::ffi 1.130000 0.010000 1.140000 ( 1.171589)
17
+ Benchmark.bm(40) do |x|
18
+ x.report("pygments popen ") { for i in 1..num; Pygments.highlight(code, :lexer => 'python'); end }
19
+ x.report("pygments popen (process already started) ") { for i in 1..num; Pygments.highlight(code, :lexer => 'python'); end }
20
+ x.report("pygments popen (process already started 2) ") { for i in 1..num; Pygments.highlight(code, :lexer => 'python'); end }
21
+ end
55
22
 
data/cache-lexers.rb ADDED
@@ -0,0 +1,8 @@
1
+ require File.join(File.dirname(__FILE__), '/lib/pygments.rb')
2
+
3
+ # Simple marshalling
4
+ serialized_lexers = Marshal.dump(Pygments.lexers!)
5
+
6
+ # Write to a file
7
+ File.open("lexers", 'w') { |file| file.write(serialized_lexers) }
8
+
data/lexers ADDED
Binary file
data/lib/pygments.rb CHANGED
@@ -1,11 +1,8 @@
1
- # require 'pygments/c'
2
- require 'pygments/ffi'
1
+ require File.join(File.dirname(__FILE__), 'pygments/popen')
2
+
3
3
 
4
4
  module Pygments
5
- # include Pygments::C
6
- include Pygments::FFI
5
+ extend Pygments::Popen
7
6
 
8
7
  autoload :Lexer, 'pygments/lexer'
9
-
10
- extend self
11
8
  end
@@ -0,0 +1,343 @@
1
+ #!/usr/bin/python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import sys, re, os, signal, resource
5
+ import traceback
6
+ if 'PYGMENTS_PATH' in os.environ:
7
+ sys.path.insert(0, os.environ['PYGMENTS_PATH'])
8
+
9
+ dirname = os.path.dirname
10
+
11
+ base_dir = dirname(dirname(dirname(os.path.abspath(__file__))))
12
+ sys.path.append(base_dir + "/vendor")
13
+ sys.path.append(base_dir + "/vendor/pygments-main")
14
+ sys.path.append(base_dir + "/vendor/simplejson")
15
+
16
+ import pygments
17
+ from pygments import lexers, formatters, styles, filters
18
+
19
+ from threading import Lock
20
+
21
+ try:
22
+ import json
23
+ except ImportError:
24
+ import simplejson as json
25
+
26
+ def _convert_keys(dictionary):
27
+ if not isinstance(dictionary, dict):
28
+ return dictionary
29
+ return dict((str(k), _convert_keys(v))
30
+ for k, v in dictionary.items())
31
+
32
+ def _write_error(error):
33
+ res = {"error": error}
34
+ out_header = json.dumps(res).encode('utf-8')
35
+ bits = _get_fixed_bits_from_header(out_header)
36
+ sys.stdout.write(bits + "\n")
37
+ sys.stdout.flush()
38
+ sys.stdout.write(out_header + "\n")
39
+ sys.stdout.flush()
40
+ return
41
+
42
+ def _get_fixed_bits_from_header(out_header):
43
+ size = len(out_header)
44
+ return "".join(map(lambda y:str((size>>y)&1), range(32-1, -1, -1)))
45
+
46
+ def _signal_handler(signal, frame):
47
+ """
48
+ Handle the signal given in the first argument, exiting gracefully
49
+ """
50
+ sys.exit(0)
51
+
52
+ class Mentos(object):
53
+ """
54
+ Interacts with pygments.rb to provide access to pygments functionality
55
+ """
56
+ def __init__(self):
57
+ pass
58
+
59
+ def return_lexer(self, lexer, args, inputs, code=None):
60
+ """
61
+ Accepting a variety of possible inputs, return a Lexer object.
62
+
63
+ The inputs argument should be a hash with at least one of the following
64
+ keys:
65
+
66
+ - 'lexer' ("python")
67
+ - 'mimetype' ("text/x-ruby")
68
+ - 'filename' ("yeaaah.py")
69
+ - 'code' ("import derp" etc)
70
+
71
+ The code guessing method is not especially great. It is advised that
72
+ clients pass in a literal lexer name whenever possible, which provides
73
+ the best probability of match (100 percent).
74
+ """
75
+
76
+ if lexer:
77
+ if inputs:
78
+ return lexers.get_lexer_by_name(lexer, **inputs)
79
+ else:
80
+ return lexers.get_lexer_by_name(lexer)
81
+
82
+ if inputs:
83
+ if 'lexer' in inputs:
84
+ return lexers.get_lexer_by_name(inputs['lexer'], **inputs)
85
+
86
+ elif 'mimetype' in inputs:
87
+ return lexers.get_lexer_for_mimetype(inputs['mimetype'], **inputs)
88
+
89
+ elif 'filename' in inputs:
90
+ name = inputs['filename']
91
+
92
+ # If we have code and a filename, pygments allows us to guess
93
+ # with both. This is better than just guessing with code.
94
+ if code:
95
+ return lexers.guess_lexer_for_filename(name, code, **inputs)
96
+ else:
97
+ return lexers.get_lexer_for_filename(name, **inputs)
98
+
99
+ # If all we got is code, try anyway.
100
+ if code:
101
+ return lexers.guess_lexer(code, **inputs)
102
+
103
+ else:
104
+ _write_error("No lexer")
105
+
106
+
107
+ def highlight_text(self, code, lexer, formatter_name, args, kwargs):
108
+ """
109
+ Highlight the relevant code, and return a result string.
110
+ The default formatter is html, but alternate formatters can be passed in via
111
+ the formatter_name argument. Additional paramters can be passed as args
112
+ or kwargs.
113
+ """
114
+ # Default to html if we don't have the formatter name.
115
+ if formatter_name:
116
+ _format_name = str(formatter_name)
117
+ else:
118
+ _format_name = "html"
119
+
120
+ # Return a lexer object
121
+ lexer = self.return_lexer(lexer, args, kwargs, code)
122
+
123
+ # Make sure we sucessfuly got a lexer
124
+ if lexer:
125
+ formatter = pygments.formatters.get_formatter_by_name(str.lower(_format_name), **kwargs)
126
+
127
+ # Do the damn thing.
128
+ res = pygments.highlight(code, lexer, formatter)
129
+
130
+ return res
131
+
132
+ else:
133
+ _write_error("No lexer")
134
+
135
+ def get_data(self, method, lexer, args, kwargs, text=None):
136
+ """
137
+ Based on the method argument, determine the action we'd like pygments
138
+ to do. Then return the data generated from pygments.
139
+ """
140
+ if kwargs:
141
+ formatter_name = kwargs.get("formatter", None)
142
+ opts = kwargs.get("options", {})
143
+
144
+ # Ensure there's a 'method' key before proceeeding
145
+ if method:
146
+ res = None
147
+
148
+ # Now check what that method is. For the get methods, pygments
149
+ # itself returns generators, so we make them lists so we can serialize
150
+ # easier.
151
+ if method == 'get_all_styles':
152
+ res = json.dumps(list(pygments.styles.get_all_styles()))
153
+
154
+ elif method == 'get_all_filters':
155
+ res = json.dumps(list(pygments.filters.get_all_filters()))
156
+
157
+ elif method == 'get_all_lexers':
158
+ res = json.dumps(list(pygments.lexers.get_all_lexers()))
159
+
160
+ elif method == 'get_all_formatters':
161
+ res = [ [ft.__name__, ft.name, ft.aliases] for ft in pygments.formatters.get_all_formatters() ]
162
+ res = json.dumps(res)
163
+
164
+ elif method == 'highlight':
165
+ try:
166
+ text = text.decode('utf-8')
167
+ except UnicodeDecodeError:
168
+ # The text may already be encoded
169
+ text = text
170
+ res = self.highlight_text(text, lexer, formatter_name, args, _convert_keys(opts))
171
+
172
+ elif method == 'css':
173
+ kwargs = _convert_keys(kwargs)
174
+ fmt = pygments.formatters.get_formatter_by_name(args[0], **kwargs)
175
+ res = fmt.get_style_defs(args[1])
176
+
177
+ elif method == 'lexer_name_for':
178
+ lexer = self.return_lexer(None, args, kwargs, text)
179
+
180
+ if lexer:
181
+ # We don't want the Lexer itself, just the name.
182
+ # Take the first alias.
183
+ res = lexer.aliases[0]
184
+
185
+ else:
186
+ _write_error("No lexer")
187
+
188
+ else:
189
+ _write_error("No lexer")
190
+
191
+ return res
192
+
193
+
194
+ def _send_data(self, res, method):
195
+
196
+ # Base header. We'll build on this, adding keys as necessary.
197
+ base_header = {"method": method}
198
+
199
+ res_bytes = len(res) + 1
200
+ base_header["bytes"] = res_bytes
201
+
202
+ out_header = json.dumps(base_header).encode('utf-8')
203
+
204
+ # Following the protocol, send over a fixed size represenation of the
205
+ # size of the JSON header
206
+ bits = _get_fixed_bits_from_header(out_header)
207
+
208
+ # Send it to Rubyland
209
+ sys.stdout.write(bits + "\n")
210
+ sys.stdout.flush()
211
+
212
+ # Send the header.
213
+ sys.stdout.write(out_header + "\n")
214
+ sys.stdout.flush()
215
+
216
+ # Finally, send the result
217
+ sys.stdout.write(res + "\n")
218
+ sys.stdout.flush()
219
+
220
+
221
+ def _get_ids(self, text):
222
+ start_id = text[:8]
223
+ end_id = text[-8:]
224
+ return start_id, end_id
225
+
226
+ def _check_and_return_text(self, text, start_id, end_id):
227
+
228
+ # Sanity check.
229
+ id_regex = re.compile('[A-Z]{8}')
230
+
231
+ if not id_regex.match(start_id) and not id_regex.match(end_id):
232
+ _write_error("ID check failed. Not an ID.")
233
+
234
+ if not start_id == end_id:
235
+ _write_error("ID check failed. ID's did not match.")
236
+
237
+ # Passed the sanity check. Remove the id's and return
238
+ text = text[10:-10]
239
+ return text
240
+
241
+ def _parse_header(self, header):
242
+ method = header["method"]
243
+ args = header.get("args", [])
244
+ kwargs = header.get("kwargs", {})
245
+ lexer = kwargs.get("lexer", None)
246
+ return (method, args, kwargs, lexer)
247
+
248
+ def start(self):
249
+ """
250
+ Main loop, waiting for inputs on stdin. When it gets some data,
251
+ it goes to work.
252
+
253
+ mentos exposes most of the "High-level API" of pygments. It always
254
+ expects and requires a JSON header of metadata. If there is data to be
255
+ pygmentized, this header will be followed by the text to be pygmentized.
256
+
257
+ The header is of form:
258
+ { "method": "highlight", "args": [], "kwargs": {"arg1": "v"}, "bytes": 128, "fd": "8"}
259
+ """
260
+ lock = Lock()
261
+
262
+ while True:
263
+ # The loop begins by reading off a simple 32-arity string
264
+ # representing an integer of 32 bits. This is the length of
265
+ # our JSON header.
266
+ size = sys.stdin.read(32)
267
+
268
+ lock.acquire()
269
+
270
+ try:
271
+ # Read from stdin the amount of bytes we were told to expect.
272
+ header_bytes = int(size, 2)
273
+
274
+ # Sanity check the size
275
+ size_regex = re.compile('[0-1]{32}')
276
+ if not size_regex.match(size):
277
+ _write_error("Size received is not valid.")
278
+
279
+ line = sys.stdin.read(header_bytes)
280
+
281
+ header = json.loads(line)
282
+
283
+ method, args, kwargs, lexer = self._parse_header(header)
284
+ _bytes = 0
285
+
286
+ if lexer:
287
+ lexer = str(lexer)
288
+
289
+ # Read more bytes if necessary
290
+ if kwargs:
291
+ _bytes = kwargs.get("bytes", 0)
292
+
293
+ # Read up to the given number bytes (possibly 0)
294
+ text = sys.stdin.read(_bytes)
295
+
296
+ # Sanity check the return.
297
+ if method == 'highlight':
298
+ start_id, end_id = self._get_ids(text)
299
+ text = self._check_and_return_text(text, start_id, end_id)
300
+
301
+ # Get the actual data from pygments.
302
+ res = self.get_data(method, lexer, args, kwargs, text)
303
+
304
+ # Put back the sanity check values.
305
+ if method == "highlight":
306
+ res = start_id + " " + res + " " + end_id
307
+
308
+ self._send_data(res, method)
309
+
310
+ except:
311
+ tb = traceback.format_exc()
312
+ _write_error(tb)
313
+
314
+ finally:
315
+ lock.release()
316
+
317
+ def main():
318
+
319
+ # Signal handlers to trap signals.
320
+ signal.signal(signal.SIGINT, _signal_handler)
321
+ signal.signal(signal.SIGTERM, _signal_handler)
322
+ signal.signal(signal.SIGHUP, _signal_handler)
323
+
324
+ mentos = Mentos()
325
+
326
+ # close fd's inherited from the ruby parent
327
+ maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
328
+ if maxfd == resource.RLIM_INFINITY:
329
+ maxfd = 65536
330
+
331
+ for fd in range(3, maxfd):
332
+ try:
333
+ os.close(fd)
334
+ except:
335
+ pass
336
+
337
+ mentos.start()
338
+
339
+ if __name__ == "__main__":
340
+ main()
341
+
342
+
343
+