org.fife.rsta.ac.java.Util Maven / Gradle / Ivy
Show all versions of languagesupport Show documentation
/* * 03/21/2010 * * Copyright (C) 2010 Robert Futrell * robert_futrell at users.sourceforge.net * http://fifesoft.com/rsyntaxtextarea * * This library is distributed under a modified BSD license. See the included * RSTALanguageSupport.License.txt file for details. */ package org.fife.rsta.ac.java; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.fife.rsta.ac.java.buildpath.SourceLocation; import org.fife.rsta.ac.java.classreader.ClassFile; import org.fife.rsta.ac.java.rjc.ast.CompilationUnit; /** * Utility methods for Java completion. * * @author Robert Futrell * @version 1.0 */ public class Util { /** * Optional leading text for doc comment lines (except the first line) that * should be removed if it exists. */ static final Pattern DOC_COMMENT_LINE_HEADER = Pattern.compile("\\s*\\n\\s*\\*");//^\\s*\\*\\s*[/]?"); /** * Pattern matching a link in a "@link" tag. This should match the * following: * *
if it is not found * or an IO error occurs. */ public static CompilationUnit getCompilationUnitFromDisk( SourceLocation loc, ClassFile cf) { // Cached value? if (loc==lastCUFileParam && cf==lastCUClassFileParam) { //System.out.println("Returning cached CompilationUnit"); return lastCUFromDisk; } lastCUFileParam = loc; lastCUClassFileParam = cf; CompilationUnit cu = null; if(loc != null) { try { cu = loc.getCompilationUnit(cf); } catch (IOException ioe) { ioe.printStackTrace(); } } lastCUFromDisk = cu; return cu; } /** * Returns the "unqualified" version of a (possibly) fully-qualified * class name. * * @param clazz The class name. * @return The unqualified version of the name. */ public static final String getUnqualified(String clazz) { int dot = clazz.lastIndexOf('.'); if (dot>-1) { clazz = clazz.substring(dot+1); } return clazz; } /** * Returns the next location of a single character in a character sequence. * This method is here because StringBuilder doesn't get this * method added to it until Java 1.5. * * @param ch The character to look for. * @param sb The character sequence. * @param offs The offset at which to start looking. * @return The next location of the character, or -1 if it is not * found. */ private static final int indexOf(char ch, CharSequence sb, int offs) { while (offs*
*/ static final Pattern LINK_TAG_MEMBER_PATTERN = Pattern.compile("(?:\\w+\\.)*\\w+(?:#\\w+(?:\\([^\\)]*\\))?)?|" + "#\\w+(?:\\([^\\)]*\\))?"); /** * A cache of the last {@link CompilationUnit} read from some attached * source on disk. This is cached because, in some scenarios, the method * {@link #getCompilationUnitFromDisk(File, ClassFile)} will be called for * the same class many times in a row (such as to get method parameter * info for all methods in a single class). */ private static CompilationUnit lastCUFromDisk; private static SourceLocation lastCUFileParam; private static ClassFile lastCUClassFileParam; /** * Private constructor to prevent instantiation. */ private Util() { } private static final void appendDocCommentTail(StringBuffer sb, StringBuffer tail) { StringBuffer params = null; StringBuffer returns = null; StringBuffer throwsItems = null; StringBuffer see = null; StringBuffer seeTemp = null; StringBuffer since = null; StringBuffer author = null; StringBuffer version = null; StringBuffer unknowns = null; boolean inParams = false, inThrows = false, inReturns = false, inSeeAlso = false, inSince = false, inAuthor = false, inVersion = false, inUnknowns = false; String[] st = tail.toString().split("[ \t\r\n\f]+"); String token = null; int i = 0; while (i- ClassName
*- fully.qualified.ClassName
*- #method
*- #method(int, int)
*- String#method
*- String#method(params)
*- fully.qualified.ClassName#method
*- fully.qualified.ClassName#method(params)
*Parameters: "); } else { params.append("
"); } if (unknowns!=null) { sb.append(unknowns).append(""); } } /** * Appends HTML representing a "link" or "linkplain" Javadoc element to * a string buffer. * * @param appendTo The buffer to append to. * @param linkContent The content of a "link" or "linkplain" item. */ private static final void appendLinkTagText(StringBuffer appendTo, String linkContent) { appendTo.append("0) { // Not -1 String prefix = match.substring(0, pound); if ("java.lang.Object".equals(prefix)) { text = match.substring(pound+1); } } else { // Just use whole match (invalid link?) // TODO: Could be just a class name. Find on classpath text = match; } } else { // match.length() < linkContent.length() int offs = match.length(); // Will usually skip just a single space while (offs
"); } params.append("").append(token).append(" "); inSeeAlso=false; inParams = true; inReturns = false; inThrows = false; inSince = false; inAuthor = false; inVersion = false; inUnknowns = false; } else if ("@return".equals(token) && iReturns: "); } inSeeAlso=false; inReturns = true; inParams = false; inThrows = false; inSince = false; inAuthor = false; inVersion = false; inUnknowns = false; } else if ("@see".equals(token) && i
"); } if (since!=null) { sb.append(since).append("See Also: "); seeTemp = new StringBuffer(); } else { if (seeTemp.length()>0) { String temp = seeTemp.substring(0, seeTemp.length()-1); //syntax is exactly the same as link appendLinkTagText(see, temp); } see.append("
"); } if (version!=null) { sb.append(version).append("
"); seeTemp.setLength(0); //see.append("
"); } inSeeAlso = true; inReturns = false; inParams = false; inThrows = false; inSince = false; inAuthor = false; inVersion = false; inUnknowns = false; } else if (("@throws".equals(token)) || ("@exception".equals(token)) && iThrows: "); } else { throwsItems.append("
"); } if (author!=null) { sb.append(author).append("
"); } throwsItems.append("").append(token).append(" "); inSeeAlso = false; inParams = false; inReturns = false; inThrows = true; inSince = false; inAuthor = false; inVersion = false; inUnknowns = false; } else if ("@since".equals(token) && iSince: "); } inSeeAlso=false; inReturns = false; inParams = false; inThrows = false; inSince = true; inAuthor = false; inVersion = false; inUnknowns = false; } else if ("@author".equals(token) && i
"); } if (see!=null) { if (seeTemp.length()>0) { // Last @see contents String temp = seeTemp.substring(0, seeTemp.length()-1); //syntax is exactly the same as link appendLinkTagText(see, temp); } see.append("Author: "); } else { author.append("
"); } if (throwsItems!=null) { sb.append(throwsItems).append("
"); } inSeeAlso=false; inReturns = false; inParams = false; inThrows = false; inSince = false; inAuthor = true; inVersion = false; inUnknowns = false; } else if ("@version".equals(token) && iVersion: "); } else { version.append("
"); } unknowns.append("").append(token).append("
"); } inSeeAlso=false; inReturns = false; inParams = false; inThrows = false; inSince = false; inAuthor = false; inVersion = true; inUnknowns = false; } else if (token.startsWith("@") && token.length()>1) { if (unknowns==null) { unknowns = new StringBuffer(); } else { unknowns.append(""); // Stop everything; unknown/unsupported tag inSeeAlso = false; inParams = false; inReturns = false; inThrows = false; inSince = false; inAuthor = false; inVersion = false; inUnknowns = true; } else if (inParams) { params.append(token).append(' '); } else if (inReturns) { returns.append(token).append(' '); } else if (inSeeAlso) { //see.append(token).append(' '); seeTemp.append(token).append(' '); } else if (inThrows) { throwsItems.append(token).append(' '); } else if (inSince) { since.append(token).append(' '); } else if (inAuthor) { author.append(token).append(' '); } else if (inVersion) { version.append(token).append(' '); } else if (inUnknowns) { unknowns.append(token).append(' '); } } sb.append("
"); if (params!=null) { sb.append(params).append("
"); } if (returns!=null) { sb.append(returns).append("
"); sb.append(see).append("").append(text); } else { // Malformed link tag System.out.println("Unmatched linkContent: " + linkContent); appendTo.append("'>").append(linkContent); } appendTo.append(" "); } /** * Converts a Java documentation comment to HTML. ** This is a * pre block ** @param dc The documentation comment. * @return An HTML version of the comment. */ public static final String docCommentToHtml(String dc) { if (dc==null) { return null; } if (dc.endsWith("*/")) { dc = dc.substring(0, dc.length()-2); } // First, strip the line transitions. These always seem to be stripped // first from Javadoc, even when in betweenandtags. Matcher m = DOC_COMMENT_LINE_HEADER.matcher(dc); dc = m.replaceAll("\n"); StringBuffer html = new StringBuffer( ""); StringBuffer tailBuf = null; BufferedReader r = new BufferedReader(new StringReader(dc)); try { // Handle the first line (guaranteed to be at least 1 line). String line = r.readLine().substring(3); line = possiblyStripDocCommentTail(line); int offs = 0; while (offs') { result.append(">"); } else if (character == '\"') { result.append("""); } else if (character == '\'') { result.append("'"); } else if (character == '&') { result.append("&"); } else { //the char is not a special one //add it to the result as is result.append(character); } character = iterator.next(); } return result.toString(); } private static final StringBuffer fixDocComment(StringBuffer text) { // Nothing to do. int index = text.indexOf("{@"); if (index==-1) { return text; } // TODO: In Java 5, replace "sb.append(sb2.substring(...))" // calls with "sb.append(sb2, offs, len)". StringBuffer sb = new StringBuffer(); int textOffs = 0; do { int closingBrace = indexOf('}', text, index+2); if (closingBrace>-1) { // Should practically always be true sb.append(text.substring(textOffs, index)); String content = text.substring(index+2, closingBrace); index = textOffs = closingBrace + 1; if (content.startsWith("code ")) { sb.append(" "). append(forXML(content.substring(5))). append("
"); } else if (content.startsWith("link ")) { sb.append(""); appendLinkTagText(sb, content.substring(5)); sb.append("
"); } else if (content.startsWith("linkplain ")) { appendLinkTagText(sb, content.substring(10)); } else if (content.startsWith("literal ")) { // TODO: Should escape HTML-breaking chars, such as '>'. sb.append(content.substring(8)); } else { // Unhandled Javadoc tag sb.append("").append(content).append("
"); } } else { break; // Unclosed javadoc tag - just bail } } while ((index=text.indexOf("{@", index))>-1); if (textOffsnull .' character. * * @param str The string to check. * @return Whether the string is fully qualified. * @see #getUnqualified(String) */ public static final boolean isFullyQualified(String str) { return str.indexOf('.')>-1; } /** * Returns whether this line ends in the middle of a pre-block. * * @param line The line's contents. * @param prevValue Whether this line started in a pre-block. * @return Whether the line ends in a pre-block. */ private static final boolean isInPreBlock(String line, boolean prevValue) { int lastPre = line.lastIndexOf("pre>"); if (lastPre<=0) { return prevValue; } char prevChar = line.charAt(lastPre-1); if (prevChar=='<') { return true; } else if (prevChar=='/' && lastPre>=2) { if (line.charAt(lastPre-2)=='<') { return false; } } return prevValue; } /** * Removes the tail end of a documentation comment from a string, if it * exists. * * @param str The string. * @return The string, possibly with the documentation comment tail * removed. */ private static final String possiblyStripDocCommentTail(String str) { if (str.endsWith("*/")) { str = str.substring(0, str.length()-2); } return str; } /** * A faster way to split on a single char than String#split(), since * we'll be doing this in a tight loop possibly thousands of times (rt.jar). * This is also fundamentally different than {@link String#split(String)}), * in the case where str
ends withch
- this * method will return an empty item at the end of the returned array, while * String#split() will not. * * @param str The string to split. * @param ch The char to split on. * @return The string, split on the character (e.g. '/' or * '.'). */ public static final String[] splitOnChar(String str, int ch) { List list = new ArrayList(3); int pos = 0; int old = 0; while ((pos=str.indexOf(ch, old))>-1) { list.add(str.substring(old, pos)); old = pos+1; } // If str ends in ch, this adds an empty item to the end of the list. // This is what we want. list.add(str.substring(old)); String[] array = new String[list.size()]; return (String[])list.toArray(array); } }