/*******************************************************************************
* Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* The Chisel Group, University of Victoria
* IBM Corporation
*******************************************************************************/
package net.sourceforge.tagsea.java.documents.internal;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.rules.EndOfLineRule;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.RuleBasedScanner;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WordRule;
/**
*
* @author Del Meyrs
*
*/
public class NewWaypointDefinitionExtractor
{
protected static final char TAG_START_CHAR = '@';
protected static final String TAG_STRING = "@tag"; //$NON-NLS-1$
protected static final String COMMENT_STRING = "//"; //$NON-NLS-1$
protected static final String MULTI_COMMENT_STRING = "/*"; //$NON-NLS-1$
protected static final String END_COMMENT_STRING = "*/"; //$NON-NLS-1$
/*
* Token Keys
*/
protected static final Object TAG_KEY = new Object();
protected static final Object END_COMMENT_KEY = new Object();
protected static final Object SINGLE_COMMENT_KEY = new Object();
protected static final Object MULTI_COMMENT_KEY = new Object();
private static RuleBasedScanner fWaypointScanner;
static
{
fWaypointScanner = new RuleBasedScanner();
EndOfLineRule tagRule = new EndOfLineRule(TAG_STRING, new Token(TAG_KEY));
WordRule eocRule = new WordRule(new EndOfCommentDetector());
eocRule.addWord(END_COMMENT_STRING, (IToken)new Token(END_COMMENT_KEY));
fWaypointScanner.setRules(new IRule[]{tagRule});
}
/**
* Gets the tag regions associated with this entire document, if no tag regions
* are found an empty array is returned
* @param source reference
* @return Array of tag regions
*/
public static IRegion[] getWaypointRegions(IDocument document)
{
return getWaypointRegions(document, 0, document.getLength());
}
/**
* Gets the tag regions associated with this document, restricted to the given source referece, if no tag regions
* are found an empty array is returned
* @param document
* @param source reference
* @return Array of tag regions
*/
public static IRegion[] getWaypointRegions(IDocument document, ISourceReference reference)
{
ISourceRange range;
try
{
range = reference.getSourceRange();
}
catch (JavaModelException e)
{
e.printStackTrace();
return new IRegion[0];
}
if(range.getOffset() < 0 || range.getOffset() + range.getLength() > document.getLength())
return new IRegion[0];
return getWaypointRegions(document, range.getOffset(), range.getLength());
}
/**
* Gets the tag regions associated with this document from the given offset and length.
* If no tag regions are found an empty array is returned.
* @param source reference
* @return Array of tag regions
*/
public static IRegion[] getWaypointRegions(IDocument document, int offset, int length)
{
IRegion[] commentRegions = getCommentRegions(document, offset, length);
List<IRegion> tagRegions = new ArrayList<IRegion>();
// for each comment block get all the tags
for (IRegion commentRegion : commentRegions)
{
IRegion[] regions = null;
regions = internalGetWaypointRegions(document, commentRegion.getOffset(), commentRegion.getLength());
for (IRegion tagRegion : regions)
{
//remove the newline.
String delim = document.getLegalLineDelimiters()[0];
try {
int line = document.getLineOfOffset(tagRegion.getOffset());
delim = document.getLineDelimiter(line);
} catch (BadLocationException e) {
}
tagRegions.add(new Region(tagRegion.getOffset(), tagRegion.getLength()-delim.length()));
}
}
IRegion[] result= new IRegion[tagRegions.size()];
tagRegions.toArray(result);
return result;
}
/**
* Gets the comment regions associated with this document, restricted to the given offset and length, if no comment regions
* are found an empty array is returned
* @param document
* @param offset
* @param length
* @param returnSingleLine Wither to collect single line commments
* @return Array of tag regions
*/
public static IRegion[] getCommentRegions(IDocument document, int offset, int length)
{
try
{
StringBuffer content = new StringBuffer(document.get(offset,length));
IRegion range = new Region(offset,length);
List<IRegion> commentRegions = new ArrayList<IRegion>();
IScanner scanner= ToolFactory.createScanner(true, false, false, false);
scanner.setSource(content.toString().toCharArray());
int shift = range.getOffset();
while (true)
{
int terminal= scanner.getNextToken();
if (terminal == ITerminalSymbols.TokenNameCOMMENT_JAVADOC || terminal == ITerminalSymbols.TokenNameCOMMENT_BLOCK)
{
int commentOffset = shift + scanner.getCurrentTokenStartPosition();
int commentEnd = shift + scanner.getCurrentTokenEndPosition() + 1;
commentRegions.add(new Region(commentOffset,commentEnd - commentOffset));
}
else if(terminal == ITerminalSymbols.TokenNameCOMMENT_LINE)
{
int commentOffset = shift + scanner.getCurrentTokenStartPosition();
int commentEnd = shift + scanner.getCurrentTokenEndPosition() + 1;
commentRegions.add(new Region(commentOffset,commentEnd - commentOffset));
}
else if(terminal == ITerminalSymbols.TokenNameEOF)
break;
}
IRegion[] result= new IRegion[commentRegions.size()];
commentRegions.toArray(result);
return result;
}
catch (BadLocationException e)
{
//e.printStackTrace();
}
catch (InvalidInputException e)
{
//e.printStackTrace();
}
return new IRegion[0];
}
/**
* Gets the tag regions associated with this document, restricted to the given offset and length, if no tag regions
* are found an empty array is returned, if a tag region overlaps the end of the region it will be ignored
* @param document
* @param offset
* @param length
* @return Array of tag regions
*/
// private static IRegion[] internalGetWaypointRegions(IDocument document, int offset, int length)
// {
// List<IRegion> tagRegions = new ArrayList<IRegion>();
// fWaypointScanner.setRange(document,offset,length);
//
// boolean tagDetected = false;
// boolean eolDetected = false;
// boolean metaOpenDetected = false;
//
// int tagOffset = 0;
// int eolOffset = 0;
//
// while (true)
// {
// IToken token = fWaypointScanner.nextToken();
//
// if(token.getData() == TAG_KEY)
// {
// /* We have already detected a tag start and eol so we have a single line tag */
// if(tagDetected && eolDetected)
// {
// tagRegions.add(new Region(tagOffset, eolOffset - tagOffset));
// /* reset eol detection */
// eolDetected = false;
// }
//
// tagDetected = true;
// tagOffset = fWaypointScanner.getTokenOffset();
// }
// else if(token.getData() == EOL_KEY)
// {
// /* we only store the first eol after the tag start */
// if(tagDetected && !eolDetected)
// {
// eolDetected = true;
// eolOffset = fWaypointScanner.getTokenOffset();
// }
// }
// else if(token.getData() == TAG_META_OPEN_KEY)
// {
// metaOpenDetected = true;
// }
// else if(token.getData() == TAG_META_CLOSE_KEY)
// {
// /*
// * We reached a meta end and we have already found a tag and meta open
// * so we have a multi line tag
// */
// if(tagDetected && metaOpenDetected)
// {
// tagRegions.add(new Region(tagOffset, (fWaypointScanner.getTokenOffset() + 1) - tagOffset));
// }
//
// tagDetected = false;
// eolDetected = false;
// metaOpenDetected = false;
// }
// else if(token.getData() == END_COMMENT_KEY)
// {
// /* We have already detected a tag start and eol so we have a tag in there somewhere */
// if(tagDetected && eolDetected)
// tagRegions.add(new Region(tagOffset, (eolOffset) - tagOffset));
// /* We have already detected a tag start but no eol so we have a single line tag */
// else if(tagDetected)
// tagRegions.add(new Region(tagOffset, (fWaypointScanner.getTokenOffset()) - tagOffset));
//
// break;
// }
// else if(token.equals(Token.EOF))
// {
// /* We have already detected a tag start and eol so we have a single line tag */
// if(tagDetected && eolDetected)
// tagRegions.add(new Region(tagOffset, (eolOffset) - tagOffset));
// else
// /* Real edge case here, a rogue tag, assume its a single line without line delimeter*/
// if(tagDetected)
// tagRegions.add(new Region(tagOffset, (fWaypointScanner.getTokenOffset()) - tagOffset));
//
// break;
// }
// }
//
// IRegion[] result= new IRegion[tagRegions.size()];
// tagRegions.toArray(result);
// return result;
// }
// Wwe only support single line tags, the method above will pull multi line tags
public static IRegion[] internalGetWaypointRegions(IDocument document, int offset, int length)
{
List<IRegion> tagRegions = new ArrayList<IRegion>();
fWaypointScanner.setRange(document,offset,length);
while (true)
{
IToken token = fWaypointScanner.nextToken();
if (token.getData() == TAG_KEY) {
Region r = new Region(fWaypointScanner.getTokenOffset(), fWaypointScanner.getTokenLength());
tagRegions.add(r);
} else if (token.equals(Token.EOF)) {
break;
}
}
IRegion[] result= new IRegion[tagRegions.size()];
tagRegions.toArray(result);
return result;
}
}