diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index d9d5508be..7ec79c433 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -29,7 +29,7 @@ import processing.app.ui.Toolkit; import processing.mode.java.debug.LineBreakpoint; import processing.mode.java.debug.LineHighlight; import processing.mode.java.debug.LineID; -import processing.mode.java.pdex.ErrorCheckerService; +import processing.mode.java.pdex.PreprocessingService; import processing.mode.java.pdex.ImportStatement; import processing.mode.java.pdex.JavaTextArea; import processing.mode.java.pdex.PDEX; @@ -70,7 +70,7 @@ public class JavaEditor extends Editor { private boolean hasJavaTabs; private boolean javaTabWarned; - protected ErrorCheckerService errorCheckerService; + protected PreprocessingService preprocessingService; protected PDEX pdex; protected List problems = Collections.emptyList(); @@ -150,7 +150,7 @@ public class JavaEditor extends Editor { getJavaTextArea().setMode(jmode); - initErrorChecker(); + initPDEX(); // ensure completion is hidden when editor loses focus addWindowFocusListener(new WindowFocusListener() { @@ -174,18 +174,9 @@ public class JavaEditor extends Editor { } - protected void initErrorChecker() { - errorCheckerService = new ErrorCheckerService(this); - for (SketchCode code : getSketch().getCode()) { - Document document = code.getDocument(); - if (document != null) { - errorCheckerService.addDocumentListener(document); - } - } - errorCheckerService.start(); - errorCheckerService.notifySketchChanged(); - - pdex = new PDEX(this, errorCheckerService); + protected void initPDEX() { + preprocessingService = new PreprocessingService(this); + pdex = new PDEX(this, preprocessingService); // Add ctrl+click listener getJavaTextArea().getPainter().addMouseListener(new MouseAdapter() { @@ -199,6 +190,44 @@ public class JavaEditor extends Editor { } } }); + + sketchChanged(); + + for (SketchCode code : getSketch().getCode()) { + Document document = code.getDocument(); + if (document != null) { + addDocumentListener(document); + } + } + } + + + public void addDocumentListener(Document doc) { + if (doc != null) doc.addDocumentListener(sketchChangedListener); + } + + + protected final DocumentListener sketchChangedListener = new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + sketchChanged(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + sketchChanged(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + sketchChanged(); + } + }; + + + protected void sketchChanged() { + pdex.notifySketchChanged(); + preprocessingService.notifySketchChanged(); } @@ -214,6 +243,7 @@ public class JavaEditor extends Editor { private int previousTabCount = 1; + // TODO: this is a clumsy way to get notified when tabs get added/deleted // Override the parent call to add hook to the rebuild() method public EditorHeader createHeader() { return new EditorHeader(this) { @@ -225,9 +255,9 @@ public class JavaEditor extends Editor { boolean hasJavaTabsChanged = hasJavaTabs != newHasJavaTabs; hasJavaTabs = newHasJavaTabs; - if (errorCheckerService != null) { + if (preprocessingService != null) { if (hasJavaTabsChanged) { - errorCheckerService.handleHasJavaTabsChange(hasJavaTabs); + preprocessingService.handleHasJavaTabsChange(hasJavaTabs); pdex.handleHasJavaTabsChange(hasJavaTabs); if (hasJavaTabs) { setProblemList(Collections.emptyList()); @@ -237,7 +267,7 @@ public class JavaEditor extends Editor { int currentTabCount = sketch.getCodeCount(); if (currentTabCount != previousTabCount) { previousTabCount = currentTabCount; - errorCheckerService.notifySketchChanged(); + sketchChanged(); } } } @@ -1327,13 +1357,13 @@ public class JavaEditor extends Editor { @Override public void librariesChanged() { - errorCheckerService.notifyLibrariesChanged(); + preprocessingService.notifyLibrariesChanged(); } @Override public void codeFolderChanged() { - errorCheckerService.notifyCodeFolderChanged(); + preprocessingService.notifyCodeFolderChanged(); } @@ -1374,111 +1404,12 @@ public class JavaEditor extends Editor { if (inspector != null) { inspector.dispose(); } - errorCheckerService.stop(); + preprocessingService.dispose(); pdex.dispose(); super.dispose(); } - // Not sure how this was supposed to work, tempErrorLog is always empty [jv] - /** - * Writes all error messages to a csv file. - * For analytics purposes only. - */ - /* - private void writeErrorsToFile() { - if (errorCheckerService.tempErrorLog.size() == 0) return; - - try { - System.out.println("Writing errors"); - StringBuilder sb = new StringBuilder(); - sb.append("Sketch: " + getSketch().getFolder() + ", " - + new java.sql.Timestamp(new java.util.Date().getTime()) - + "\nComma in error msg is substituted with ^ symbol\nFor separating arguments in error args | symbol is used\n"); - sb.append("ERROR TYPE, ERROR ARGS, ERROR MSG\n"); - - for (String errMsg : errorCheckerService.tempErrorLog.keySet()) { - IProblem ip = errorCheckerService.tempErrorLog.get(errMsg); - if (ip != null) { - sb.append(ErrorMessageSimplifier.getIDName(ip.getID())); - sb.append(','); - sb.append("{"); - for (int i = 0; i < ip.getArguments().length; i++) { - sb.append(ip.getArguments()[i]); - if (i < ip.getArguments().length-1) - sb.append("| "); - } - sb.append("}"); - sb.append(','); - sb.append(ip.getMessage().replace(',', '^')); - sb.append("\n"); - } - } - System.out.println(sb); - File opFile = new File(getSketch().getFolder(), "ErrorLogs" - + File.separator + "ErrorLog_" + System.currentTimeMillis() + ".csv"); - PApplet.saveStream(opFile, new ByteArrayInputStream(sb.toString() - .getBytes(Charset.defaultCharset()))); - } catch (Exception e) { - System.err.println("Failed to save log file for sketch " + getSketch().getName()); - e.printStackTrace(); - } - }*/ - - - /* - private AtomicBoolean debugToolbarEnabled; - - public boolean isDebugToolbarEnabled() { - return debugToolbarEnabled != null && debugToolbarEnabled.get(); - } - - - /// Toggles between java mode and debug mode toolbar - protected void switchToolbars(){ - final EditorToolbar nextToolbar; - if(debugToolbarEnabled.get()){ - // switch to java - if(javaToolbar == null) - javaToolbar = createToolbar(); - nextToolbar = javaToolbar; - debugToolbarEnabled.set(false); - Base.log("Switching to Java Mode Toolbar"); - } - else{ - // switch to debug - if(debugToolbar == null) - debugToolbar = new DebugToolbar(this, getBase()); - nextToolbar = debugToolbar; - debugToolbarEnabled.set(true); - Base.log("Switching to Debugger Toolbar"); - } - - SwingUtilities.invokeLater(new Runnable() { - public void run() { - Box upper = (Box)splitPane.getComponent(0); - upper.remove(0); - upper.add(nextToolbar, 0); - upper.validate(); - nextToolbar.repaint(); - toolbar = nextToolbar; - // The toolbar responds to shift down/up events - // in order to show the alt version of toolbar buttons. - // With toolbar switch, KeyListener has to be changed as well - for (KeyListener kl : textarea.getKeyListeners()) { - if(kl instanceof EditorToolbar) - { - textarea.removeKeyListener(kl); - textarea.addKeyListener(toolbar); - break; - } - } - textarea.repaint(); - } - }); - } - */ - /** * Creates the debug menu. Includes ActionListeners for the menu items. * Intended for adding to the menu bar. @@ -1660,26 +1591,6 @@ public class JavaEditor extends Editor { // }); // debugMenu.add(item); - /* - item = Toolkit.newJMenuItem(Language.text("menu.debug.show_sketch_outline"), KeyEvent.VK_L); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - Messages.log("Show Sketch Outline:"); - errorCheckerService.getASTGenerator().showSketchOutline(); - } - }); - debugMenu.add(item); - - item = Toolkit.newJMenuItem(Language.text("menu.debug.show_tabs_list"), KeyEvent.VK_Y); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - Messages.log("Show Tab Outline:"); - errorCheckerService.getASTGenerator().showTabOutline(); - } - }); - debugMenu.add(item); - */ - return debugMenu; } @@ -1928,8 +1839,8 @@ public class JavaEditor extends Editor { } - public ErrorCheckerService getErrorChecker() { - return errorCheckerService; + public PreprocessingService getPreprocessingService() { + return preprocessingService; } @@ -1942,7 +1853,7 @@ public class JavaEditor extends Editor { autoSave(); super.prepareRun(); downloadImports(); - errorCheckerService.cancel(); + preprocessingService.cancel(); } @@ -2388,8 +2299,8 @@ public class JavaEditor extends Editor { super.setCode(code); Document newDoc = code.getDocument(); - if (oldDoc != newDoc && errorCheckerService != null) { - errorCheckerService.addDocumentListener(newDoc); + if (oldDoc != newDoc && preprocessingService != null) { + addDocumentListener(newDoc); } // set line background colors for tab @@ -2529,24 +2440,6 @@ public class JavaEditor extends Editor { */ -// /** -// * Initializes and starts Error Checker Service -// */ -// private void initializeErrorChecker() { -// Thread errorCheckerThread = null; -// -// if (errorCheckerThread == null) { -// errorCheckerService = new ErrorCheckerService(this); -// errorCheckerThread = new Thread(errorCheckerService); -// try { -// errorCheckerThread.start(); -// } catch (Exception e) { -// Base.loge("Error Checker Service not initialized", e); -// } -// } -// } - - public void setProblemList(List problems) { this.problems = problems; boolean hasErrors = problems.stream().anyMatch(Problem::isError); @@ -2566,7 +2459,7 @@ public class JavaEditor extends Editor { for (Problem p : problems) { String message = p.getMessage(); - if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF) && + if (JavaMode.importSuggestEnabled && p.getImportSuggestions() != null && p.getImportSuggestions().length > 0) { message += " (double-click for suggestions)"; @@ -2616,19 +2509,17 @@ public class JavaEditor extends Editor { * line or not */ public void updateEditorStatus() { - if (JavaMode.errorCheckEnabled) { - Problem problem = findError(textarea.getCaretLine()); - if (problem != null) { - int type = problem.isError() ? - EditorStatus.CURSOR_LINE_ERROR : EditorStatus.CURSOR_LINE_WARNING; - statusMessage(problem.getMessage(), type); - } else { - switch (getStatusMode()) { - case EditorStatus.CURSOR_LINE_ERROR: - case EditorStatus.CURSOR_LINE_WARNING: - statusEmpty(); - break; - } + Problem problem = findError(textarea.getCaretLine()); + if (problem != null) { + int type = problem.isError() ? + EditorStatus.CURSOR_LINE_ERROR : EditorStatus.CURSOR_LINE_WARNING; + statusMessage(problem.getMessage(), type); + } else { + switch (getStatusMode()) { + case EditorStatus.CURSOR_LINE_ERROR: + case EditorStatus.CURSOR_LINE_WARNING: + statusEmpty(); + break; } } } @@ -2797,16 +2688,13 @@ public class JavaEditor extends Editor { * the error button at the bottom of the PDE */ public void updateErrorToggle(boolean hasErrors) { - footer.setNotification(errorTable.getParent(), //errorTableScrollPane, - JavaMode.errorCheckEnabled && - hasErrors); + footer.setNotification(errorTable.getParent(), hasErrors); // String title = Language.text("editor.footer.errors"); -// if (JavaMode.errorCheckEnabled && errorCheckerService.hasErrors()) { +// if (hasErrors) { // title += "*"; // } // ((JTabbedPane) footer).setTitleAt(ERROR_TAB_INDEX, title); -//// btnShowErrors.updateMarker(JavaMode.errorCheckEnabled && -//// errorCheckerService.hasErrors(), +//// btnShowErrors.updateMarker(hasErrors, //// errorBar.errorColor); } @@ -2875,8 +2763,7 @@ public class JavaEditor extends Editor { jmode.loadPreferences(); Messages.log("Applying prefs"); // trigger it once to refresh UI - errorCheckerService.handlePreferencesChange(); - setProblemList(Collections.emptyList()); + sketchChanged(); } } diff --git a/java/src/processing/mode/java/JavaMode.java b/java/src/processing/mode/java/JavaMode.java index ed9d4e3e3..d15348c24 100644 --- a/java/src/processing/mode/java/JavaMode.java +++ b/java/src/processing/mode/java/JavaMode.java @@ -117,33 +117,6 @@ public class JavaMode extends Mode { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - /* - public Runner handleRun(Sketch sketch, - RunnerListener listener) throws SketchException { - final JavaEditor editor = (JavaEditor) listener; - editor.errorCheckerService.quickErrorCheck(); -// if (enableTweak) { -// enableTweak = false; -// return handleTweak(sketch, listener, false); -// } else { - return handleLaunch(sketch, listener, false); -// } - } - - - public Runner handlePresent(Sketch sketch, - RunnerListener listener) throws SketchException { - final JavaEditor editor = (JavaEditor) listener; - editor.errorCheckerService.quickErrorCheck(); -// if (enableTweak) { -// enableTweak = false; -// return handleTweak(sketch, listener, true); -// } else { - return handleLaunch(sketch, listener, true); -// } - } - */ - /** Handles the standard Java "Run" or "Present" */ public Runner handleLaunch(Sketch sketch, RunnerListener listener, @@ -174,7 +147,6 @@ public class JavaMode extends Mode { RunnerListener listener) throws SketchException { // final boolean present) throws SketchException { final JavaEditor editor = (JavaEditor) listener; -// editor.errorCheckerService.quickErrorCheck(); // done in prepareRun() if (isSketchModified(sketch)) { editor.deactivateRun(); @@ -334,7 +306,7 @@ public class JavaMode extends Mode { // } - static public volatile boolean errorCheckEnabled = true; +// static public volatile boolean errorCheckEnabled = true; static public volatile boolean warningsEnabled = true; static public volatile boolean codeCompletionsEnabled = true; static public volatile boolean debugOutputEnabled = false; @@ -343,7 +315,7 @@ public class JavaMode extends Mode { static public volatile boolean autoSavePromptEnabled = true; static public volatile boolean defaultAutoSaveEnabled = true; static public volatile boolean ccTriggerEnabled = false; -// static public volatile boolean importSuggestEnabled = true; + static public volatile boolean importSuggestEnabled = true; static public int autoSaveInterval = 3; //in minutes @@ -352,7 +324,7 @@ public class JavaMode extends Mode { */ volatile public static int codeCompletionTriggerLength = 1; - static public final String prefErrorCheck = "pdex.errorCheckEnabled"; +// static public final String prefErrorCheck = "pdex.errorCheckEnabled"; static public final String prefWarnings = "pdex.warningsEnabled"; static public final String prefDebugOP = "pdex.dbgOutput"; static public final String prefErrorLogs = "pdex.writeErrorLogs"; @@ -377,7 +349,7 @@ public class JavaMode extends Mode { public void loadPreferences() { Messages.log("Load PDEX prefs"); ensurePrefsExist(); - errorCheckEnabled = Preferences.getBoolean(prefErrorCheck); +// errorCheckEnabled = Preferences.getBoolean(prefErrorCheck); warningsEnabled = Preferences.getBoolean(prefWarnings); codeCompletionsEnabled = Preferences.getBoolean(COMPLETION_PREF); // DEBUG = Preferences.getBoolean(prefDebugOP); @@ -388,14 +360,14 @@ public class JavaMode extends Mode { autoSavePromptEnabled = Preferences.getBoolean(prefAutoSavePrompt); defaultAutoSaveEnabled = Preferences.getBoolean(prefDefaultAutoSave); ccTriggerEnabled = Preferences.getBoolean(COMPLETION_TRIGGER_PREF); -// importSuggestEnabled = Preferences.getBoolean(prefImportSuggestEnabled); + importSuggestEnabled = Preferences.getBoolean(SUGGEST_IMPORTS_PREF); loadSuggestionsMap(); } public void savePreferences() { Messages.log("Saving PDEX prefs"); - Preferences.setBoolean(prefErrorCheck, errorCheckEnabled); +// Preferences.setBoolean(prefErrorCheck, errorCheckEnabled); Preferences.setBoolean(prefWarnings, warningsEnabled); Preferences.setBoolean(COMPLETION_PREF, codeCompletionsEnabled); // Preferences.setBoolean(prefDebugOP, DEBUG); @@ -406,7 +378,7 @@ public class JavaMode extends Mode { Preferences.setBoolean(prefAutoSavePrompt, autoSavePromptEnabled); Preferences.setBoolean(prefDefaultAutoSave, defaultAutoSaveEnabled); Preferences.setBoolean(COMPLETION_TRIGGER_PREF, ccTriggerEnabled); -// Preferences.setBoolean(prefImportSuggestEnabled, importSuggestEnabled); + Preferences.setBoolean(SUGGEST_IMPORTS_PREF, importSuggestEnabled); } public void loadSuggestionsMap() { @@ -453,8 +425,8 @@ public class JavaMode extends Mode { public void ensurePrefsExist() { //TODO: Need to do a better job of managing prefs. Think lists. - if (Preferences.get(prefErrorCheck) == null) - Preferences.setBoolean(prefErrorCheck, errorCheckEnabled); +// if (Preferences.get(prefErrorCheck) == null) +// Preferences.setBoolean(prefErrorCheck, errorCheckEnabled); if (Preferences.get(prefWarnings) == null) Preferences.setBoolean(prefWarnings, warningsEnabled); if (Preferences.get(COMPLETION_PREF) == null) @@ -475,8 +447,8 @@ public class JavaMode extends Mode { Preferences.setBoolean(prefDefaultAutoSave, defaultAutoSaveEnabled); if (Preferences.get(COMPLETION_TRIGGER_PREF) == null) Preferences.setBoolean(COMPLETION_TRIGGER_PREF, ccTriggerEnabled); -// if (Preferences.get(prefImportSuggestEnabled) == null) -// Preferences.setBoolean(prefImportSuggestEnabled, importSuggestEnabled); + if (Preferences.get(SUGGEST_IMPORTS_PREF) == null) + Preferences.setBoolean(SUGGEST_IMPORTS_PREF, importSuggestEnabled); } diff --git a/java/src/processing/mode/java/pdex/CompletionGenerator.java b/java/src/processing/mode/java/pdex/CompletionGenerator.java index 364e786fe..6ccc639d5 100644 --- a/java/src/processing/mode/java/pdex/CompletionGenerator.java +++ b/java/src/processing/mode/java/pdex/CompletionGenerator.java @@ -61,6 +61,7 @@ import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import processing.app.Messages; +import processing.mode.java.JavaMode; import com.google.classpath.ClassPath; import com.google.classpath.RegExpResourceFilter; @@ -687,8 +688,6 @@ public class CompletionGenerator { return null; } - //PreprocessedSketch ps = ecs.requestResult(); - if (className.indexOf('.') >= 0) { // Figure out what is package and what is class String[] parts = className.split("\\."); @@ -1319,6 +1318,41 @@ public class CompletionGenerator { } + protected static boolean ignorableSuggestionImport(PreprocessedSketch ps, String impName) { + + String impNameLc = impName.toLowerCase(); + + List programImports = ps.programImports; + List codeFolderImports = ps.codeFolderImports; + + boolean isImported = Stream + .concat(programImports.stream(), codeFolderImports.stream()) + .anyMatch(impS -> { + String packageNameLc = impS.getPackageName().toLowerCase(); + return impNameLc.startsWith(packageNameLc); + }); + + if (isImported) return false; + + final String include = "include"; + final String exclude = "exclude"; + + if (impName.startsWith("processing")) { + if (JavaMode.suggestionsMap.containsKey(include) && JavaMode.suggestionsMap.get(include).contains(impName)) { + return false; + } else if (JavaMode.suggestionsMap.containsKey(exclude) && JavaMode.suggestionsMap.get(exclude).contains(impName)) { + return true; + } + } else if (impName.startsWith("java")) { + if (JavaMode.suggestionsMap.containsKey(include) && JavaMode.suggestionsMap.get(include).contains(impName)) { + return false; + } + } + + return true; + } + + /** * A wrapper for java.lang.reflect types. * Will have to see if the usage turns out to be internal only here or not @@ -1850,7 +1884,7 @@ public class CompletionGenerator { matchedClass2 = matchedClass2.replace('/', '.'); //package name String matchedClass = matchedClass2.substring(0, matchedClass2.length() - 6); int d = matchedClass.lastIndexOf('.'); - if (!ErrorCheckerService.ignorableSuggestionImport(ps, matchedClass)) { + if (!ignorableSuggestionImport(ps, matchedClass)) { matchedClass = matchedClass.substring(d + 1); //class name // display package name in grey String html = "" + matchedClass + " : " + diff --git a/java/src/processing/mode/java/pdex/JavaTextArea.java b/java/src/processing/mode/java/pdex/JavaTextArea.java index 9ef3f6d2e..09ba709f3 100644 --- a/java/src/processing/mode/java/pdex/JavaTextArea.java +++ b/java/src/processing/mode/java/pdex/JavaTextArea.java @@ -322,7 +322,7 @@ public class JavaTextArea extends JEditTextArea { int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); int lineStartOffset = editor.getTextArea().getLineStartOffset(caretLineIndex); - editor.getErrorChecker().acceptWhenDone(ps -> { + editor.getPreprocessingService().whenDone(ps -> { int lineNumber = ps.tabOffsetToJavaLine(codeIndex, lineStartOffset); String phrase = null; diff --git a/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java b/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java index 286b9a79a..4d891893b 100644 --- a/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java +++ b/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java @@ -342,7 +342,7 @@ public class JavaTextAreaPainter extends TextAreaPainter /** - * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) + * Loads theme for TextAreaPainter(XQMode) */ public void setMode(Mode mode) { errorUnderlineColor = mode.getColor("editor.error.underline.color"); @@ -385,96 +385,6 @@ public class JavaTextAreaPainter extends TextAreaPainter } - /* - @Override - public String getToolTipText(MouseEvent event) { - if (!getJavaEditor().hasJavaTabs()) { - int off = textArea.xyToOffset(event.getX(), event.getY()); - if (off < 0) { - setToolTipText(null); - return super.getToolTipText(event); - } - int line = textArea.getLineOfOffset(off); - if (line < 0) { - setToolTipText(null); - return super.getToolTipText(event); - } - - String s = textArea.getLineText(line); - if (s == null || s.isEmpty()) { - setToolTipText(null); - return super.getToolTipText(event); - - } else { - int x = textArea.xToOffset(line, event.getX()), x2 = x + 1, x1 = x - 1; - int xLS = off - textArea.getLineStartNonWhiteSpaceOffset(line); - if (x < 0 || x >= s.length()) { - setToolTipText(null); - return super.getToolTipText(event); - } - String word = s.charAt(x) + ""; - if (s.charAt(x) == ' ') { - setToolTipText(null); - return super.getToolTipText(event); - } - if (!(Character.isLetterOrDigit(s.charAt(x)) || - s.charAt(x) == '_' || s.charAt(x) == '$' || s.charAt(x) == '{' || - s.charAt(x) == '}')) { - setToolTipText(null); - return super.getToolTipText(event); - } - int i = 0; - while (true) { - i++; - if (x1 >= 0 && x1 < s.length()) { - if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { - word = s.charAt(x1--) + word; - xLS--; - } else - x1 = -1; - } else - x1 = -1; - - if (x2 >= 0 && x2 < s.length()) { - if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' - || s.charAt(x2) == '$') - word = word + s.charAt(x2++); - else - x2 = -1; - } else - x2 = -1; - - if (x1 < 0 && x2 < 0) - break; - if (i > 200) { - // time out! - // System.err.println("Whoopsy! :P"); - break; - } - } - if (Character.isDigit(word.charAt(0))) { - setToolTipText(null); - return super.getToolTipText(event); - } - ASTGenerator ast = getJavaEditor().getErrorChecker().getASTGenerator(); - synchronized (ast) { - String tooltipText = ast.getLabelForASTNode(line, word, xLS); - - // log(errorCheckerService.mainClassOffset + " MCO " - // + "|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); - if (tooltipText != null) { - return tooltipText; - } - } - } - } - // Used when there are Java tabs, but also the fall-through case from above -// setToolTipText(null); - return super.getToolTipText(event); - } - */ - - // TweakMode code protected int horizontalAdjustment = 0; diff --git a/java/src/processing/mode/java/pdex/PDEX.java b/java/src/processing/mode/java/pdex/PDEX.java index d9ac64668..1e9dae51a 100644 --- a/java/src/processing/mode/java/pdex/PDEX.java +++ b/java/src/processing/mode/java/pdex/PDEX.java @@ -1,5 +1,9 @@ package processing.mode.java.pdex; +import com.google.classpath.ClassPath; +import com.google.classpath.RegExpResourceFilter; + +import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; @@ -27,7 +31,12 @@ import java.util.Comparator; import java.util.Deque; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.swing.BorderFactory; @@ -48,10 +57,12 @@ import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; import processing.app.Messages; +import processing.app.Preferences; import processing.app.Sketch; import processing.app.ui.EditorStatus; import processing.app.ui.Toolkit; import processing.mode.java.JavaEditor; +import processing.mode.java.JavaMode; import processing.mode.java.pdex.PreprocessedSketch.SketchInterval; import static processing.mode.java.pdex.ASTUtils.*; @@ -62,24 +73,28 @@ public class PDEX { private boolean enabled = true; + private ErrorChecker errorChecker; + private ShowUsage showUsage; private Rename rename; private DebugTree debugTree; private JavaEditor editor; - private ErrorCheckerService ecs; + private PreprocessingService pps; - public PDEX(JavaEditor editor, ErrorCheckerService ecs) { + public PDEX(JavaEditor editor, PreprocessingService pps) { this.editor = editor; - this.ecs = ecs; + this.pps = pps; this.enabled = !editor.hasJavaTabs(); - showUsage = new ShowUsage(editor, ecs); + errorChecker = new ErrorChecker(editor, pps); + + showUsage = new ShowUsage(editor, pps); rename = new Rename(editor); if (SHOW_DEBUG_TREE) { - debugTree = new DebugTree(editor, ecs); + debugTree = new DebugTree(editor, pps); } } @@ -87,21 +102,21 @@ public class PDEX { public void handleShowUsage(int tabIndex, int startTabOffset, int stopTabOffset) { Messages.log("* handleShowUsage"); if (!enabled) return; // show usage disabled if java tabs - ecs.acceptWhenDone(ps -> showUsage.findUsageAndUpdateTree(ps, tabIndex, startTabOffset, stopTabOffset)); + pps.whenDone(ps -> showUsage.findUsageAndUpdateTree(ps, tabIndex, startTabOffset, stopTabOffset)); } public void handleRename(int tabIndex, int startTabOffset, int stopTabOffset) { Messages.log("* handleRename"); if (!enabled) return; // refactoring disabled w/ java tabs - ecs.acceptWhenDone(ps -> rename.handleRename(ps, tabIndex, startTabOffset, stopTabOffset)); + pps.whenDone(ps -> rename.handleRename(ps, tabIndex, startTabOffset, stopTabOffset)); } public void handleCtrlClick(int tabIndex, int offset) { Messages.log("* handleCtrlClick"); if (!enabled) return; // disabled w/ java tabs - ecs.acceptWhenDone(ps -> handleCtrlClick(ps, tabIndex, offset)); + pps.whenDone(ps -> handleCtrlClick(ps, tabIndex, offset)); } @@ -113,7 +128,13 @@ public class PDEX { } + public void notifySketchChanged() { + errorChecker.notifySketchChanged(); + } + + public void dispose() { + errorChecker.dispose(); showUsage.dispose(); rename.dispose(); if (debugTree != null) { @@ -178,16 +199,16 @@ public class PDEX { final JTree tree; final JavaEditor editor; - final ErrorCheckerService ecs; + final PreprocessingService pps; final Consumer reloadListener; IBinding binding; - ShowUsage(JavaEditor editor, ErrorCheckerService ecs) { + ShowUsage(JavaEditor editor, PreprocessingService pps) { this.editor = editor; - this.ecs = ecs; + this.pps = pps; reloadListener = this::reloadShowUsage; @@ -201,12 +222,12 @@ public class PDEX { // Delete references to ASTNodes so that whole AST can be GC'd binding = null; tree.setModel(null); - ecs.unregisterDoneListener(reloadListener); + pps.unregisterListener(reloadListener); } @Override public void componentShown(ComponentEvent e) { - ecs.registerDoneListener(reloadListener); + pps.registerListener(reloadListener); } }); window.setSize(300, 400); @@ -689,7 +710,7 @@ public class PDEX { final Consumer updateListener; - DebugTree(JavaEditor editor, ErrorCheckerService ecs) { + DebugTree(JavaEditor editor, PreprocessingService pps) { updateListener = this::buildAndUpdateTree; window = new JDialog(editor); @@ -713,7 +734,7 @@ public class PDEX { window.addComponentListener(new ComponentAdapter() { @Override public void componentHidden(ComponentEvent e) { - ecs.unregisterDoneListener(updateListener); + pps.unregisterListener(updateListener); tree.setModel(null); } }); @@ -723,8 +744,8 @@ public class PDEX { JScrollPane sp = new JScrollPane(); sp.setViewportView(tree); window.add(sp); - ecs.acceptWhenDone(updateListener); - ecs.registerDoneListener(updateListener); + pps.whenDone(updateListener); + pps.registerListener(updateListener); tree.addTreeSelectionListener(e -> { @@ -735,7 +756,7 @@ public class PDEX { (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (tnode.getUserObject() instanceof ASTNode) { ASTNode node = (ASTNode) tnode.getUserObject(); - ecs.acceptWhenDone(ps -> { + pps.whenDone(ps -> { SketchInterval si = ps.mapJavaToSketch(node); EventQueue.invokeLater(() -> { editor.highlight(si.tabIndex, si.startTabOffset, si.stopTabOffset); @@ -797,4 +818,134 @@ public class PDEX { } + + + private static class ErrorChecker { + + // Delay delivering error check result after last sketch change #2677 + private final static long DELAY_BEFORE_UPDATE = 650; + + private ScheduledExecutorService scheduler; + private volatile ScheduledFuture scheduledUiUpdate = null; + private volatile long nextUiUpdate = 0; + + private final Consumer errorHandlerListener = this::handleSketchProblems; + + private JavaEditor editor; + + + public ErrorChecker(JavaEditor editor, PreprocessingService pps) { + this.editor = editor; + scheduler = Executors.newSingleThreadScheduledExecutor(); + pps.registerListener(errorHandlerListener); + } + + + public void notifySketchChanged() { + nextUiUpdate = System.currentTimeMillis() + DELAY_BEFORE_UPDATE; + } + + + public void dispose() { + if (scheduler != null) { + scheduler.shutdownNow(); + } + } + + + private void handleSketchProblems(PreprocessedSketch ps) { + // Process problems + final List problems = ps.problems.stream() + // Filter Warnings if they are not enabled + .filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled)) + // Hide a useless error which is produced when a line ends with + // an identifier without a semicolon. "Missing a semicolon" is + // also produced and is preferred over this one. + // (Syntax error, insert ":: IdentifierOrNew" to complete Expression) + // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780 + .filter(iproblem -> !iproblem.getMessage() + .contains("Syntax error, insert \":: IdentifierOrNew\"")) + // Transform into our Problems + .map(iproblem -> { + int start = iproblem.getSourceStart(); + int stop = iproblem.getSourceEnd() + 1; // make it exclusive + SketchInterval in = ps.mapJavaToSketch(start, stop); + int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset); + Problem p = new Problem(iproblem, in.tabIndex, line); + p.setPDEOffsets(in.startTabOffset, in.stopTabOffset); + return p; + }) + .collect(Collectors.toList()); + + // Handle import suggestions + if (JavaMode.importSuggestEnabled) { + Map> undefinedTypeProblems = problems.stream() + // Get only problems with undefined types/names + .filter(p -> { + int id = p.getIProblem().getID(); + return id == IProblem.UndefinedType || + id == IProblem.UndefinedName || + id == IProblem.UnresolvedVariable; + }) + // Group problems by the missing type/name + .collect(Collectors.groupingBy(p -> p.getIProblem().getArguments()[0])); + + if (!undefinedTypeProblems.isEmpty()) { + final ClassPath cp = ps.searchClassPath; + + // Get suggestions for each missing type, update the problems + undefinedTypeProblems.entrySet().stream() + .forEach(entry -> { + String missingClass = entry.getKey(); + List affectedProblems = entry.getValue(); + String[] suggestions = getImportSuggestions(cp, missingClass); + affectedProblems.forEach(p -> p.setImportSuggestions(suggestions)); + }); + } + } + + if (scheduledUiUpdate != null) { + scheduledUiUpdate.cancel(true); + } + // Update UI after a delay. See #2677 + long delay = nextUiUpdate - System.currentTimeMillis(); + Runnable uiUpdater = () -> { + if (nextUiUpdate > 0 && System.currentTimeMillis() >= nextUiUpdate) { + EventQueue.invokeLater(() -> editor.setProblemList(problems)); + } + }; + scheduledUiUpdate = scheduler.schedule(uiUpdater, delay, + TimeUnit.MILLISECONDS); + } + + + public static String[] getImportSuggestions(ClassPath cp, String className) { + RegExpResourceFilter regf = new RegExpResourceFilter( + Pattern.compile(".*"), + Pattern.compile("(.*\\$)?" + className + "\\.class", + Pattern.CASE_INSENSITIVE)); + + String[] resources = cp.findResources("", regf); + return Arrays.stream(resources) + // remove ".class" suffix + .map(res -> res.substring(0, res.length() - 6)) + // replace path separators with dots + .map(res -> res.replace('/', '.')) + // replace inner class separators with dots + .map(res -> res.replace('$', '.')) + // sort, prioritize clases from java. package + .sorted((o1, o2) -> { + // put java.* first, should be prioritized more + boolean o1StartsWithJava = o1.startsWith("java"); + boolean o2StartsWithJava = o2.startsWith("java"); + if (o1StartsWithJava != o2StartsWithJava) { + if (o1StartsWithJava) return -1; + return 1; + } + return o1.compareTo(o2); + }) + .toArray(String[]::new); + } + + } } diff --git a/java/src/processing/mode/java/pdex/ErrorCheckerService.java b/java/src/processing/mode/java/pdex/PreprocessingService.java similarity index 66% rename from java/src/processing/mode/java/pdex/ErrorCheckerService.java rename to java/src/processing/mode/java/pdex/PreprocessingService.java index df5c0e764..34da90203 100644 --- a/java/src/processing/mode/java/pdex/ErrorCheckerService.java +++ b/java/src/processing/mode/java/pdex/PreprocessingService.java @@ -20,11 +20,8 @@ along with this program; if not, write to the Free Software Foundation, Inc. package processing.mode.java.pdex; -import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; -import com.google.classpath.RegExpResourceFilter; -import java.awt.EventQueue; import java.io.File; import java.net.MalformedURLException; import java.net.URL; @@ -41,21 +38,12 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; -import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.stream.Stream; import java.util.stream.StreamSupport; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; -import javax.swing.text.Document; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -65,7 +53,6 @@ import org.eclipse.jdt.core.dom.CompilationUnit; import processing.app.Library; import processing.app.Messages; -import processing.app.Preferences; import processing.app.Sketch; import processing.app.SketchCode; import processing.app.SketchException; @@ -74,7 +61,6 @@ import processing.data.IntList; import processing.data.StringList; import processing.mode.java.JavaEditor; import processing.mode.java.JavaMode; -import processing.mode.java.pdex.PreprocessedSketch.SketchInterval; import processing.mode.java.pdex.TextTransform.OffsetMapper; import processing.mode.java.preproc.PdePreprocessor; import processing.mode.java.preproc.PdePreprocessor.Mode; @@ -84,39 +70,23 @@ import processing.mode.java.preproc.PdePreprocessor.Mode; * The main error checking service */ @SuppressWarnings("unchecked") -public class ErrorCheckerService { +public class PreprocessingService { protected final JavaEditor editor; - /** The amazing eclipse ast parser */ protected final ASTParser parser = ASTParser.newParser(AST.JLS8); - /** Class path factory for ASTGenerator */ - protected final ClassPathFactory classPathFactory = new ClassPathFactory(); + private final ClassPathFactory classPathFactory = new ClassPathFactory(); - /** - * Used to indirectly stop the Error Checker Thread - */ - private volatile boolean running; - - /** - * Error checking doesn't happen before this interval has ellapsed since the - * last request() call. - */ - private final static long errorCheckInterval = 650; - - private Thread errorCheckerThread; + private final Thread preprocessingThread; private final BlockingQueue requestQueue = new ArrayBlockingQueue<>(1); - private ScheduledExecutorService scheduler; - private volatile ScheduledFuture scheduledUiUpdate = null; - private volatile long nextUiUpdate = 0; private final Object requestLock = new Object(); - private boolean needsCheck = false; - private AtomicBoolean codeFolderChanged = new AtomicBoolean(true); - private AtomicBoolean librariesChanged = new AtomicBoolean(true); + private final AtomicBoolean codeFolderChanged = new AtomicBoolean(true); + private final AtomicBoolean librariesChanged = new AtomicBoolean(true); + private volatile boolean running; private CompletableFuture preprocessingTask = new CompletableFuture<>(); private CompletableFuture lastCallback = @@ -124,75 +94,58 @@ public class ErrorCheckerService { complete(null); // initialization block }}; - private final Consumer errorHandlerListener = this::handleSketchProblems; - private volatile boolean isEnabled = true; - private volatile boolean isContinuousCheckEnabled = true; - public ErrorCheckerService(JavaEditor editor) { + public PreprocessingService(JavaEditor editor) { this.editor = editor; isEnabled = !editor.hasJavaTabs(); - isContinuousCheckEnabled = JavaMode.errorCheckEnabled; - registerDoneListener(errorHandlerListener); + + preprocessingThread = new Thread(this::mainLoop, "ECS"); + preprocessingThread.start(); } private void mainLoop() { running = true; PreprocessedSketch prevResult = null; + Messages.log("PPS: Hi!"); while (running) { try { try { - requestQueue.take(); // blocking until check requested + requestQueue.take(); // blocking until requested } catch (InterruptedException e) { running = false; break; } - Messages.log("Starting preprocessing"); + Messages.log("PPS: Starting"); prevResult = preprocessSketch(prevResult); synchronized (requestLock) { if (requestQueue.isEmpty()) { - Messages.log("Completing preprocessing"); + Messages.log("PPS: Completed"); preprocessingTask.complete(prevResult); } } } catch (Exception e) { - Messages.loge("problem in error checker loop", e); + Messages.loge("problem in preprocessor service loop", e); } } + Messages.log("PPS: Bye!"); } - public void start() { - scheduler = Executors.newSingleThreadScheduledExecutor(); - errorCheckerThread = new Thread(this::mainLoop, "ECS"); - errorCheckerThread.start(); - } - - - public void stop() { + public void dispose() { cancel(); running = false; - if (errorCheckerThread != null) { - running = false; - errorCheckerThread.interrupt(); - } - if (scheduler != null) { - scheduler.shutdownNow(); - } + preprocessingThread.interrupt(); } public void cancel() { requestQueue.clear(); - nextUiUpdate = 0; - if (scheduledUiUpdate != null) { - scheduledUiUpdate.cancel(true); - } } @@ -202,35 +155,28 @@ public class ErrorCheckerService { if (preprocessingTask.isDone()) { preprocessingTask = new CompletableFuture<>(); // Register callback which executes all listeners - registerCallback(this::fireDoneListeners); - } - if (isContinuousCheckEnabled) { - // Continuous check enabled, request - nextUiUpdate = System.currentTimeMillis() + errorCheckInterval; - requestQueue.offer(Boolean.TRUE); - } else { - // Continuous check not enabled, take note - needsCheck = true; + whenDone(this::fireListeners); } + requestQueue.offer(Boolean.TRUE); } } public void notifyLibrariesChanged() { + Messages.log("PPS: notified libraries changed"); librariesChanged.set(true); - Messages.log("Notify libraries changed"); notifySketchChanged(); } public void notifyCodeFolderChanged() { + Messages.log("PPS: snotified code folder changed"); codeFolderChanged.set(true); - Messages.log("Notify code folder changed"); notifySketchChanged(); } - private void registerCallback(Consumer callback) { + public void whenDone(Consumer callback) { if (!isEnabled) return; synchronized (requestLock) { lastCallback = preprocessingTask @@ -238,49 +184,36 @@ public class ErrorCheckerService { .thenAcceptBothAsync(lastCallback, (ps, a) -> callback.accept(ps)) // Make sure exception in callback won't cancel whole callback chain .handleAsync((res, e) -> { - if (e != null) Messages.loge("problem during preprocessing callback", e); + if (e != null) Messages.loge("exception in preprocessing callback", e); return res; }); } } - 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 ---------------------------------------------------------------- - private Set> doneListeners = new CopyOnWriteArraySet<>(); + private Set> listeners = new CopyOnWriteArraySet<>(); - public void registerDoneListener(Consumer listener) { - if (listener != null) doneListeners.add(listener); + public void registerListener(Consumer listener) { + if (listener != null) listeners.add(listener); } - public void unregisterDoneListener(Consumer listener) { - doneListeners.remove(listener); + public void unregisterListener(Consumer listener) { + listeners.remove(listener); } - private void fireDoneListeners(PreprocessedSketch ps) { - for (Consumer listener : doneListeners) { + private void fireListeners(PreprocessedSketch ps) { + for (Consumer listener : listeners) { try { listener.accept(ps); } catch (Exception e) { - Messages.loge("error when firing ecs listener", e); + Messages.loge("error when firing preprocessing listener", e); } } } @@ -289,30 +222,6 @@ public class ErrorCheckerService { /// -------------------------------------------------------------------------- - - public void addDocumentListener(Document doc) { - if (doc != null) doc.addDocumentListener(sketchChangedListener); - } - - - protected final DocumentListener sketchChangedListener = new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - notifySketchChanged(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - notifySketchChanged(); - } - - @Override - public void changedUpdate(DocumentEvent e) { - notifySketchChanged(); - } - }; - - private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) { boolean firstCheck = prevResult == null; @@ -505,77 +414,6 @@ public class ErrorCheckerService { } - private void handleSketchProblems(PreprocessedSketch ps) { - // Process problems - final List problems = ps.problems.stream() - // Filter Warnings if they are not enabled - .filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled)) - // Hide a useless error which is produced when a line ends with - // an identifier without a semicolon. "Missing a semicolon" is - // also produced and is preferred over this one. - // (Syntax error, insert ":: IdentifierOrNew" to complete Expression) - // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780 - .filter(iproblem -> !iproblem.getMessage() - .contains("Syntax error, insert \":: IdentifierOrNew\"")) - // Transform into our Problems - .map(iproblem -> { - int start = iproblem.getSourceStart(); - int stop = iproblem.getSourceEnd() + 1; // make it exclusive - SketchInterval in = ps.mapJavaToSketch(start, stop); - int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset); - Problem p = new Problem(iproblem, in.tabIndex, line); - p.setPDEOffsets(in.startTabOffset, in.stopTabOffset); - return p; - }) - .collect(Collectors.toList()); - - // Handle import suggestions - if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF)) { - Map> undefinedTypeProblems = problems.stream() - // Get only problems with undefined types/names - .filter(p -> { - int id = p.getIProblem().getID(); - return id == IProblem.UndefinedType || - id == IProblem.UndefinedName || - id == IProblem.UnresolvedVariable; - }) - // Group problems by the missing type/name - .collect(Collectors.groupingBy(p -> p.getIProblem().getArguments()[0])); - - if (!undefinedTypeProblems.isEmpty()) { - final ClassPath cp = ps.searchClassPath; - - // Get suggestions for each missing type, update the problems - undefinedTypeProblems.entrySet().stream() - .forEach(entry -> { - String missingClass = entry.getKey(); - List affectedProblems = entry.getValue(); - String[] suggestions = getImportSuggestions(cp, missingClass); - affectedProblems.forEach(p -> p.setImportSuggestions(suggestions)); - }); - } - } - - if (scheduledUiUpdate != null) { - scheduledUiUpdate.cancel(true); - } - // Update UI after a delay. See #2677 - long delay = nextUiUpdate - System.currentTimeMillis(); - Runnable uiUpdater = () -> { - if (nextUiUpdate > 0 && System.currentTimeMillis() >= nextUiUpdate) { - EventQueue.invokeLater(() -> { - if (isContinuousCheckEnabled) { - editor.setProblemList(problems); - } - }); - } - }; - scheduledUiUpdate = scheduler.schedule(uiUpdater, delay, - TimeUnit.MILLISECONDS); - } - - - /// IMPORTS ----------------------------------------------------------------- private List coreAndDefaultImports; @@ -608,6 +446,22 @@ public class ErrorCheckerService { } + private static boolean checkIfImportsChanged(List prevImports, + List imports) { + if (imports.size() != prevImports.size()) { + return true; + } else { + int count = imports.size(); + for (int i = 0; i < count; i++) { + if (!imports.get(i).isSameAs(prevImports.get(i))) { + return true; + } + } + } + return false; + } + + /// CLASSPATHS --------------------------------------------------------------- @@ -621,8 +475,8 @@ public class ErrorCheckerService { private List codeFolderClassPath; - private List searchLibraryClassPath; private List sketchLibraryClassPath; + private List searchLibraryClassPath; private static List buildCodeFolderClassPath(Sketch sketch) { @@ -670,6 +524,7 @@ public class ErrorCheckerService { return sanitizeClassPath(classPath.toString()); } + private static List buildSearchLibraryClassPath(JavaMode mode) { StringBuilder classPath = new StringBuilder(); @@ -735,36 +590,7 @@ public class ErrorCheckerService { - public static String[] getImportSuggestions(ClassPath cp, String className) { - RegExpResourceFilter regf = new RegExpResourceFilter( - Pattern.compile(".*"), - Pattern.compile("(.*\\$)?" + className + "\\.class", - Pattern.CASE_INSENSITIVE)); - - String[] resources = cp.findResources("", regf); - return Arrays.stream(resources) - // remove ".class" suffix - .map(res -> res.substring(0, res.length() - 6)) - // replace path separators with dots - .map(res -> res.replace('/', '.')) - // replace inner class separators with dots - .map(res -> res.replace('$', '.')) - // sort, prioritize clases from java. package - .sorted((o1, o2) -> { - // put java.* first, should be prioritized more - boolean o1StartsWithJava = o1.startsWith("java"); - boolean o2StartsWithJava = o2.startsWith("java"); - if (o1StartsWithJava != o2StartsWithJava) { - if (o1StartsWithJava) return -1; - return 1; - } - return o1.compareTo(o2); - }) - .toArray(String[]::new); - } - - - protected static CompilationUnit makeAST(ASTParser parser, + private static CompilationUnit makeAST(ASTParser parser, char[] source, Map options) { parser.setSource(source); @@ -776,7 +602,7 @@ public class ErrorCheckerService { } - protected static CompilationUnit makeASTWithBindings(ASTParser parser, + private static CompilationUnit makeASTWithBindings(ASTParser parser, char[] source, Map options, String className, @@ -796,47 +622,12 @@ public class ErrorCheckerService { /** * Ignore processing packages, java.*.*. etc. */ - protected boolean ignorableImport(String packageName) { + private boolean ignorableImport(String packageName) { return (packageName.startsWith("java.") || packageName.startsWith("javax.")); } - protected static boolean ignorableSuggestionImport(PreprocessedSketch ps, String impName) { - - String impNameLc = impName.toLowerCase(); - - List programImports = ps.programImports; - List codeFolderImports = ps.codeFolderImports; - - boolean isImported = Stream - .concat(programImports.stream(), codeFolderImports.stream()) - .anyMatch(impS -> { - String packageNameLc = impS.getPackageName().toLowerCase(); - return impNameLc.startsWith(packageNameLc); - }); - - if (isImported) return false; - - final String include = "include"; - final String exclude = "exclude"; - - if (impName.startsWith("processing")) { - if (JavaMode.suggestionsMap.containsKey(include) && JavaMode.suggestionsMap.get(include).contains(impName)) { - return false; - } else if (JavaMode.suggestionsMap.containsKey(exclude) && JavaMode.suggestionsMap.get(exclude).contains(impName)) { - return true; - } - } else if (impName.startsWith("java")) { - if (JavaMode.suggestionsMap.containsKey(include) && JavaMode.suggestionsMap.get(include).contains(impName)) { - return false; - } - } - - return true; - } - - static private final Map COMPILER_OPTIONS; static { Map compilerOptions = new HashMap<>(); @@ -879,37 +670,6 @@ public class ErrorCheckerService { } - /** - * Checks if import statements in the sketch have changed. If they have, - * compiler classpath needs to be updated. - */ - protected static boolean checkIfImportsChanged(List prevImports, - List imports) { - if (imports.size() != prevImports.size()) { - return true; - } else { - int count = imports.size(); - for (int i = 0; i < count; i++) { - if (!imports.get(i).isSameAs(prevImports.get(i))) { - return true; - } - } - } - return false; - } - - - 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."); - } - } - - public void handleHasJavaTabsChange(boolean hasJavaTabs) { isEnabled = !hasJavaTabs; if (isEnabled) {