/* * 08/11/2009 * * TaskTagParser.java - Parser that scans code comments for task tags. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.rsyntaxtextarea.parser; import java.awt.Color; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import javax.swing.text.Element; import org.fife.ui.rsyntaxtextarea.ErrorStrip; import org.fife.ui.rsyntaxtextarea.RSyntaxDocument; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.Token; /** * Parser that identifies "task tags," such as "<code>TODO</code>", * "<code>FIXME</code>", etc. in source code comments. * * @author Robert Futrell * @version 1.0 */ public class TaskTagParser extends AbstractParser { private DefaultParseResult result; private String DEFAULT_TASK_PATTERN = "TODO|FIXME|HACK"; private Pattern taskPattern; private static final Color COLOR = new Color(48, 150, 252); /** * Creates a new task parser. The default parser treats the following * identifiers in comments as task definitions: "<code>TODO</code>", * "<code>FIXME</code>", and "<code>HACK</code>". */ public TaskTagParser() { result = new DefaultParseResult(this); setTaskPattern(DEFAULT_TASK_PATTERN); } /** * Returns the regular expression used to search for tasks. * * @return The regular expression. This may be <code>null</code> if no * regular expression was specified (or an empty string was * specified). * @see #setTaskPattern(String) */ public String getTaskPattern() { return taskPattern==null ? null : taskPattern.pattern(); } public ParseResult parse(RSyntaxDocument doc, String style) { Element root = doc.getDefaultRootElement(); int lineCount = root.getElementCount(); if (taskPattern==null || style==null || SyntaxConstants.SYNTAX_STYLE_NONE.equals(style)){ result.clearNotices(); result.setParsedLines(0, lineCount-1); return result; } // TODO: Pass in parsed line range and just do that result.clearNotices(); result.setParsedLines(0, lineCount-1); for (int line=0; line<lineCount; line++) { Token t = doc.getTokenListForLine(line); int offs = -1; int start = -1; String text = null; while (t!=null && t.isPaintable()) { if (t.isComment()) { offs = t.getOffset(); text = t.getLexeme(); Matcher m = taskPattern.matcher(text); if (m.find()) { start = m.start(); offs += start; break; } } t = t.getNextToken(); } if (start>-1) { text = text.substring(start); // TODO: Strip off end of MLC's if they're there. int len = text.length(); TaskNotice pn = new TaskNotice(this, text, line+1, offs, len); pn.setLevel(ParserNotice.Level.INFO); pn.setShowInEditor(false); pn.setColor(COLOR); result.addNotice(pn); } } return result; } /** * Sets the pattern of task identifiers. You will usually want this to be * a list of words "or'ed" together, such as * "<code>TODO|FIXME|HACK|REMIND</code>". * * @param pattern The pattern. A value of <code>null</code> or an * empty string effectively disables task parsing. * @throws PatternSyntaxException If <code>pattern</code> is an invalid * regular expression. * @see #getTaskPattern() */ public void setTaskPattern(String pattern) throws PatternSyntaxException { if (pattern==null || pattern.length()==0) { taskPattern = null; } else { taskPattern = Pattern.compile(pattern); } } /** * A parser notice that signifies a task. This class is here so we can * treat tasks specially and show them in the {@link ErrorStrip} even * though they are <code>INFO</code>-level and marked as "don't show in * editor." */ public static class TaskNotice extends DefaultParserNotice { public TaskNotice(Parser parser, String message, int line, int offs, int length) { super(parser, message, line, offs, length); } } }