diff --git a/app/src/processing/app/Problem.java b/app/src/processing/app/Problem.java index 2e69c8dd1..c5f633c67 100644 --- a/app/src/processing/app/Problem.java +++ b/app/src/processing/app/Problem.java @@ -20,12 +20,29 @@ 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. * @@ -65,32 +82,55 @@ public interface Problem { public String getMessage(); /** - * Determine against what reference point for the this Problem's specific - * location is reported. + * 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 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 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 getLineStartOffset(); + + /** + * Get the exact character on which this problem ends in code line relative. * - * @return True if getStartOffset and getStopOffset are number of characters - * relative to the start of the line reported by getLineNumber. False if - * getStartOffset and getStopOffset are number of characters from start of - * the tab. + * @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 boolean usesLineOffset(); + public Optional getLineStopOffset(); /** - * Get the exact character on which this problem starts in code. + * Get the exact character on which this problem ends in code tab relative. * - * @return Number of characters past the reference point in usesLineOffset - * at which this problem starts (where the code to which the problem - * is attributed starts). + * @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 getStartOffset(); + public int computeTabStartOffset(LineToTabOffsetGetter strategy); /** - * Get the exact character on which this problem ends in code. + * Get the exact character on which this problem ends in code tab relative. * - * @return Number of characters past the reference point in usesLineOffset - * at which this problem ends (where the code to which the problem - * is attributed ends). + * @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 getStopOffset(); + public int computeTabStopOffset(LineToTabOffsetGetter strategy); } diff --git a/app/src/processing/app/syntax/PdeTextAreaPainter.java b/app/src/processing/app/syntax/PdeTextAreaPainter.java index e55fa413c..be0d5fdc8 100644 --- a/app/src/processing/app/syntax/PdeTextAreaPainter.java +++ b/app/src/processing/app/syntax/PdeTextAreaPainter.java @@ -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); @@ -76,6 +78,10 @@ public void mousePressed(MouseEvent event) { } } }); + + lineToTabOffsetGetter = (x) -> { + return textArea.getLineStartOffset(x); + }; } @@ -147,18 +153,14 @@ protected void paintLine(Graphics gfx, int line, int x, TokenMarkerState marker) protected void paintErrorLine(Graphics gfx, int line, int x) { List 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); - - if (problem.usesLineOffset()) { - startOffset += lineOffset; - stopOffset += lineOffset; - } + 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(); @@ -168,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) { @@ -333,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; diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java index 3cf6d7ba1..824f8ac20 100644 --- a/app/src/processing/app/ui/Editor.java +++ b/app/src/processing/app/ui/Editor.java @@ -2556,8 +2556,15 @@ public void updateErrorTable(List 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); } } @@ -2623,15 +2630,10 @@ public List findProblems(int line) { .filter(p -> p.getTabIndex() == currentTab) .filter(p -> { int pStartLine = p.getLineNumber(); - int pEndOffset = p.getStopOffset(); - - int pEndLine; - if (p.usesLineOffset()) { - int lineGlobalOffset = textarea.getLineStartOffset(pStartLine); - pEndLine = textarea.getLineOfOffset(pEndOffset + lineGlobalOffset); - } else { - pEndLine = textarea.getLineOfOffset(pEndOffset); - } + int pEndOffset = p.computeTabStopOffset( + (startLine) -> textarea.getLineStartOffset(pStartLine) + ); + int pEndLine = textarea.getLineOfOffset(pEndOffset); return line >= pStartLine && line <= pEndLine; }) diff --git a/java/src/processing/mode/java/ErrorChecker.java b/java/src/processing/mode/java/ErrorChecker.java index 015673ed3..1302dd773 100644 --- a/java/src/processing/mode/java/ErrorChecker.java +++ b/java/src/processing/mode/java/ErrorChecker.java @@ -277,9 +277,16 @@ static private List 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); diff --git a/java/src/processing/mode/java/JavaProblem.java b/java/src/processing/mode/java/JavaProblem.java index adf86fcab..5233c785c 100644 --- a/java/src/processing/mode/java/JavaProblem.java +++ b/java/src/processing/mode/java/JavaProblem.java @@ -20,6 +20,8 @@ package processing.mode.java; +import java.util.Optional; + import org.eclipse.jdt.core.compiler.IProblem; import processing.app.Problem; @@ -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 startOffset; - private int stopOffset; + private Optional stopOffset; /** * If the error is a 'cannot find type' contains the list of suggested imports @@ -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(); } @@ -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 getTabStartOffset() { return startOffset; } @Override - public int getStopOffset() { + public Optional getTabStopOffset() { return stopOffset; } + @Override + public Optional getLineStartOffset() { + return Optional.empty(); + } + + @Override + public Optional getLineStopOffset() { + return Optional.empty(); + } @Override public boolean isError() { @@ -149,4 +162,37 @@ public String toString() { + startOffset + ",LN STOP OFF: " + stopOffset + ",PROB: " + message; } + + @Override + public int computeTabStartOffset(LineToTabOffsetGetter strategy) { + Optional nativeTabStartOffset = getTabStartOffset(); + if (nativeTabStartOffset.isPresent()) { + return nativeTabStartOffset.get(); + } + + Optional lineStartOffset = getLineStartOffset(); + int lineOffset = strategy.get(getLineNumber()); + if (lineStartOffset.isPresent()) { + return lineOffset + lineStartOffset.get(); + } else { + return lineOffset; + } + } + + @Override + public int computeTabStopOffset(LineToTabOffsetGetter strategy) { + Optional nativeTabStopOffset = getTabStopOffset(); + if (nativeTabStopOffset.isPresent()) { + return nativeTabStopOffset.get(); + } + + Optional lineStopOffset = getLineStopOffset(); + int lineOffset = strategy.get(getLineNumber()); + if (lineStopOffset.isPresent()) { + return lineOffset + lineStopOffset.get(); + } else { + return lineOffset; + } + } + } diff --git a/java/src/processing/mode/java/SyntaxProblem.java b/java/src/processing/mode/java/SyntaxProblem.java index a1af0ed8b..bf037b971 100644 --- a/java/src/processing/mode/java/SyntaxProblem.java +++ b/java/src/processing/mode/java/SyntaxProblem.java @@ -1,5 +1,26 @@ +/* +Part of the Processing project - http://processing.org +Copyright (c) 2012-15 The Processing Foundation + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 +as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + package processing.mode.java; +import java.util.Optional; + + /** * Problem identifying a syntax error found in preprocessing. */ @@ -8,9 +29,10 @@ public class SyntaxProblem extends JavaProblem { private final int tabIndex; private final int lineNumber; private final String message; - private final int startOffset; - private final int stopOffset; - private final boolean lineFlag; + private final Optional tabStartOffset; + private final Optional tabStopOffset; + private final Optional lineStartOffset; + private final Optional lineStopOffset; /** * Create a new syntax problem. @@ -33,9 +55,18 @@ public SyntaxProblem(int newTabIndex, int newLineNumber, String newMessage, int tabIndex = newTabIndex; lineNumber = newLineNumber; message = newMessage; - startOffset = newStartOffset; - stopOffset = newStopOffset; - lineFlag = newUsesLineOffset; + + if (newUsesLineOffset) { + lineStartOffset = Optional.of(newStartOffset); + lineStopOffset = Optional.of(newStopOffset); + tabStartOffset = Optional.empty(); + tabStopOffset = Optional.empty(); + } else { + lineStartOffset = Optional.empty(); + lineStopOffset = Optional.empty(); + tabStartOffset = Optional.of(newStartOffset); + tabStopOffset = Optional.of(newStopOffset); + } } @Override @@ -64,17 +95,23 @@ public String getMessage() { } @Override - public int getStartOffset() { - return startOffset; + public Optional getTabStartOffset() { + return tabStartOffset; } @Override - public int getStopOffset() { - return stopOffset; + public Optional getTabStopOffset() { + return tabStopOffset; } - public boolean usesLineOffset() { - return lineFlag; + @Override + public Optional getLineStartOffset() { + return lineStartOffset; + } + + @Override + public Optional getLineStopOffset() { + return lineStopOffset; } } diff --git a/java/src/processing/mode/java/lsp/PdeAdapter.java b/java/src/processing/mode/java/lsp/PdeAdapter.java index 24dc2e1d6..9e8942e27 100644 --- a/java/src/processing/mode/java/lsp/PdeAdapter.java +++ b/java/src/processing/mode/java/lsp/PdeAdapter.java @@ -233,13 +233,13 @@ void updateProblems(List problems) { new Position( prob.getLineNumber(), PdeAdapter - .toLineCol(code.getProgram(), prob.getStartOffset()) + .toLineCol(code.getProgram(), prob.getTabStartOffset().get()) .col - 1 ), new Position( prob.getLineNumber(), PdeAdapter - .toLineCol(code.getProgram(), prob.getStopOffset()) + .toLineCol(code.getProgram(), prob.getTabStopOffset().get()) .col - 1 ) ),