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

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
 and 
tags. 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') { 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 StringBuilder fixDocComment(StringBuilder text) { // Nothing to do. int index = text.indexOf("{@"); if (index==-1) { return text; } StringBuilder sb = new StringBuilder(); int textOffs = 0; do { int closingBrace = indexOf('}', text, index+2); if (closingBrace>-1) { // Should practically always be true sb.append(text, 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 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 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 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 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 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 from {@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 String[] splitOnChar(String str, int ch) { List list = new ArrayList<>(3); int pos; 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 list.toArray(array); } }



© 2015 - 2024 Weber Informatics LLC | Privacy Policy