Programatically add ParserNotices to RSTA

Questions on using RSyntaxTextArea should go here.

Moderator: robert

Programatically add ParserNotices to RSTA

Postby preditcon » Fri Jan 24, 2014 2:33 pm

As can be seen in the attached SSCCE, I've tried to invoke a second parser from an existing one. But unless I use a timer or wrap the invocation within a swingutilities invokeLater, my ParserNotices from the second parser do not get delegated to RSTA (no squiggles). Is there a safe way of doing what I'm trying to do here?

Basically I want to programatically add ParserNotices to RSTA. The example is an attempt to abuse a "hidden" parser to achieve this, since I haven't found another way to do it, other than through a ParseResult. Uncomment "invoker.restart();" and comment the next line to see the desired result.

java code:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.fife.ui.rsyntaxtextarea.ErrorStrip;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.parser.AbstractParser;
import org.fife.ui.rsyntaxtextarea.parser.ParseResult;
import org.fife.ui.rsyntaxtextarea.parser.Parser;
import org.fife.ui.rsyntaxtextarea.parser.ParserNotice;
import org.fife.ui.rtextarea.RTextScrollPane;

public class SecondParser extends JFrame {

private RTextScrollPane scroll;
private RSyntaxTextArea rsta;
private JButton reparse;
private ErrorStrip annotations;
private MyParser parser;
private MyParserMimic mimic;
private Timer invoker;

public SecondParser() {
initComponents();
}

private void initComponents() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());

rsta = new RSyntaxTextArea();
rsta.setEditable(false);
rsta.setText(
"Debugging is twice as hard as writing the code in the first "
+ "place. Therefore, if you\n"
+ "write the code as cleverly as possible, you are, by "
+ "definition, not smart enough to\n"
+ "debug it.\n\n"
+ "Brian Kernighan");

scroll = new RTextScrollPane(rsta);
add(scroll, BorderLayout.CENTER);

reparse = new JButton("Reparse");
add(reparse, BorderLayout.PAGE_END);
reparse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
rsta.append("!");
}
});

annotations = new ErrorStrip(rsta);
add(annotations, BorderLayout.EAST);

setSize(650, 200);
setLocationRelativeTo(null);

invoker = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
invokeSecondParser();
}
});
invoker.setRepeats(false);

parser = new MyParser();
rsta.addParser(parser);

mimic = new MyParserMimic();
mimic.setEnabled(false);
rsta.addParser(mimic);
}

private void invokeSecondParser() {
mimic.setEnabled(true);
try {
rsta.forceReparsing(mimic);
} finally {
mimic.setEnabled(false);
}
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {

public void run() {
new SecondParser().setVisible(true);
}
});
}

public class MyParser extends AbstractParser {

public ParseResult parse(RSyntaxDocument doc, String style) {
MyParserNotice notice = new MyParserNotice(
this, ParserNotice.ERROR, 1, "Something went terribly wrong.", 10, 10);
List<ParserNotice> notices = new ArrayList<ParserNotice>();
notices.add(notice);
// invoker.restart();
invokeSecondParser();
return new MyParseResult(
null, 0, doc.getDefaultRootElement().getElementCount(),
notices, this, 0);
}

}

public class MyParserMimic extends AbstractParser {

public ParseResult parse(RSyntaxDocument doc, String style) {
List<ParserNotice> notices = new ArrayList<ParserNotice>();
MyParserNotice notice;
notice = new MyParserNotice(
this, ParserNotice.ERROR, 1, "Something else went terribly wrong.", 10, 10);
notices.add(notice);
notice = new MyParserNotice(
this, ParserNotice.ERROR, 2, "Another thing went terribly wrong.", 90, 10);
notices.add(notice);
return new MyParseResult(
null, 0, doc.getDefaultRootElement().getElementCount(),
notices, this, 0);
}

}

public class MyParseResult implements ParseResult {

private Exception exception;
private int firstLine;
private int lastLine;
private List<ParserNotice> notices;
private AbstractParser parser;
private long parseTime;

public MyParseResult(
Exception exception, int firstLine, int lastLine,
List<ParserNotice> notices, AbstractParser parser,
long parseTime) {
this.exception = exception;
this.firstLine = firstLine;
this.lastLine = lastLine;
this.notices = notices;
this.parser = parser;
this.parseTime = parseTime;
}

public Exception getError() {
return exception;
}

public int getFirstLineParsed() {
return firstLine;
}

public int getLastLineParsed() {
return lastLine;
}

public List getNotices() {
return notices;
}

public Parser getParser() {
return parser;
}

public long getParseTime() {
return parseTime;
}

}

public class MyParserNotice implements ParserNotice {

private int level;
private int line;
private String message;
private Parser parser;
private String tooltip;
private int offset;
private int length;

public MyParserNotice(
Parser parser, int level, int line, String message, int offset,
int length) {
this.parser = parser;
this.level = level;
this.line = line;
this.message = message;
this.tooltip = this.message;
this.offset = offset;
this.length = length;
}

public boolean containsPosition(int i) {
return offset <= i && i < (offset + length);
}

public Color getColor() {
return Color.RED;
}

public int getLength() {
return length;
}

public int getLevel() {
return level;
}

public int getLine() {
return line;
}

public String getMessage() {
return message;
}

public int getOffset() {
return offset;
}

public Parser getParser() {
return parser;
}

public boolean getShowInEditor() {
return true;
}

public String getToolTipText() {
return tooltip;
}

public int compareTo(ParserNotice o) {
// just compare levels
if (o instanceof MyParserNotice) {
MyParserNotice other = (MyParserNotice) o;
if (this.level == other.level) {
return 0;
} else {
return this.level > other.level ? 1 : -1;
}
}
return -1;
}
}
}
preditcon
 
Posts: 27
Joined: Wed Jan 25, 2012 10:09 am

Re: Programatically add ParserNotices to RSTA

Postby robert » Sat Feb 01, 2014 12:38 am

I've just recently run into a similar situation, where I wanted to generate my ParserNotices in a separate thread, and update RSTA on the EDT when it completed. I might have a "real" fix for this soon; in the mean time I'll try to come up with a workaround for you.
User avatar
robert
 
Posts: 805
Joined: Sat May 10, 2008 5:16 pm

Re: Programatically add ParserNotices to RSTA

Postby preditcon » Tue Feb 11, 2014 12:11 pm

The above code actually represents a possible workaround, just not sure how safe it is to rely on timing to make it work. In my tests it works nicely, but it might be inherently broken anyways.
preditcon
 
Posts: 27
Joined: Wed Jan 25, 2012 10:09 am

Re: Programatically add ParserNotices to RSTA

Postby robert » Thu Feb 13, 2014 5:23 am

Well, I don't think your strategy will ever really fail, so I'd just say to go with what works. In the future the Parser API may change somewhat drastically, using deferreds or a callback mechanism to better support slower parsers, as well as an easy way to manually add parser notices programmatically.
User avatar
robert
 
Posts: 805
Joined: Sat May 10, 2008 5:16 pm


Return to Help

Who is online

Users browsing this forum: No registered users and 2 guests

cron