From: Yaroslav Halchenko Date: Fri, 22 Oct 2010 02:37:23 +0000 (-0400) Subject: dirty but working version of quoting X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=bd02d8170569b1d6b0deb22453ba6d4a1e3660fd;p=neurodebian.git dirty but working version of quoting tested with sphinx 0.6.6-3 and docutils 0.7-2 --- diff --git a/sphinx/ext/quote.py b/sphinx/ext/quote.py index 1b1ae8e..668b681 100644 --- a/sphinx/ext/quote.py +++ b/sphinx/ext/quote.py @@ -10,17 +10,29 @@ :license: BSD """ +import operator +from random import sample + from docutils import nodes from docutils.parsers.rst import directives, Directive from docutils.parsers.rst.directives import body -from sphinx.locale import _ from sphinx.environment import NoUri from sphinx.util.compat import Directive, make_admonition -class quote_node(nodes.Admonition, nodes.Element): pass -class quotelist(nodes.General, nodes.Element): pass +class quote_node(nodes.Body, nodes.Element): pass +class quotes(nodes.General, nodes.Element): pass + +def _info(msg): + # print "I: ", msg + pass + +def _prep_tags(options): + """Extract tags listed in a string""" + options['tags'] = set((x.strip() + for x in + options.get('tags', '').split(','))) class Quote(Directive): """ @@ -36,18 +48,26 @@ class Quote(Directive): 'affiliation': directives.unchanged, 'date': directives.unchanged, 'group': directives.unchanged, + 'tags': directives.unchanged, # list of tags per quote 'source': directives.unchanged} def run(self): state = self.state env = self.state.document.settings.env options = self.options - - targetid = 'index-%s' % env.new_serialno('index') + if hasattr(env, 'new_serialno'): + targetid = 'index-%s' % env.new_serialno('index') + else: + targetid = "index-%s" % env.index_num targetnode = nodes.target('', '', ids=[targetid]) targetnode['classes'] = ['epigraph'] - node = state.block_quote(self.content, self.content_offset) + node = quote_node() + node += nodes.block_quote( + '', + nodes.paragraph('', '\n'.join(self.content), classes=['text'])) + #state.nested_parse(self.content, self.content_offset, node) + for element in node: if isinstance(element, nodes.block_quote): element['classes'] += ['epigraph'] @@ -65,7 +85,11 @@ class Quote(Directive): siglb += [nodes.inline('', ' '+options[el], classes=[el])] signode[0].extend(siglb) node[0].extend(signode) - return [targetnode] + node; + node.line = self.lineno + # tune up options + _prep_tags(self.options) + node.options = options + return [targetnode] + [node] @@ -73,25 +97,27 @@ def process_quotes(app, doctree): # collect all quotes in the environment # this is not done in the directive itself because it some transformations # must have already been run, e.g. substitutions + _info("process_quotes") + env = app.builder.env if not hasattr(env, 'quote_all_quotes'): env.quote_all_quotes = [] - ## for node in doctree.traverse(quote_node): - ## try: - ## targetnode = node.parent[node.parent.index(node) - 1] - ## if not isinstance(targetnode, nodes.target): - ## raise IndexError - ## except IndexError: - ## targetnode = None - ## env.quote_all_quotes.append({ - ## 'docname': env.docname, - ## 'lineno': node.line, - ## 'quote': node.deepcopy(), - ## 'target': targetnode, - ## }) - - -class QuoteList(Directive): + for node in doctree.traverse(quote_node): + try: + targetnode = node.parent[node.parent.index(node) - 1] + if not isinstance(targetnode, nodes.target): + raise IndexError + except IndexError: + targetnode = None + env.quote_all_quotes.append({ + 'docname': env.docname, + 'lineno': node.line, + 'quote': node, #.deepcopy(), + 'target': targetnode, + }) + + +class Quotes(Directive): """ A list of all quote entries. """ @@ -101,13 +127,22 @@ class QuoteList(Directive): optional_arguments = 0 final_argument_whitespace = False option_spec = { - 'entries': lambda a: directives.choice(a, ('all', 'random')), - 'grouping': lambda a: directives.choice(a, ('month', 'group', None))} + 'random': directives.positive_int, # how many to randomly output + 'group': directives.unchanged, # what group to show + 'tags': directives.unchanged, # list of tags to be matched + #'sections': lambda a: directives.choice(a, ('date', 'group')) + } def run(self): - # Simply insert an empty quotelist node which will be replaced later + # Simply insert an empty quotes node which will be replaced later # when process_quote_nodes is called - return [quotelist('')] + res = quotes('') + # tags which must be matched + if 'tags' in self.options: + _prep_tags(self.options) + res.options = self.options + _info("Run Quotes %s" % res) + return [res] @@ -116,59 +151,111 @@ def process_quote_nodes(app, doctree, fromdocname): ## for node in doctree.traverse(quote_node): ## node.parent.remove(node) - # Replace all quotelist nodes with a list of the collected quotes. + # Replace all quotes nodes with a list of the collected quotes. # Augment each quote with a backlink to the original location. env = app.builder.env if not hasattr(env, 'quote_all_quotes'): env.quote_all_quotes = [] - for node in doctree.traverse(quotelist): + #_info("process_quote_nodes '%s' %i" + # % (fromdocname, len(env.quote_all_quotes))) + + for node in doctree.traverse(quotes): ## if not app.config['quote_include_quotes']: ## node.replace_self([]) ## continue content = [] + filters = [] + loptions = node.options + + # Filter by tags? + if 'tags' in loptions: + ltags = loptions['tags'] + filters.append( + lambda quote: set.issuperset( + quote.options['tags'], ltags)) + # Filter by group? + if 'group' in loptions: + loptions['group'] + filters.append( + lambda quote: + quote.options.get('group', '') == loptions['group']) for quote_info in env.quote_all_quotes: - para = nodes.paragraph(classes=['quote-source']) - filename = env.doc2path(quote_info['docname'], base=None) - description = _('(The <> is located in ' - ' %s, line %d.)') % (filename, quote_info['lineno']) - desc1 = description[:description.find('<<')] - desc2 = description[description.find('>>')+2:] - para += nodes.Text(desc1, desc1) - - # Create a reference - newnode = nodes.reference('', '', internal=True) - innernode = nodes.emphasis(_('original entry'), _('original entry')) - try: - newnode['refuri'] = app.builder.get_relative_uri( - fromdocname, quote_info['docname']) - newnode['refuri'] += '#' + quote_info['target']['refid'] - except NoUri: - # ignore if no URI can be determined, e.g. for LaTeX output - pass - newnode.append(innernode) - para += newnode - para += nodes.Text(desc2, desc2) - #para += nodes.Text("XXX", "YYY") + quote_entry = quote_info['quote'] + if not reduce(operator.__and__, + [f(quote_entry) for f in filters], + True): + continue + ## Commented out mechanism to back-reference original + ## location + ## + ## para = nodes.paragraph(classes=['quote-source']) + ## filename = env.doc2path(quote_info['docname'], base=None) + ## description = _('(The <> is located in ' + ## ' %s, line %d.)') % (filename, quote_info['lineno']) + ## desc1 = description[:description.find('<<')] + ## desc2 = description[description.find('>>')+2:] + ## para += nodes.Text(desc1, desc1) + + ## # Create a reference + ## newnode = nodes.reference('', '', internal=True) + ## innernode = nodes.emphasis(_('original entry'), _('original entry')) + ## try: + ## newnode['refuri'] = app.builder.get_relative_uri( + ## fromdocname, quote_info['docname']) + ## newnode['refuri'] += '#' + quote_info['target']['refid'] + ## except NoUri: + ## # ignore if no URI can be determined, e.g. for LaTeX output + ## pass + ## newnode.append(innernode) + ## para += newnode + ## para += nodes.Text(desc2, desc2) + ## #para += nodes.Text("XXX", "YYY") # (Recursively) resolve references in the quote content - quote_entry = quote_info['quote'] env.resolve_references(quote_entry, quote_info['docname'], app.builder) - # Insert into the quotelist + # Insert into the quotes content.append(quote_entry) - content.append(para) - + ## content.append(para) + + # Handle additional quotes options + + # Select a limited number of random samples + if loptions.get('random', None): + # Randomly select desired number of quotes + content = sample(content, loptions['random']) + + # Group items into sections and intersperse the list + # with section nodes + if loptions.get('sections', None): + raise NotImplementedError + term = loptions['sections'] + terms = [q.options.get(term, None) for q in content] + terms = list(set([x for x in terms if x])) + # Simply sort according to what to group on, + # and then insert sections? + #import pydb + #pydb.debugger() + section = nodes.section('') + section.extend(nodes.title('', 'XXX')) + section += content[:2] + section.parent = content[0].parent + content = [ section ] + + # Substitute with the content node.replace_self(content) + def purge_quotes(app, env, docname): if not hasattr(env, 'quote_all_quotes'): return + _info("purge_quotes") env.quote_all_quotes = [quote for quote in env.quote_all_quotes if quote['docname'] != docname] @@ -180,14 +267,14 @@ def setup(app): ## app.add_config_value('quotes_include_quotes', False, False) #import pydb #pydb.debugger() - app.add_node(quotelist) + app.add_node(quotes) app.add_node(quote_node, html=(quotes_noop, quotes_noop), latex=(quotes_noop, quotes_noop), text=(quotes_noop, quotes_noop)) app.add_directive('quote', Quote) - app.add_directive('quotelist', QuoteList) + app.add_directive('quotes', Quotes) app.connect('doctree-read', process_quotes) app.connect('doctree-resolved', process_quote_nodes) app.connect('env-purge-doc', purge_quotes)