pygments.rb 0.2.13 → 0.3.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.
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
+