org.fife.rsta.ac.java.Util Maven / Gradle / Ivy
/*
* 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
* LICENSE.md file for details.
*/
package org.fife.rsta.ac.java;
import java.io.BufferedReader;
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 final 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:
*
*
* - ClassName
* - fully.qualified.ClassName
* - #method
* - #method(int, int)
* - String#method
* - String#method(params)
* - fully.qualified.ClassName#method
* - fully.qualified.ClassName#method(params)
*
*
* Hyperlinks ("<a href=..."
) are not matched and should be
* handled separately.
*/
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(SourceLocation, 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 void appendDocCommentTail(StringBuilder sb,
StringBuilder tail) {
StringBuilder params = null;
StringBuilder returns = null;
StringBuilder throwsItems = null;
StringBuilder see = null;
StringBuilder seeTemp = null;
StringBuilder since = null;
StringBuilder author = null;
StringBuilder version = null;
StringBuilder unknowns = null;
boolean inParams = false;
boolean inThrows = false;
boolean inReturns = false;
boolean inSeeAlso = false;
boolean inSince = false;
boolean inAuthor = false;
boolean inVersion = false;
boolean inUnknowns = false;
String[] st = tail.toString().split("[ \t\r\n\f]+");
String token;
int i = 0;
while (iParameters:");
}
else {
params.append("
");
}
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) && iSee Also:");
seeTemp = new StringBuilder();
}
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("
");
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("
");
}
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) && iAuthor:");
}
else {
author.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("
");
}
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 StringBuilder();
}
else {
unknowns.append("
");
}
unknowns.append("").append(token).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("
");
}
if (throwsItems!=null) {
sb.append(throwsItems).append("
");
}
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("
");
sb.append(see).append("
");
}
if (author!=null) {
sb.append(author).append("
");
}
if (version!=null) {
sb.append(version).append("
");
}
if (since!=null) {
sb.append(since).append("
");
}
if (unknowns!=null) {
sb.append(unknowns).append("");
}
}
/**
* Appends HTML representing a "link" or "linkplain" Javadoc element to
* a string buffer.
* For some information on this format, see
*
* http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#see.
*
* @param appendTo The buffer to append to.
* @param linkContent The content of a "link", "linkplain" or "see" item.
*/
private static void appendLinkTagText(StringBuilder appendTo,
String linkContent) {
linkContent = linkContent.trim(); // If "@link" and text on different lines
Matcher m = LINK_TAG_MEMBER_PATTERN.matcher(linkContent);
if (m.find() && m.start() == 0) {
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").append(text);
appendTo.append(" ");
}
// @see
* This is a
* pre block
*
*
* @param dc The documentation comment.
* @return An HTML version of the comment.
*/
public static 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 between andtags. Matcher m = DOC_COMMENT_LINE_HEADER.matcher(dc); dc = m.replaceAll("\n"); StringBuilder html = new StringBuilder( ""); StringBuilder 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
").
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 (textOffsstr
ends with ch
- 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 String[] splitOnChar(String str, int ch) {
List