diff --git a/sphinx/builder.py b/sphinx/builder.py index fca3cfaee..c85f70abb 100644 --- a/sphinx/builder.py +++ b/sphinx/builder.py @@ -407,7 +407,8 @@ class StandaloneHTMLBuilder(Builder): pl = pl.split(', ') if pl else [] platforms.update(pl) if fl != mn[0].lower() and mn[0] != '_': - modindexentries.append(['', False, 0, False, mn[0].upper(), '', [], False]) + modindexentries.append(['', False, 0, False, + mn[0].upper(), '', [], False]) tn = mn.partition('.')[0] if tn != mn: # submodule diff --git a/sphinx/directives.py b/sphinx/directives.py index 8df7e9b6b..f4dcb8e1a 100644 --- a/sphinx/directives.py +++ b/sphinx/directives.py @@ -246,7 +246,7 @@ def parse_c_signature(signode, sig, desctype): opcode_sig_re = re.compile(r'(\w+(?:\+\d)?)\s*\((.*)\)') -def parse_opcode_signature(signode, sig, desctype): +def parse_opcode_signature(signode, sig): """Transform an opcode signature into RST nodes.""" m = opcode_sig_re.match(sig) if m is None: raise ValueError @@ -258,6 +258,18 @@ def parse_opcode_signature(signode, sig, desctype): return opname.strip() +option_desc_re = re.compile(r'([-/])([-_a-zA-Z0-9]+)(\s*.*)') + +def parse_option_desc(signode, sig): + """Transform an option description into RST nodes.""" + m = option_desc_re.match(sig) + if m is None: raise ValueError + prefix, optname, args = m.groups() + signode += addnodes.desc_name(prefix+optname, prefix+optname) + signode += addnodes.desc_classname(args, args) + return optname + + def add_refcount_annotation(env, node, name): """Add a reference count annotation. Return None.""" entry = env.refcounts.get(name) @@ -298,18 +310,27 @@ def desc_directive(desctype, arguments, options, content, lineno, elif desctype in ('cfunction', 'cmember', 'cmacro', 'ctype', 'cvar'): name = parse_c_signature(signode, sig, desctype) elif desctype == 'opcode': - name = parse_opcode_signature(signode, sig, desctype) + name = parse_opcode_signature(signode, sig) elif desctype == 'cmdoption': - # TODO: add custom parsing for parts? - signode.clear() - signode += addnodes.desc_name(sig, sig) + optname = parse_option_desc(signode, sig) if not noindex: - targetname = 'cmdoption-%s' % env.index_num - env.index_num += 1 + targetname = 'cmdoption-' + optname signode['ids'].append(targetname) state.document.note_explicit_target(signode) env.note_index_entry('pair', 'command line option; %s' % sig, targetname, targetname) + env.note_reftarget('option', optname, targetname) + continue + elif desctype == 'envvar': + signode.clear() + signode += addnodes.desc_name(sig, sig) + if not noindex: + targetname = 'envvar-' + sig + signode['ids'].append(targetname) + state.document.note_explicit_target(signode) + env.note_index_entry('pair', 'environment variable; %s' % sig, + targetname, targetname) + env.note_reftarget('envvar', sig, targetname) continue else: # for "describe": use generic fallback @@ -378,6 +399,7 @@ desctypes = [ 'opcode', # the generic ones 'cmdoption', # for command line options + 'envvar', # for environment variables 'describe', ] @@ -472,7 +494,7 @@ def productionlist_directive(name, arguments, options, content, lineno, if idname not in state.document.ids: subnode['ids'].append(idname) state.document.note_implicit_target(subnode, subnode) - env.note_token(subnode['tokenname']) + env.note_reftarget('token', subnode['tokenname'], idname) subnode.extend(token_xrefs(tokens, env)) node.append(subnode) return [node] + messages @@ -621,7 +643,7 @@ def glossary_directive(name, arguments, options, content, lineno, env.gloss_entries.add(new_id) li[0]['names'].append(new_id) li[0]['ids'].append(new_id) - state.document.settings.env.note_glossaryterm(termtext, new_id) + state.document.settings.env.note_reftarget('term', termtext, new_id) return [node] glossary_directive.content = 1 diff --git a/sphinx/environment.py b/sphinx/environment.py index b6d2b2a66..6568a5168 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -52,7 +52,7 @@ default_settings = { # This is increased every time a new environment attribute is added # to properly invalidate pickle files. -ENV_VERSION = 11 +ENV_VERSION = 12 def walk_depth(node, depth, maxdepth): @@ -204,9 +204,9 @@ class BuildEnvironment: self.descrefs = {} # fullname -> filename, desctype self.filemodules = {} # filename -> [modules] self.modules = {} # modname -> filename, synopsis, platform, deprecated - self.tokens = {} # tokenname -> filename - self.labels = {} # labelname -> filename, labelid - self.glossary = {} # term -> filename, labelid + self.labels = {} # labelname -> filename, labelid, sectionname + self.reftargets = {} # (type, name) -> filename, labelid + # where type is term, token, option, envvar # Other inventories self.indexentries = {} # filename -> list of @@ -244,15 +244,12 @@ class BuildEnvironment: for modname, (fn, _, _, _) in self.modules.items(): if fn == filename: del self.modules[modname] - for tokenname, fn in self.tokens.items(): - if fn == filename: - del self.tokens[tokenname] for labelname, (fn, _, _) in self.labels.items(): if fn == filename: del self.labels[labelname] - for term, (fn, _) in self.glossary.items(): + for key, (fn, _) in self.reftargets.items(): if fn == filename: - del self.glossary[term] + del self.reftargets[key] self.indexentries.pop(filename, None) for version, changes in self.versionchanges.items(): new = [change for change in changes if change[1] != filename] @@ -302,7 +299,8 @@ class BuildEnvironment: Yields a summary and then filenames as it processes them. """ added, changed, removed = self.get_outdated_files(config) - msg = '%s added, %s changed, %s removed' % (len(added), len(changed), len(removed)) + msg = '%s added, %s changed, %s removed' % (len(added), len(changed), + len(removed)) if self.config != config: msg = '[config changed] ' + msg yield msg @@ -502,8 +500,8 @@ class BuildEnvironment: self.modules[modname] = (self.filename, synopsis, platform, deprecated) self.filemodules.setdefault(self.filename, []).append(modname) - def note_token(self, tokenname): - self.tokens[tokenname] = self.filename + def note_reftarget(self, type, name, labelid): + self.reftargets[type, name] = (self.filename, labelid) def note_index_entry(self, type, string, targetid, aliasname): self.indexentries.setdefault(self.filename, []).append( @@ -512,9 +510,6 @@ class BuildEnvironment: def note_versionchange(self, type, version, node): self.versionchanges.setdefault(version, []).append( (type, self.filename, self.currmodule, self.currdesc, node.deepcopy())) - - def note_glossaryterm(self, text, labelname): - self.glossary[text] = (self.filename, labelname) # ------- # --------- RESOLVING REFERENCES AND TOCTREES ------------------------------ @@ -584,8 +579,6 @@ class BuildEnvironment: typ = node['reftype'] target = node['reftarget'] - modname = node['modname'] - clsname = node['classname'] if typ == 'ref': filename, labelid, sectname = self.labels.get(target, ('','','')) @@ -602,11 +595,12 @@ class BuildEnvironment: newnode['refuri'] = builder.get_relative_uri( docfilename, filename) + '#' + labelid newnode.append(nodes.emphasis(sectname, sectname)) - elif typ == 'term': - filename, labelid = self.glossary.get(target, ('', '')) + elif typ in ('token', 'term', 'envvar', 'option'): + filename, labelid = self.reftargets.get((typ, target), ('', '')) if not filename: - print >>self.warning_stream, \ - '%s: term not in glossary: %s' % (docfilename, target) + if typ == 'term': + print >>self.warning_stream, \ + '%s: term not in glossary: %s' % (docfilename, target) newnode = contnode else: newnode = nodes.reference('', '') @@ -616,18 +610,6 @@ class BuildEnvironment: newnode['refuri'] = builder.get_relative_uri( docfilename, filename) + '#' + labelid newnode.append(contnode) - elif typ == 'token': - filename = self.tokens.get(target, '') - if not filename: - newnode = contnode - else: - newnode = nodes.reference('', '') - if filename == docfilename: - newnode['refid'] = 'grammar-token-' + target - else: - newnode['refuri'] = builder.get_relative_uri( - docfilename, filename) + '#grammar-token-' + target - newnode.append(contnode) elif typ == 'mod': filename, synopsis, platform, deprecated = \ self.modules.get(target, ('','','', '')) @@ -649,6 +631,8 @@ class BuildEnvironment: synopsis, (' (deprecated)' if deprecated else '')) newnode.append(contnode) else: + modname = node['modname'] + clsname = node['classname'] searchorder = 1 if node.hasattr('refspecific') else 0 name, desc = self.find_desc(modname, clsname, target, typ, searchorder) if not desc: diff --git a/sphinx/roles.py b/sphinx/roles.py index 10737aead..874885167 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -29,7 +29,6 @@ generic_docroles = { 'manpage' : addnodes.literal_emphasis, 'mimetype' : addnodes.literal_emphasis, 'newsgroup' : addnodes.literal_emphasis, - 'option' : addnodes.literal_emphasis, 'program' : nodes.strong, 'regexp' : nodes.literal, } @@ -48,10 +47,14 @@ def indexmarkup_role(typ, rawtext, text, lineno, inliner, options={}, content=[] if typ == 'envvar': env.note_index_entry('single', '%s' % text, targetid, text) - env.note_index_entry('single', 'environment variables!%s' % text, + env.note_index_entry('single', 'environment variable; %s' % text, targetid, text) - textnode = nodes.strong(text, text) - return [targetnode, textnode], [] + #textnode = nodes.strong(text, text) + pnode = addnodes.pending_xref(rawtext) + pnode['reftype'] = 'envvar' + pnode['reftarget'] = text + pnode += nodes.strong(text, text, classes=['xref']) + return [targetnode, pnode], [] elif typ == 'pep': env.note_index_entry('single', 'Python Enhancement Proposals!PEP %s' % text, targetid, 'PEP %s' % text) @@ -91,6 +94,7 @@ innernodetypes = { 'ref': nodes.emphasis, 'term': nodes.emphasis, 'token': nodes.strong, + 'option': addnodes.literal_emphasis, } def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): @@ -112,7 +116,12 @@ def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): typ in ('data', 'exc', 'func', 'class', 'const', 'attr', 'meth'): text = text[1:] pnode['refspecific'] = True - pnode['reftarget'] = ws_re.sub((' ' if typ == 'term' else ''), text) + if typ == 'term': + pnode['reftarget'] = ws_re.sub(' ', text) + elif typ == 'option': + pnode['reftarget'] = text[1:] if text[0] in '-/' else text + else: + pnode['reftarget'] = ws_re.sub('', text) pnode['modname'] = env.currmodule pnode['classname'] = env.currclass pnode += innernodetypes.get(typ, nodes.literal)(rawtext, text, classes=['xref']) @@ -160,6 +169,7 @@ specific_docroles = { 'ref': xfileref_role, 'token' : xfileref_role, 'term': xfileref_role, + 'option': xfileref_role, 'menuselection' : menusel_role, 'file' : emph_literal_role, diff --git a/sphinx/writer.py b/sphinx/writer.py index 1084dc782..caff0f817 100644 --- a/sphinx/writer.py +++ b/sphinx/writer.py @@ -258,6 +258,14 @@ def translator_class(config, buildername): self.depart_emphasis(node) self.no_smarty -= 1 + def visit_desc_signature(self, node): + self.no_smarty += 1 + HTMLTranslator.visit_desc_signature(self, node) + + def depart_desc_signature(self, node): + self.no_smarty -= 1 + HTMLTranslator.depart_desc_signature(self, node) + def visit_productionlist(self, node): self.no_smarty += 1 try: