ipython_console_highlighting.py
114 lines
| 4.1 KiB
| text/x-python
|
PythonLexer
Fernando Perez
|
r1850 | """reST directive for syntax-highlighting ipython interactive sessions. | ||
Brian Granger
|
r2275 | |||
XXX - See what improvements can be made based on the new (as of Sept 2009) | ||||
'pycon' lexer for the python console. At the very least it will give better | ||||
highlighted tracebacks. | ||||
Fernando Perez
|
r1850 | """ | ||
#----------------------------------------------------------------------------- | ||||
# Needed modules | ||||
# Standard library | ||||
import re | ||||
# Third party | ||||
Fernando Perez
|
r1694 | from pygments.lexer import Lexer, do_insertions | ||
Fernando Perez
|
r1850 | from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer, | ||
PythonTracebackLexer) | ||||
Fernando Perez
|
r1694 | from pygments.token import Comment, Generic | ||
Fernando Perez
|
r1850 | |||
Fernando Perez
|
r1694 | from sphinx import highlighting | ||
Fernando Perez
|
r1850 | #----------------------------------------------------------------------------- | ||
# Global constants | ||||
Fernando Perez
|
r1694 | line_re = re.compile('.*?\n') | ||
Fernando Perez
|
r1850 | #----------------------------------------------------------------------------- | ||
# Code begins - classes and functions | ||||
Fernando Perez
|
r1694 | class IPythonConsoleLexer(Lexer): | ||
""" | ||||
For IPython console output or doctests, such as: | ||||
.. sourcecode:: ipython | ||||
In [1]: a = 'foo' | ||||
In [2]: a | ||||
Out[2]: 'foo' | ||||
In [3]: print a | ||||
foo | ||||
In [4]: 1 / 0 | ||||
Fernando Perez
|
r1850 | |||
Notes: | ||||
- Tracebacks are not currently supported. | ||||
- It assumes the default IPython prompts, not customized ones. | ||||
Fernando Perez
|
r1694 | """ | ||
Fernando Perez
|
r1850 | |||
Fernando Perez
|
r1694 | name = 'IPython console session' | ||
aliases = ['ipython'] | ||||
mimetypes = ['text/x-ipython-console'] | ||||
input_prompt = re.compile("(In \[[0-9]+\]: )|( \.\.\.+:)") | ||||
output_prompt = re.compile("(Out\[[0-9]+\]: )|( \.\.\.+:)") | ||||
continue_prompt = re.compile(" \.\.\.+:") | ||||
tb_start = re.compile("\-+") | ||||
def get_tokens_unprocessed(self, text): | ||||
pylexer = PythonLexer(**self.options) | ||||
tblexer = PythonTracebackLexer(**self.options) | ||||
curcode = '' | ||||
insertions = [] | ||||
for match in line_re.finditer(text): | ||||
line = match.group() | ||||
input_prompt = self.input_prompt.match(line) | ||||
continue_prompt = self.continue_prompt.match(line.rstrip()) | ||||
output_prompt = self.output_prompt.match(line) | ||||
if line.startswith("#"): | ||||
insertions.append((len(curcode), | ||||
[(0, Comment, line)])) | ||||
elif input_prompt is not None: | ||||
insertions.append((len(curcode), | ||||
[(0, Generic.Prompt, input_prompt.group())])) | ||||
curcode += line[input_prompt.end():] | ||||
elif continue_prompt is not None: | ||||
insertions.append((len(curcode), | ||||
[(0, Generic.Prompt, continue_prompt.group())])) | ||||
curcode += line[continue_prompt.end():] | ||||
elif output_prompt is not None: | ||||
Brian Granger
|
r2275 | # Use the 'error' token for output. We should probably make | ||
# our own token, but error is typicaly in a bright color like | ||||
# red, so it works fine for our output prompts. | ||||
Fernando Perez
|
r1694 | insertions.append((len(curcode), | ||
Brian Granger
|
r2275 | [(0, Generic.Error, output_prompt.group())])) | ||
Fernando Perez
|
r1694 | curcode += line[output_prompt.end():] | ||
else: | ||||
if curcode: | ||||
for item in do_insertions(insertions, | ||||
pylexer.get_tokens_unprocessed(curcode)): | ||||
yield item | ||||
curcode = '' | ||||
insertions = [] | ||||
yield match.start(), Generic.Output, line | ||||
if curcode: | ||||
for item in do_insertions(insertions, | ||||
pylexer.get_tokens_unprocessed(curcode)): | ||||
yield item | ||||
Brian Granger
|
r2275 | |||
def setup(app): | ||||
"""Setup as a sphinx extension.""" | ||||
# This is only a lexer, so adding it below to pygments appears sufficient. | ||||
# But if somebody knows that the right API usage should be to do that via | ||||
# sphinx, by all means fix it here. At least having this setup.py | ||||
# suppresses the sphinx warning we'd get without it. | ||||
pass | ||||
Fernando Perez
|
r1850 | #----------------------------------------------------------------------------- | ||
# Register the extension as a valid pygments lexer | ||||
Fernando Perez
|
r1694 | highlighting.lexers['ipython'] = IPythonConsoleLexer() | ||