[Epydoc-commits] SF.net SVN: epydoc: [1177] trunk/epydoc/src/epydoc/docwriter
Brought to you by:
edloper
From: <ed...@us...> - 2006-04-06 04:33:12
|
Revision: 1177 Author: edloper Date: 2006-04-05 21:33:06 -0700 (Wed, 05 Apr 2006) ViewCVS: http://svn.sourceforge.net/epydoc/?rev=1177&view=rev Log Message: ----------- - PythonSourceColorizer now generates links back into the documentation for all identifiers in the source whose short name is equal to at least one documented object. If multiple documented objects have the same short name, then pop up a little box which lets the user select which item they're interested in. Modified Paths: -------------- trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/docwriter/html_colorize.py trunk/epydoc/src/epydoc/docwriter/html_css.py Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2006-04-06 04:29:04 UTC (rev 1176) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2006-04-06 04:33:06 UTC (rev 1177) @@ -652,7 +652,8 @@ self.href(doc, label='%s %s' % (self.doc_kind(doc), name))) out('<div class="py-src">\n') out('<pre class="py-src">\n') - out(PythonSourceColorizer(filename, name).colorize()) + out(PythonSourceColorizer(filename, name, self.docindex, + self.indexed_docs, self.url).colorize()) out('</pre>\n</div>\n<br />\n') # Footer Modified: trunk/epydoc/src/epydoc/docwriter/html_colorize.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2006-04-06 04:29:04 UTC (rev 1176) +++ trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2006-04-06 04:33:06 UTC (rev 1177) @@ -20,6 +20,7 @@ from epydoc import log from epydoc.util import decode_with_backslashreplace, plaintext_to_html from epydoc.util import py_src_filename +from epydoc.apidoc import * ###################################################################### ## Regular expression colorizer @@ -433,8 +434,7 @@ var s = ""; if (linenumpadding != "") s = "<span class=\'lineno\'>" + linenumpadding + "</span>" - s = s + "<span class=\'pysrc-toggle\'> </span>" + - "<span class=\'py-line\'>" + indent + + s = s + " <span class=\'py-line\'>" + indent + "<a href=\'#\' onclick=\'expand(\\"" + id + "\\");return false\'>...</a></span><br />"; elt.innerHTML = s; @@ -498,6 +498,69 @@ } } +function kill_doclink() { + if (!this.contains(event.toElement)) { + var parent = document.getElementById(this.parentID); + parent.removeChild(parent.childNodes.item(0)); + } +} + +function doclink(id, name, targets) { + var elt = document.getElementById(id); + + // If we already opened the box, then destroy it. + // (This case should never occur, but leave it in just in case.) + if (elt.childNodes.length > 1) { + elt.removeChild(elt.childNodes.item(0)); + } + else { + // The outer box: relative + inline positioning. + var box1 = document.createElement("div"); + box1.style.position = "relative"; + box1.style.display = "inline"; + box1.style.top = 0; + box1.style.left = 0; + + // A shadow for fun + var shadow = document.createElement("div"); + shadow.style.position = "absolute"; + shadow.style.left = "-1.3em"; + shadow.style.top = "-1.3em"; + shadow.style.background = "#404040"; + + // The inner box: absolute positioning. + var box2 = document.createElement("div"); + box2.style.position = "relative"; + box2.style.border = "1px solid #a0a0a0"; + box2.style.left = "-.2em"; + box2.style.top = "-.2em"; + box2.style.background = "white"; + box2.style.padding = ".3em .4em .3em .4em"; + box2.style.fontStyle = "normal"; + box2.onmouseout=kill_doclink; + box2.parentID = id; + + var links = ""; + target_list = targets.split(","); + for (var i=0; i<target_list.length; i++) { + var target = target_list[i].split("="); + links += "<li><a href=\'" + target[1] + + "\' style=\'text-decoration:none\'>" + + target[0] + "</a></li>"; + } + + // Put it all together. + elt.insertBefore(box1, elt.childNodes.item(0)); + //box1.appendChild(box2); + box1.appendChild(shadow); + shadow.appendChild(box2); + box2.innerHTML = "Which <b>"+name+"</b> do you want to see "+ + "documentation for?" + + "<ul style=\'margin-bottom: 0;\'>" + + links + "</ul>"; + } +} + expandto(location.href); // --> </script> @@ -544,12 +607,7 @@ - Unicode input is supported (including automatic detection of C{'coding:'} declarations). - Still to do: - - cross-referencing within the code..? - - """ - #: A look-up table that is used to determine which CSS class #: should be used to colorize a given token. The following keys #: may be used: @@ -612,7 +670,10 @@ #: add line numbers. ADD_LINE_NUMBERS = True - def __init__(self, module_filename, module_name): + ADD_TOOLTIPS = False + + def __init__(self, module_filename, module_name, + docindex=None, api_docs=None, url_func=None): """ Create a new HTML colorizer for the specified module. @@ -632,6 +693,19 @@ #: The dotted name of the module we're colorizing. self.module_name = module_name + self.docindex = docindex + + #: A mapping from short names to lists of ValueDoc. + self.name_to_docs = {} + for api_doc in api_docs: + if (api_doc.canonical_name is not None and + url_func(api_doc) is not None): + name = api_doc.canonical_name[-1] + self.name_to_docs.setdefault(name,set()).add(api_doc) + + #: A function that maps APIDoc -> URL + self.url_func = url_func + #: The index in C{text} of the last character of the last #: token we've processed. self.pos = 0 @@ -668,6 +742,7 @@ #: on the previous logical line, or C{None} if the previous #: logical line was not a class or function definition. self.def_name = None + def find_line_offsets(self): """ @@ -741,9 +816,6 @@ html += PYSRC_JAVASCRIPTS return html - - # Add header/footer and return - #return PYSRC_TEMPLATE % (self.module_name, html) def tokeneater(self, toktype, toktext, (srow,scol), (erow,ecol), line): """ @@ -776,6 +848,8 @@ self.handle_line(self.cur_line) self.cur_line = [] + _next_uid = 0 + def handle_line(self, line): """ Render a single logical line from the module, and write the @@ -797,18 +871,21 @@ ended_def_blocks = 0 # The html output. - s = '<span class="pysrc-toggle"> </span>' if self.ADD_LINE_NUMBERS: - s = self.lineno_to_html() + s + s = self.lineno_to_html() self.lineno += 1 - s += '<span class="py-line">' + else: + s = '' + s += ' <span class="py-line">' # Loop through each token, and colorize it appropriately. for i, (toktype, toktext) in enumerate(line): # For each token, determine its css class and whether it - # should link to an href. + # should link to a url. css_class = None - href = None + url = None + tooltip = None + onclick = uid = None # these 3 are used together. # Is this token the class name in a class definition? If # so, then make it a link back into the API docs. @@ -818,7 +895,7 @@ def_name = toktext if None not in self.context: cls_name = '.'.join(self.context+[def_name]) - href = self.name2href(cls_name) + url = self.name2url(cls_name) s = self.mark_def(s, cls_name) # Is this token the function name in a function def? If @@ -830,7 +907,7 @@ if None not in self.context: cls_name = '.'.join(self.context) func_name = '.'.join(self.context+[def_name]) - href = self.name2href(cls_name, def_name) + url = self.name2url(cls_name, def_name) s = self.mark_def(s, func_name) # For each indent, update the indents list (which we use @@ -882,8 +959,32 @@ ((i>0 and line[i-1][1]=='@') or (i>1 and line[i-1][0]==None and line[i-2][1] == '@'))): css_class = self.CSS_CLASSES['DECORATOR'] - + # If it's a name, try to link it. + elif toktype == token.NAME: + css_class = self.CSS_CLASSES['NAME'] + # If we have a variable named `toktext` in the current + # context, then link to that. Note that if we're inside + # a function, then that function is our context, not + # the namespace that contains it. [xx] this isn't always + # the right thing to do. + if None not in self.context: + container = DottedName(self.module_name, *self.context) + doc = self.docindex.get_vardoc(container+toktext) + if doc is not None: + url = self.url_func(doc) + # Otherwise, check the name_to_docs index to see what + # else this name might refer to. + if url is None: + docs = sorted(self.name_to_docs.get(toktext, [])) + if docs: + if len(docs) == 1: + url = self.url_func(docs[0]) + tooltip='%s' % docs[0].canonical_name + else: + uid, onclick = self.doclink(toktext, docs) + tooltip='*.%s' % toktext + # For all other tokens, look up the CSS class to use # based on the token's type. else: @@ -905,20 +1006,32 @@ if toktext in (')',']','}'): in_param_default -= 1 if toktext == ',' and in_param_default == 1: in_param_default = 0 - # Write this token, with appropriate colorization. - if href: s += '<a href="%s" class="%s">' % (href, css_class) - elif css_class: s += '<span class="%s">' % css_class + if tooltip and self.ADD_TOOLTIPS: + tooltip_html = ' title="%s"' % tooltip + else: tooltip_html = '' + if css_class: css_class_html = ' class="%s"' % css_class + else: css_class_html = '' + if onclick: + s += ('<span id="%s"%s><a%s%s href="#" onclick="%s">' % + (uid, css_class_html, tooltip_html, + css_class_html, onclick)) + elif url: + s += ('<a%s%s href="%s">' % + (tooltip_html, css_class_html, url)) + elif css_class_html or tooltip_html: + s += '<span%s%s>' % (tooltip_html, css_class_html) if i == len(line)-1: s += ' </span>' # Closes <span class="py-line"> s += cgi.escape(toktext) else: s += self.add_line_numbers(cgi.escape(toktext), css_class) - - if href: s += '</a>' - elif css_class: s += '</span>' + if onclick: s += "</a></span>" + if url: s += '</a>' + elif css_class_html or tooltip_html: s += '</span>' + if self.ADD_DEF_BLOCKS: for i in range(ended_def_blocks): self.out(self.END_DEF_BLOCK) @@ -929,7 +1042,7 @@ if def_name and None not in self.context: self.out('</div>') - # Add divs if we're starting a def block. + # Add div's if we're starting a def block. if (self.ADD_DEF_BLOCKS and def_name and (line[-2][1] == ':') and None not in self.context): indentation = (''.join(self.indents)+' ').replace(' ', ' ') @@ -940,13 +1053,56 @@ self.def_name = def_name + def doclink(self, name, docs): + uid = 'link-%s' % self._next_uid + self._next_uid += 1 + if None not in self.context: + container = DottedName(self.module_name, *self.context) + else: + container = None + targets = ['%s=%s' % (self.doc_descr(d,container), self.url_func(d)) + for d in docs] + onclick = ("doclink('%s', '%s', '%s'); return false;" % + (uid, name, ','.join(targets))) + return uid, onclick + + def doc_descr(self, doc, context): + name = doc.canonical_name.contextualize(context) + descr = '%s %s' % (self.doc_kind(doc), name) + if isinstance(doc, RoutineDoc): + descr += '()' + return descr + + # [XX] copied streight from html.py; this should be consolidated, + # probably into apidoc. + def doc_kind(self, doc): + if isinstance(doc, ModuleDoc) and doc.is_package == True: + return 'Package' + elif (isinstance(doc, ModuleDoc) and + doc.canonical_name[0].startswith('script')): + return 'Script' + elif isinstance(doc, ModuleDoc): + return 'Module' + elif isinstance(doc, ClassDoc): + return 'Class' + elif isinstance(doc, ClassMethodDoc): + return 'Class Method' + elif isinstance(doc, StaticMethodDoc): + return 'Static Method' + elif isinstance(doc, RoutineDoc): + if isinstance(self.docindex.container(doc), ClassDoc): + return 'Method' + else: + return 'Function' + else: + return 'Variable' + def mark_def(self, s, name): replacement = ('<a name="%s"></a><div id="%s-def">\\1' '<a class="pysrc-toggle" href="#" id="%s-toggle" ' 'onclick="toggle(\'%s\'); return false;">-</a>\\2' % (name, name, name, name)) - return re.sub('(.*<span class="pysrc-toggle">) (</span>.*)\Z', - replacement, s) + return re.sub('(.*) (<span class="py-line">.*)\Z', replacement, s) def is_docstring(self, line, i): if line[i][0] != token.STRING: return False @@ -967,8 +1123,7 @@ result += '\n' if self.ADD_LINE_NUMBERS: result += self.lineno_to_html() - result += '<span class="pysrc-toggle"> </span>' - result += '<span class="py-line">' + result += ' <span class="py-line">' if css_class: result += '<span class="%s">' % css_class start = end end = s.find('\n', end)+1 @@ -976,7 +1131,7 @@ result += s[start:] return result - def name2href(self, class_name, func_name=None): + def name2url(self, class_name, func_name=None): if class_name: class_name = '%s.%s' % (self.module_name, class_name) if func_name: Modified: trunk/epydoc/src/epydoc/docwriter/html_css.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_css.py 2006-04-06 04:29:04 UTC (rev 1176) +++ trunk/epydoc/src/epydoc/docwriter/html_css.py 2006-04-06 04:33:06 UTC (rev 1177) @@ -119,8 +119,7 @@ .continue { border-top: 0; } /* Links */ -a.navbar:link { text-decoration: none; } -a.navbar:visited { text-decoration: none; } +a.navbar { text-decoration: none; } /* Source Code Listings */ pre.py-src { border: 2px solid black; } @@ -128,12 +127,11 @@ border-bottom: 1px solid black; } div.highlight { border-bottom: 2px solid black; } a.pysrc-toggle { text-decoration: none; } -span.pysrc-toggle { font-size: 80%; font-style: normal; - padding-left: .4em; } .py-line { border-left: 2px solid black; margin-left: .2em; padding-left: .4em; } .lineno { font-style: italic; font-size: 90%; padding-left: .5em; } +a.py-name { text-decoration: none; } /* For Graphs */ .graph-without-title { border: none; } @@ -157,7 +155,6 @@ h2 span.codelink { font-size: 58%; font-weight: normal; } span.codelink { font-size: 85%; font-weight; normal; } """ -#(* (/ 1. 1.2) .7) # Black on white, with blue highlights. This is similar to how # javadoc looks. @@ -202,6 +199,8 @@ .py-keyword { background: transparent; color: #600000; } .py-output { background: transparent; color: #404040; } .py-name { background: transparent; color: #000050; } +.py-name:link { background: transparent; color: #000050; } +.py-name:visited { background: transparent; color: #000050; } .py-number { background: transparent; color: #005000; } .py-def-name { background: transparent; color: #000060; font-weight: bold; } @@ -297,6 +296,8 @@ .py-keyword { background: transparent; color: #600000; } .py-output { background: transparent; color: #404040; } .py-name { background: transparent; color: #000050; } +.py-name:link { background: transparent; color: #000050; } +.py-name:visited { background: transparent; color: #000050; } .py-number { background: transparent; color: #005000; } .py-def-name { background: transparent; color: #000060; font-weight: bold; } @@ -391,6 +392,8 @@ .py-keyword { background: transparent; color: #800000; } .py-output { background: transparent; color: #484848; } .py-name { background: transparent; color: #000050; } +.py-name:link { background: transparent; color: #000050; } +.py-name:visited { background: transparent; color: #000050; } .py-number { background: transparent; color: #005000; } .py-def-name { background: transparent; color: #000060; font-weight: bold; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |