diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index 7d84d45f6..b319248f5 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -5,7 +5,6 @@ import java.awt.event.*; import java.beans.*; import java.io.*; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -204,9 +203,15 @@ public class JavaEditor extends Editor { super.rebuild(); // after Rename and New Tab, we may have new .java tabs - hasJavaTabs = checkForJavaTabs(); + boolean newHasJavaTabs = checkForJavaTabs(); + boolean hasJavaTabsChanged = hasJavaTabs != newHasJavaTabs; + hasJavaTabs = newHasJavaTabs; if (errorCheckerService != null) { + if (hasJavaTabsChanged) { + errorCheckerService.handleHasJavaTabsChange(hasJavaTabs); + } + int currentTabCount = sketch.getCodeCount(); if (currentTabCount != previousTabCount) { previousTabCount = currentTabCount; @@ -2753,7 +2758,7 @@ public class JavaEditor extends Editor { jmode.loadPreferences(); Messages.log("Applying prefs"); // trigger it once to refresh UI - errorCheckerService.handleErrorCheckingToggle(); + errorCheckerService.handlePreferencesChange(); } } diff --git a/java/src/processing/mode/java/MarkerColumn.java b/java/src/processing/mode/java/MarkerColumn.java index e87f0dbba..9cbedfed5 100644 --- a/java/src/processing/mode/java/MarkerColumn.java +++ b/java/src/processing/mode/java/MarkerColumn.java @@ -29,6 +29,7 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import javax.swing.JPanel; @@ -114,12 +115,9 @@ public class MarkerColumn extends JPanel { public void updateErrorPoints(final List problems) { - errorPoints.clear(); - // Each problem.getSourceLine() will have an extra line added because - // of class declaration in the beginning as well as default imports - for (Problem problem : problems) { - errorPoints.add(new LineMarker(problem, problem.isError())); - } + errorPoints = problems.stream() + .map(problem -> new LineMarker(problem, problem.isError())) + .collect(Collectors.toList()); repaint(); editor.getErrorChecker().updateEditorStatus(); } @@ -166,7 +164,6 @@ public class MarkerColumn extends JPanel { private void recalculateMarkerPositions() { - List errorPoints = getErrorPoints(); if (errorPoints != null && errorPoints.size() > 0) { Sketch sketch = editor.getSketch(); SketchCode code = sketch.getCurrentCode(); diff --git a/java/src/processing/mode/java/pdex/ErrorCheckerService.java b/java/src/processing/mode/java/pdex/ErrorCheckerService.java index b8fabbf24..553e32728 100644 --- a/java/src/processing/mode/java/pdex/ErrorCheckerService.java +++ b/java/src/processing/mode/java/pdex/ErrorCheckerService.java @@ -118,7 +118,6 @@ public class ErrorCheckerService { private volatile long nextUiUpdate = 0; private final Object requestLock = new Object(); - private final Object serialCallbackLock = new Object(); private boolean needsCheck = false; private CompletableFuture preprocessingTask = @@ -126,20 +125,23 @@ public class ErrorCheckerService { complete(PreprocessedSketch.empty()); // initialization block }}; - private CompletableFuture lastErrorCheckTask = - new CompletableFuture() {{ - complete(null); // initalization block - }}; - private CompletableFuture lastCallback = new CompletableFuture() {{ complete(null); // initialization block }}; + private final Consumer errorHandlerListener = this::handleSketchErrors; + + private volatile boolean isEnabled = true; + private volatile boolean isContinuousCheckEnabled = true; + public ErrorCheckerService(JavaEditor editor) { this.editor = editor; astGenerator = new ASTGenerator(editor, this); + isEnabled = !editor.hasJavaTabs(); + isContinuousCheckEnabled = JavaMode.errorCheckEnabled; + registerDoneListener(errorHandlerListener); } @@ -202,24 +204,14 @@ public class ErrorCheckerService { public void notifySketchChanged() { - if (editor.hasJavaTabs()) return; + if (!isEnabled) return; synchronized (requestLock) { if (preprocessingTask.isDone()) { preprocessingTask = new CompletableFuture<>(); - lastErrorCheckTask = preprocessingTask - // Run error handler after both preprocessing - // task and previous error handler completed - .thenAcceptBothAsync(lastErrorCheckTask, - (ps, a) -> handleSketchErrors(ps)) - // Make sure exception in error handler won't spoil the chain - .handleAsync((res, e) -> { - if (e != null) Messages.loge("problem during error handling", e); - return res; - }); - // Fire listeners, don't trigger check - acceptWhenDone(this::fireDoneListeners, false); + // Register callback which executes all listeners + registerCallback(this::fireDoneListeners); } - if (isContinuousCheckEnabled()) { + if (isContinuousCheckEnabled) { // Continuous check enabled, request nextUiUpdate = System.currentTimeMillis() + errorCheckInterval; requestQueue.offer(Boolean.TRUE); @@ -231,24 +223,9 @@ public class ErrorCheckerService { } - public void acceptWhenDone(Consumer callback) { - // Public version always triggers check - acceptWhenDone(callback, true); - } - - - private void acceptWhenDone(Consumer callback, boolean triggerCheck) { - if (editor.hasJavaTabs()) return; - if (triggerCheck) { - // Continuous check not enabled, request check now - synchronized (requestLock) { - if (!isContinuousCheckEnabled() && needsCheck) { - needsCheck = false; - requestQueue.offer(Boolean.TRUE); - } - } - } - synchronized (serialCallbackLock) { + private void registerCallback(Consumer callback) { + if (!isEnabled) return; + synchronized (requestLock) { lastCallback = preprocessingTask // Run callback after both preprocessing task and previous callback .thenAcceptBothAsync(lastCallback, (ps, a) -> callback.accept(ps)) @@ -261,6 +238,19 @@ public class ErrorCheckerService { } + public void acceptWhenDone(Consumer callback) { + if (!isEnabled) return; + synchronized (requestLock) { + // Continuous check not enabled, request check now + if (needsCheck && !isContinuousCheckEnabled) { + needsCheck = false; + requestQueue.offer(Boolean.TRUE); + } + registerCallback(callback); + } + } + + /// LISTENERS ---------------------------------------------------------------- @@ -529,7 +519,7 @@ public class ErrorCheckerService { } } - final boolean updateErrorToggle = ps.hasSyntaxErrors || + final boolean hasErrors = ps.hasSyntaxErrors || ps.hasCompilationErrors; if (scheduledUiUpdate != null) { @@ -540,11 +530,8 @@ public class ErrorCheckerService { Runnable uiUpdater = () -> { if (nextUiUpdate > 0 && System.currentTimeMillis() >= nextUiUpdate) { EventQueue.invokeLater(() -> { - if (JavaMode.errorCheckEnabled) { - updateErrorTable(problems); - editor.updateErrorBar(problems); - editor.getTextArea().repaint(); - editor.updateErrorToggle(updateErrorToggle); + if (isContinuousCheckEnabled) { + setProblemList(problems, hasErrors); } }); } @@ -554,6 +541,14 @@ public class ErrorCheckerService { } + protected void setProblemList(List problems, boolean hasErrors) { + updateErrorTable(problems); + editor.updateErrorBar(problems); + editor.getTextArea().repaint(); + editor.updateErrorToggle(hasErrors); + } + + protected String[] buildClassPath(List neededImports) { JavaMode mode = (JavaMode) editor.getMode(); Sketch sketch = editor.getSketch(); @@ -811,7 +806,7 @@ public class ErrorCheckerService { // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); - if (JavaMode.errorCheckEnabled) { + if (isContinuousCheckEnabled) { LineMarker errorMarker = editor.findError(editor.getTextArea().getCaretLine()); if (errorMarker != null) { if (errorMarker.getType() == LineMarker.WARNING) { @@ -897,22 +892,28 @@ public class ErrorCheckerService { } - private static boolean isContinuousCheckEnabled() { - return JavaMode.errorCheckEnabled; + public void handlePreferencesChange() { + isContinuousCheckEnabled = JavaMode.errorCheckEnabled; + if (isContinuousCheckEnabled) { + Messages.log(editor.getSketch().getName() + " Error Checker enabled."); + notifySketchChanged(); + } else { + Messages.log(editor.getSketch().getName() + " Error Checker disabled."); + setProblemList(Collections.emptyList(), false); + } } - public void handleErrorCheckingToggle() { - if (!JavaMode.errorCheckEnabled) { - Messages.log(editor.getSketch().getName() + " Error Checker disabled."); - editor.getErrorPoints().clear(); - updateErrorTable(Collections.emptyList()); - updateEditorStatus(); - editor.getTextArea().repaint(); - editor.repaintErrorBar(); - } else { - Messages.log(editor.getSketch().getName() + " Error Checker enabled."); + public void handleHasJavaTabsChange(boolean hasJavaTabs) { + isEnabled = !hasJavaTabs; + if (isEnabled) { notifySketchChanged(); + } else { + preprocessingTask.cancel(false); + setProblemList(Collections.emptyList(), false); + if (astGenerator.getGui().showUsageBinding != null) { + astGenerator.getGui().showUsageWindow.setVisible(false); + } } }