Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error highlighting in IDE. #715

Merged
merged 10 commits into from
Jul 13, 2023
107 changes: 104 additions & 3 deletions app/src/processing/app/Problem.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,117 @@

package processing.app;

import java.util.Optional;


/**
* Structure describing a problem encountered in sketch compilation.
*/
public interface Problem {

/**
* Strategy converting line number in tab to character offset from tab start.
*/
public interface LineToTabOffsetGetter {

/**
* Convert a line number to the number of characters past tab start.
*
* @param line The line number to convert.
* @return The number of characters past tab start where that line starts.
*/
public int get(int line);

}

/**
* Get if the problem is an error that prevented compilation.
*
* @return True if an error such that the sketch did not compile and false
* otherwise.
*/
public boolean isError();

/**
* Get if the problem is an warning that did not prevent compilation.
*
* @return True if a warning and the sketch compiled and false otherwise.
*/
public boolean isWarning();

/**
* Get which tab (sketch file) the problem was encountered.
*
* @return The index of the tab in which the problem was encountered.
*/
public int getTabIndex();
public int getLineNumber(); // 0-indexed

/**
* Get at which line the problem was encountered.
*
* @return Zero-indexed line number within the tab at getTabIndex in which
* this problem was encountered. Note that this is not the line in the
* generated Java file.
*/
public int getLineNumber();

/**
* Get a human-reabable description of the problem encountered.
*
* @return String describing the error or warning encountered.
*/
public String getMessage();

public int getStartOffset();
public int getStopOffset();
/**
* Get the exact character on which this problem starts in code tab relative.
*
* @return Number of characters past the start of the tab if known where the
* code associated with the Problem starts. Returns empty if not provided.
*/
public Optional<Integer> getTabStartOffset();

/**
* Get the exact character on which this problem ends in code tab relative.
*
* @return Number of characters past the start of the tab if known where the
* code associated with the Problem ends. Returns empty if not provided.
*/
public Optional<Integer> getTabStopOffset();

/**
* Get the exact character on which this problem starts in code line relative.
*
* @return Number of characters past the start of the line if known where the
* code associated with the Problem starts. Returns empty if not provided.
*/
public Optional<Integer> getLineStartOffset();

/**
* Get the exact character on which this problem ends in code line relative.
*
* @return Number of characters past the start of the line if known where the
* code associated with the Problem ends. Returns empty if not provided.
*/
public Optional<Integer> getLineStopOffset();

/**
* Get the exact character on which this problem ends in code tab relative.
*
* @param strategy Strategy to convert line to tab start if needed.
* @return Number of characters past the start of the tab if known where the
* code associated with the Problem ends, using the provided conversion
* if needed. Returns line start if character position not given.
*/
public int computeTabStartOffset(LineToTabOffsetGetter strategy);

/**
* Get the exact character on which this problem ends in code tab relative.
*
* @param strategy Strategy to convert line to tab start if needed.
* @return Number of characters past the start of the tab if known where the
* code associated with the Problem ends, using the provided conversion
* if needed. Returns line start if character position not given.
*/
public int computeTabStopOffset(LineToTabOffsetGetter strategy);
}

26 changes: 18 additions & 8 deletions app/src/processing/app/syntax/PdeTextAreaPainter.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public class PdeTextAreaPainter extends TextAreaPainter {
protected Color gutterTextInactiveColor;
protected Color gutterHighlightColor;

private final Problem.LineToTabOffsetGetter lineToTabOffsetGetter;


public PdeTextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults) {
super(textArea, defaults);
Expand Down Expand Up @@ -76,6 +78,10 @@ public void mousePressed(MouseEvent event) {
}
}
});

lineToTabOffsetGetter = (x) -> {
return textArea.getLineStartOffset(x);
};
}


Expand Down Expand Up @@ -147,13 +153,14 @@ protected void paintLine(Graphics gfx, int line, int x, TokenMarkerState marker)
protected void paintErrorLine(Graphics gfx, int line, int x) {
List<Problem> problems = getEditor().findProblems(line);
for (Problem problem : problems) {
int startOffset = problem.getStartOffset();
int stopOffset = problem.getStopOffset();
int startOffset = problem.computeTabStartOffset(lineToTabOffsetGetter);
int stopOffset = problem.computeTabStopOffset(lineToTabOffsetGetter);

int lineOffset = textArea.getLineStartOffset(line);
int lineOffsetStart = textArea.getLineStartOffset(line);
int lineOffsetStop = textArea.getLineStopOffset(line);

int wiggleStart = Math.max(startOffset, lineOffset);
int wiggleStop = Math.min(stopOffset, textArea.getLineStopOffset(line));
int wiggleStart = Math.max(startOffset, lineOffsetStart);
int wiggleStop = Math.min(stopOffset, lineOffsetStop);

int y = textArea.lineToY(line) + getLineDisplacement();

Expand All @@ -163,7 +170,10 @@ protected void paintErrorLine(Graphics gfx, int line, int x) {
try {
SyntaxDocument doc = textArea.getDocument();
badCode = doc.getText(wiggleStart, wiggleStop - wiggleStart);
goodCode = doc.getText(lineOffset, wiggleStart - lineOffset);
goodCode = doc.getText(
lineOffsetStart,
wiggleStart - lineOffsetStart
);
//log("paintErrorLine() LineText GC: " + goodCode);
//log("paintErrorLine() LineText BC: " + badCode);
} catch (BadLocationException bl) {
Expand Down Expand Up @@ -328,8 +338,8 @@ public String getToolTipText(MouseEvent event) {
int lineStart = textArea.getLineStartOffset(line);
int lineEnd = textArea.getLineStopOffset(line);

int errorStart = problem.getStartOffset();
int errorEnd = problem.getStopOffset() + 1;
int errorStart = problem.computeTabStartOffset(lineToTabOffsetGetter);
int errorEnd = problem.computeTabStopOffset(lineToTabOffsetGetter) + 1;

int startOffset = Math.max(errorStart, lineStart) - lineStart;
int stopOffset = Math.min(errorEnd, lineEnd) - lineStart;
Expand Down
14 changes: 12 additions & 2 deletions app/src/processing/app/ui/Editor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2556,8 +2556,15 @@ public void updateErrorTable(List<Problem> problems) {


public void highlight(Problem p) {
Problem.LineToTabOffsetGetter getter = (x) -> {
return textarea.getLineStartOffset(x);
};

if (p != null) {
highlight(p.getTabIndex(), p.getStartOffset(), p.getStopOffset());
int tabIndex = p.getTabIndex();
int tabToStartOffset = p.computeTabStartOffset(getter);
int tabToStopOffset = p.computeTabStopOffset(getter);
highlight(tabIndex, tabToStartOffset, tabToStopOffset);
}
}

Expand Down Expand Up @@ -2623,8 +2630,11 @@ public List<Problem> findProblems(int line) {
.filter(p -> p.getTabIndex() == currentTab)
.filter(p -> {
int pStartLine = p.getLineNumber();
int pEndOffset = p.getStopOffset();
int pEndOffset = p.computeTabStopOffset(
(startLine) -> textarea.getLineStartOffset(pStartLine)
);
int pEndLine = textarea.getLineOfOffset(pEndOffset);

return line >= pStartLine && line <= pEndLine;
})
.collect(Collectors.toList());
Expand Down
11 changes: 9 additions & 2 deletions java/src/processing/mode/java/ErrorChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,16 @@ static private List<JavaProblem> checkForCurlyQuotes(PreprocSketch ps) {
String q = matcher.group();
int tabStart = in.startTabOffset + offset;
int tabStop = tabStart + 1;
int line = ps.tabOffsetToTabLine(in.tabIndex, tabStart);

// Prevent duplicate problems
if (problems.stream().noneMatch(p -> p.getStartOffset() == tabStart)) {
int line = ps.tabOffsetToTabLine(in.tabIndex, tabStart);
boolean isDupe = problems.stream()
.filter(p -> p.getTabIndex() == in.tabIndex)
.filter(p -> p.getLineNumber() == line)
.findAny()
.isPresent();

if (isDupe) {
String message;
if (iproblem.getID() == IProblem.UnterminatedString) {
message = Language.interpolate("editor.status.unterm_string_curly", q);
Expand Down
61 changes: 55 additions & 6 deletions java/src/processing/mode/java/JavaProblem.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

package processing.mode.java;

import java.util.Optional;

import org.eclipse.jdt.core.compiler.IProblem;

import processing.app.Problem;
Expand All @@ -42,9 +44,9 @@ public class JavaProblem implements Problem {
/** Line number (pde code) of the error */
private final int lineNumber;

private int startOffset;
private Optional<Integer> startOffset;

private int stopOffset;
private Optional<Integer> stopOffset;

/**
* If the error is a 'cannot find type' contains the list of suggested imports
Expand All @@ -60,6 +62,8 @@ public JavaProblem(String message, int type, int tabIndex, int lineNumber) {
this.type = type;
this.tabIndex = tabIndex;
this.lineNumber = lineNumber;
this.startOffset = Optional.empty();
this.stopOffset = Optional.empty();
}


Expand All @@ -83,22 +87,31 @@ static public JavaProblem fromIProblem(IProblem iProblem, int tabIndex,


public void setPDEOffsets(int startOffset, int stopOffset){
this.startOffset = startOffset;
this.stopOffset = stopOffset;
this.startOffset = Optional.of(startOffset);
this.stopOffset = Optional.of(stopOffset);
}


@Override
public int getStartOffset() {
public Optional<Integer> getTabStartOffset() {
return startOffset;
}


@Override
public int getStopOffset() {
public Optional<Integer> getTabStopOffset() {
return stopOffset;
}

@Override
public Optional<Integer> getLineStartOffset() {
return Optional.empty();
}

@Override
public Optional<Integer> getLineStopOffset() {
return Optional.empty();
}

@Override
public boolean isError() {
Expand Down Expand Up @@ -139,11 +152,47 @@ public void setImportSuggestions(String[] a) {
importSuggestions = a;
}

public boolean usesLineOffset() {
return false;
}

@Override
public String toString() {
return "TAB " + tabIndex + ",LN " + lineNumber + "LN START OFF: "
+ startOffset + ",LN STOP OFF: " + stopOffset + ",PROB: "
+ message;
}

@Override
public int computeTabStartOffset(LineToTabOffsetGetter strategy) {
Optional<Integer> nativeTabStartOffset = getTabStartOffset();
if (nativeTabStartOffset.isPresent()) {
return nativeTabStartOffset.get();
}

Optional<Integer> lineStartOffset = getLineStartOffset();
int lineOffset = strategy.get(getLineNumber());
if (lineStartOffset.isPresent()) {
return lineOffset + lineStartOffset.get();
} else {
return lineOffset;
}
}

@Override
public int computeTabStopOffset(LineToTabOffsetGetter strategy) {
Optional<Integer> nativeTabStopOffset = getTabStopOffset();
if (nativeTabStopOffset.isPresent()) {
return nativeTabStopOffset.get();
}

Optional<Integer> lineStopOffset = getLineStopOffset();
int lineOffset = strategy.get(getLineNumber());
if (lineStopOffset.isPresent()) {
return lineOffset + lineStopOffset.get();
} else {
return lineOffset;
}
}

}
8 changes: 5 additions & 3 deletions java/src/processing/mode/java/ProblemFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public static Problem build(PdePreprocessIssue pdePreprocessIssue, List<Integer>
localLine,
message,
lineStart,
lineStop
lineStop,
false
);
}

Expand Down Expand Up @@ -83,8 +84,9 @@ public static Problem build(PdePreprocessIssue pdePreprocessIssue, List<Integer>
tab,
localLine,
message,
localLine,
localLine + col
0,
col,
true
);
}

Expand Down
Loading