summaryrefslogtreecommitdiff
path: root/sphinx/directives/code.py
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2009-02-18 19:55:57 +0100
committerGeorg Brandl <georg@python.org>2009-02-18 19:55:57 +0100
commit044d42953db35999f68ff8d3f6f8a60d76cbc980 (patch)
treeb2ca978d76a2dd68243e7249946abba41d831aee /sphinx/directives/code.py
parent8bd4e8e3984bf4b0fbd0d5b7a19a7f5c81b882f6 (diff)
downloadsphinx-git-044d42953db35999f68ff8d3f6f8a60d76cbc980.tar.gz
Convert builtin directives to classes. Refactor desc_directive so that it is easier to subclass.
Diffstat (limited to 'sphinx/directives/code.py')
-rw-r--r--sphinx/directives/code.py284
1 files changed, 154 insertions, 130 deletions
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index 3162d5575..a66940857 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -16,135 +16,159 @@ from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.util import parselinenos
-
-
-# ------ highlight directive ---------------------------------------------------
-
-def highlightlang_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- if 'linenothreshold' in options:
- try:
- linenothreshold = int(options['linenothreshold'])
- except Exception:
- linenothreshold = 10
- else:
- linenothreshold = sys.maxint
- return [addnodes.highlightlang(lang=arguments[0].strip(),
- linenothreshold=linenothreshold)]
-
-highlightlang_directive.content = 0
-highlightlang_directive.arguments = (1, 0, 0)
-highlightlang_directive.options = {'linenothreshold': directives.unchanged}
-directives.register_directive('highlight', highlightlang_directive)
-# old name
-directives.register_directive('highlightlang', highlightlang_directive)
-
-
-# ------ code-block directive --------------------------------------------------
-
-def codeblock_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- code = u'\n'.join(content)
- literal = nodes.literal_block(code, code)
- literal['language'] = arguments[0]
- literal['linenos'] = 'linenos' in options
- return [literal]
-
-codeblock_directive.content = 1
-codeblock_directive.arguments = (1, 0, 0)
-codeblock_directive.options = {'linenos': directives.flag}
-directives.register_directive('code-block', codeblock_directive)
-directives.register_directive('sourcecode', codeblock_directive)
-
-
-# ------ literalinclude directive ----------------------------------------------
-
-def literalinclude_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- """Like .. include:: :literal:, but only warns if the include file is
- not found."""
- if not state.document.settings.file_insertion_enabled:
- return [state.document.reporter.warning('File insertion disabled',
- line=lineno)]
- env = state.document.settings.env
- rel_fn = arguments[0]
- source_dir = path.dirname(path.abspath(state_machine.input_lines.source(
- lineno - state_machine.input_offset - 1)))
- fn = path.normpath(path.join(source_dir, rel_fn))
-
- if 'pyobject' in options and 'lines' in options:
- return [state.document.reporter.warning(
- 'Cannot use both "pyobject" and "lines" options', line=lineno)]
-
- encoding = options.get('encoding', env.config.source_encoding)
- try:
- f = codecs.open(fn, 'rU', encoding)
- lines = f.readlines()
- f.close()
- except (IOError, OSError):
- return [state.document.reporter.warning(
- 'Include file %r not found or reading it failed' % arguments[0],
- line=lineno)]
- except UnicodeError:
- return [state.document.reporter.warning(
- 'Encoding %r used for reading included file %r seems to '
- 'be wrong, try giving an :encoding: option' %
- (encoding, arguments[0]))]
-
- objectname = options.get('pyobject')
- if objectname is not None:
- from sphinx.pycode import ModuleAnalyzer
- analyzer = ModuleAnalyzer.for_file(fn, '')
- tags = analyzer.find_tags()
- if objectname not in tags:
- return [state.document.reporter.warning(
- 'Object named %r not found in include file %r' %
- (objectname, arguments[0]), line=lineno)]
+from sphinx.util.compat import Directive
+
+
+class Highlight(Directive):
+ """
+ Directive to set the highlighting language for code blocks, as well
+ as the threshold for line numbers.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {
+ 'linenothreshold': directives.unchanged,
+ }
+
+ def run(self):
+ if 'linenothreshold' in self.options:
+ try:
+ linenothreshold = int(self.options['linenothreshold'])
+ except Exception:
+ linenothreshold = 10
else:
- lines = lines[tags[objectname][1] - 1 : tags[objectname][2] - 1]
-
- linespec = options.get('lines')
- if linespec is not None:
+ linenothreshold = sys.maxint
+ return [addnodes.highlightlang(lang=self.arguments[0].strip(),
+ linenothreshold=linenothreshold)]
+
+
+class CodeBlock(Directive):
+ """
+ Directive for a code block with special highlighting or line numbering
+ settings.
+ """
+
+ has_content = True
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {
+ 'linenos': directives.flag,
+ }
+
+ def run(self):
+ code = u'\n'.join(self.content)
+ literal = nodes.literal_block(code, code)
+ literal['language'] = self.arguments[0]
+ literal['linenos'] = 'linenos' in self.options
+ return [literal]
+
+
+class LiteralInclude(Directive):
+ """
+ Like ``.. include:: :literal:``, but only warns if the include file is
+ not found, and does not raise errors. Also has several options for
+ selecting what to include.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {
+ 'linenos': directives.flag,
+ 'language': directives.unchanged_required,
+ 'encoding': directives.encoding,
+ 'pyobject': directives.unchanged_required,
+ 'lines': directives.unchanged_required,
+ 'start-after': directives.unchanged_required,
+ 'end-before': directives.unchanged_required,
+ }
+
+ def run(self):
+ document = self.state.document
+ filename = self.arguments[0]
+ if not document.settings.file_insertion_enabled:
+ return [document.reporter.warning('File insertion disabled',
+ line=self.lineno)]
+ env = document.settings.env
+ rel_fn = filename
+ sourcename = self.state_machine.input_lines.source(
+ self.lineno - self.state_machine.input_offset - 1)
+ source_dir = path.dirname(path.abspath(sourcename))
+ fn = path.normpath(path.join(source_dir, rel_fn))
+
+ if 'pyobject' in self.options and 'lines' in self.options:
+ return [document.reporter.warning(
+ 'Cannot use both "pyobject" and "lines" options',
+ line=self.lineno)]
+
+ encoding = self.options.get('encoding', env.config.source_encoding)
try:
- linelist = parselinenos(linespec, len(lines))
- except ValueError, err:
- return [state.document.reporter.warning(str(err), line=lineno)]
- lines = [lines[i] for i in linelist]
-
- startafter = options.get('start-after')
- endbefore = options.get('end-before')
- if startafter is not None or endbefore is not None:
- use = not startafter
- res = []
- for line in lines:
- if not use and startafter in line:
- use = True
- elif use and endbefore in line:
- use = False
- break
- elif use:
- res.append(line)
- lines = res
-
- text = ''.join(lines)
- retnode = nodes.literal_block(text, text, source=fn)
- retnode.line = 1
- if options.get('language', ''):
- retnode['language'] = options['language']
- if 'linenos' in options:
- retnode['linenos'] = True
- state.document.settings.env.note_dependency(rel_fn)
- return [retnode]
-
-literalinclude_directive.options = {
- 'linenos': directives.flag,
- 'language': directives.unchanged_required,
- 'encoding': directives.encoding,
- 'pyobject': directives.unchanged_required,
- 'lines': directives.unchanged_required,
- 'start-after': directives.unchanged_required,
- 'end-before': directives.unchanged_required,
-}
-literalinclude_directive.content = 0
-literalinclude_directive.arguments = (1, 0, 0)
-directives.register_directive('literalinclude', literalinclude_directive)
+ f = codecs.open(fn, 'rU', encoding)
+ lines = f.readlines()
+ f.close()
+ except (IOError, OSError):
+ return [document.reporter.warning(
+ 'Include file %r not found or reading it failed' % filename,
+ line=self.lineno)]
+ except UnicodeError:
+ return [document.reporter.warning(
+ 'Encoding %r used for reading included file %r seems to '
+ 'be wrong, try giving an :encoding: option' %
+ (encoding, filename))]
+
+ objectname = self.options.get('pyobject')
+ if objectname is not None:
+ from sphinx.pycode import ModuleAnalyzer
+ analyzer = ModuleAnalyzer.for_file(fn, '')
+ tags = analyzer.find_tags()
+ if objectname not in tags:
+ return [document.reporter.warning(
+ 'Object named %r not found in include file %r' %
+ (objectname, filename), line=self.lineno)]
+ else:
+ lines = lines[tags[objectname][1]-1 : tags[objectname][2]-1]
+
+ linespec = self.options.get('lines')
+ if linespec is not None:
+ try:
+ linelist = parselinenos(linespec, len(lines))
+ except ValueError, err:
+ return [document.reporter.warning(str(err), line=self.lineno)]
+ lines = [lines[i] for i in linelist]
+
+ startafter = self.options.get('start-after')
+ endbefore = self.options.get('end-before')
+ if startafter is not None or endbefore is not None:
+ use = not startafter
+ res = []
+ for line in lines:
+ if not use and startafter in line:
+ use = True
+ elif use and endbefore in line:
+ use = False
+ break
+ elif use:
+ res.append(line)
+ lines = res
+
+ text = ''.join(lines)
+ retnode = nodes.literal_block(text, text, source=fn)
+ retnode.line = 1
+ if self.options.get('language', ''):
+ retnode['language'] = self.options['language']
+ if 'linenos' in self.options:
+ retnode['linenos'] = True
+ document.settings.env.note_dependency(rel_fn)
+ return [retnode]
+
+
+directives.register_directive('highlight', Highlight)
+directives.register_directive('highlightlang', Highlight) # old name
+directives.register_directive('code-block', CodeBlock)
+directives.register_directive('sourcecode', CodeBlock)
+directives.register_directive('literalinclude', LiteralInclude)