All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fife.rsta.ac.java.Util Maven / Gradle / Ivy

Go to download

A library adding code completion and other advanced features for Java, JavaScript, Perl, and other languages to RSyntaxTextArea.

There is a newer version: 3.3.0
Show newest version
/*
 * 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:
	 * 
	 * 
    *
  • ClassName
  • *
  • fully.qualified.ClassName
  • *
  • #method
  • *
  • #method(int, int)
  • *
  • String#method
  • *
  • String#method(params)
  • *
  • fully.qualified.ClassName#method
  • *
  • fully.qualified.ClassName#method(params)
  • *
*/ 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 (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 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("
"); 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 StringBuffer(); } 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. * * @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").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 between
 and 
tags. 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
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.' 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 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 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); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy