src.org.python.indexer.demos.Linker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython Show documentation
Show all versions of jython Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
/**
* Copyright 2009, Google Inc. All rights reserved.
* Licensed to PSF under a Contributor Agreement.
*/
package org.python.indexer.demos;
import org.python.indexer.Def;
import org.python.indexer.Ref;
import org.python.indexer.Indexer;
import org.python.indexer.NBinding;
import org.python.indexer.StyleRun;
import org.python.indexer.Util;
import org.python.indexer.types.NModuleType;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Collects per-file hyperlinks, as well as styles that require the
* symbol table to resolve properly.
*/
class Linker {
private static final Pattern CONSTANT = Pattern.compile("[A-Z_][A-Z0-9_]*");
// Map of file-path to semantic styles & links for that path.
private Map> fileStyles = new HashMap>();
private File outDir; // where we're generating the output html
private String rootPath;
/**
* Constructor.
* @param root the root of the directory tree being indexed
* @param outdir the html output directory
*/
public Linker(String root, File outdir) {
rootPath = root;
outDir = outdir;
}
/**
* Process all bindings across all files and record per-file semantic styles.
* Should be called once per index.
*/
public void findLinks(Indexer indexer) {
for (NBinding nb : indexer.getBindings().values()) {
addSemanticStyles(nb);
processDefs(nb);
processRefs(nb);
}
}
/**
* Returns the styles (links and extra styles) generated for a given file.
* @param path an absolute source path
* @return a possibly-empty list of styles for that path
*/
public List getStyles(String path) {
return stylesForFile(path);
}
private List stylesForFile(String path) {
List styles = fileStyles.get(path);
if (styles == null) {
styles = new ArrayList();
fileStyles.put(path, styles);
}
return styles;
}
private void addFileStyle(String path, StyleRun style) {
stylesForFile(path).add(style);
}
/**
* Add additional highlighting styles based on information not evident from
* the AST.
* @param def the binding's main definition node
* @param b the binding
*/
private void addSemanticStyles(NBinding nb) {
Def def = nb.getSignatureNode();
if (def == null || !def.isName()) {
return;
}
boolean isConst = CONSTANT.matcher(def.getName()).matches();
switch (nb.getKind()) {
case SCOPE:
if (isConst) {
addSemanticStyle(def, StyleRun.Type.CONSTANT);
}
break;
case VARIABLE:
addSemanticStyle(def, isConst ? StyleRun.Type.CONSTANT : StyleRun.Type.IDENTIFIER);
break;
case PARAMETER:
addSemanticStyle(def, StyleRun.Type.PARAMETER);
break;
case CLASS:
addSemanticStyle(def, StyleRun.Type.TYPE_NAME);
break;
}
}
private void addSemanticStyle(Def def, StyleRun.Type type) {
String path = def.getFile();
if (path != null) {
addFileStyle(path, new StyleRun(type, def.start(), def.length()));
}
}
/**
* Create name anchors for definition sites.
*/
private void processDefs(NBinding nb) {
Def def = nb.getSignatureNode();
if (def == null || def.isURL()) {
return;
}
StyleRun style = new StyleRun(StyleRun.Type.ANCHOR, def.start(), def.length());
style.message = nb.getQname();
style.url = nb.getQname();
addFileStyle(def.getFile(), style);
}
/**
* Collect cross-reference links for every file.
*/
private void processRefs(NBinding nb) {
if (nb.hasRefs()) { // avoid lazy ref-list instantiation
for (Ref ref : nb.getRefs()) {
processRef(ref, nb);
}
}
}
/**
* Adds a hyperlink for a single reference.
*/
void processRef(Ref ref, NBinding nb) {
String path = ref.getFile();
StyleRun link = new StyleRun(StyleRun.Type.LINK, ref.start(), ref.length());
link.message = nb.getQname();
link.url = toURL(nb, path);
if (link.url != null) {
addFileStyle(path, link);
}
}
/**
* Generate a URL for a reference to a binding.
* @param nb the referenced binding
* @param path the path containing the reference, or null if there was an error
*/
private String toURL(NBinding nb, String path) {
Def def = nb.getSignatureNode();
if (def == null) {
return null;
}
if (nb.isBuiltin()) {
return def.getURL();
}
if (def.isModule()) {
return toModuleUrl(nb);
}
String anchor = "#" + nb.getQname();
if (nb.getFirstFile().equals(path)) {
return anchor;
}
String destPath = def.getFile();
try {
String relpath = destPath.substring(rootPath.length());
return Util.joinPath(outDir.getAbsolutePath(), relpath) + ".html" + anchor;
} catch (Exception x) {
System.err.println("path problem: dest=" + destPath + ", root=" + rootPath + ": " + x);
return null;
}
}
/**
* Generate an anchorless URL linking to another file in the index.
*/
private String toModuleUrl(NBinding nb) {
NModuleType mtype = nb.getType().follow().asModuleType();
String path = mtype.getFile();
if (!path.startsWith(rootPath)) {
return "file://" + path; // can't find file => punt & load it directly
}
String relpath = path.substring(rootPath.length());
return Util.joinPath(outDir.getAbsolutePath(), relpath) + ".html";
}
}