/** * Retrieves the word on which the mouse pointer is present * * @param evt - the MouseEvent which triggered this method */ private String fetchPhrase(MouseEvent evt) { Messages.log("--handle Mouse Right Click--"); int off = xyToOffset(evt.getX(), evt.getY()); if (off < 0) return null; int line = getLineOfOffset(off); if (line < 0) return null; String s = getLineText(line); if (s == null) return null; else if (s.length() == 0) return null; else { int x = xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; int xLS = off - getLineStartNonWhiteSpaceOffset(line); Messages.log("x=" + x); if (x < 0 || x >= s.length()) return null; String word = s.charAt(x) + ""; if (s.charAt(x) == ' ') return null; if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s.charAt(x) == '$')) return null; 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! break; } } if (Character.isDigit(word.charAt(0))) { return null; } Messages.log("Mouse click, word: " + word.trim()); ASTGenerator astGenerator = editor.getErrorChecker().getASTGenerator(); synchronized (astGenerator) { astGenerator.setLastClickedWord(line, word, xLS); } return word.trim(); } }
/** * Calculates location of caret and displays the suggestion popup at the location. * * @param listModel * @param subWord */ protected void showSuggestion(DefaultListModel<CompletionCandidate> listModel, String subWord) { // new Exception(System.currentTimeMillis() + "").printStackTrace(System.out); hideSuggestion(); if (listModel.size() == 0) { Messages.log("TextArea: No suggestions to show."); } else { int position = getCaretPosition(); Point location = new Point(); try { location.x = offsetToX(getCaretLine(), position - getLineStartOffset(getCaretLine())); location.y = lineToY(getCaretLine()) + getPainter().getFontMetrics().getHeight() + getPainter().getFontMetrics().getDescent(); // log("TA position: " + location); } catch (Exception e2) { e2.printStackTrace(); return; } suggestion = new CompletionPanel(this, position, subWord, listModel, location, editor); requestFocusInWindow(); } }
/** Kickstart auto-complete suggestions */ private void prepareSuggestions(final KeyEvent evt) { // Provide completions only if it's enabled if (JavaMode.codeCompletionsEnabled && (JavaMode.ccTriggerEnabled || (suggestion != null && suggestion.isVisible()))) { Messages.log("[KeyEvent]" + evt.getKeyChar() + " |Prediction started"); fetchPhrase(); } }
private void processCompletionKeys(final KeyEvent event) { char keyChar = event.getKeyChar(); int keyCode = event.getKeyCode(); if (keyChar == KeyEvent.VK_ENTER || keyChar == KeyEvent.VK_ESCAPE || keyChar == KeyEvent.VK_TAB || (event.getID() == KeyEvent.KEY_RELEASED && keyCode != KeyEvent.VK_LEFT && keyCode != KeyEvent.VK_RIGHT)) { // ignore } else if (keyChar == ')') { // https://github.com/processing/processing/issues/2741 hideSuggestion(); } else if (keyChar == '.') { if (JavaMode.codeCompletionsEnabled) { Messages.log( "[KeyEvent]" + KeyEvent.getKeyText(event.getKeyCode()) + " |Prediction started"); fetchPhrase(); } } else if (keyChar == ' ') { // Trigger on Ctrl-Space if (!Platform.isMacOS() && JavaMode.codeCompletionsEnabled && (event.isControlDown() || event.isMetaDown())) { // Provide completions only if it's enabled if (JavaMode.codeCompletionsEnabled) { // Removed for https://github.com/processing/processing/issues/3847 // try { // getDocument().remove(getCaretPosition() - 1, 1); // Remove the typed space Messages.log("[KeyEvent]" + event.getKeyChar() + " |Prediction started"); fetchPhrase(); // } catch (BadLocationException e) { // e.printStackTrace(); // } } } else { hideSuggestion(); // hide on spacebar } } else { if (JavaMode.codeCompletionsEnabled) { prepareSuggestions(event); } } }
// Special case for OS X, where Ctrl-Space is not detected as KEY_TYPED // https://github.com/processing/processing/issues/2699 private void processControlSpace(final KeyEvent event) { if (event.getKeyCode() == KeyEvent.VK_SPACE && event.isControlDown()) { // Provide completions only if it's enabled if (JavaMode.codeCompletionsEnabled) { Messages.log( "[KeyEvent]" + KeyEvent.getKeyText(event.getKeyCode()) + " |Prediction started"); fetchPhrase(); } } }
public void loadSuggestionsMap() { File suggestionsListFile = new File(getFolder() + File.separator + suggestionsFileName); if (!suggestionsListFile.exists()) { Messages.loge("Suggestions file not found! " + suggestionsListFile.getAbsolutePath()); return; } try { BufferedReader br = new BufferedReader(new FileReader(suggestionsListFile)); while (true) { String line = br.readLine(); if (line == null) { break; } line = line.trim(); if (line.startsWith("#")) { continue; } else { if (line.contains("=")) { String key = line.split("=")[0]; String val = line.split("=")[1]; if (suggestionsMap.containsKey(key)) { suggestionsMap.get(key).add(val); } else { HashSet<String> set = new HashSet<>(); set.add(val); suggestionsMap.put(key, set); } } } } br.close(); } catch (IOException e) { Messages.loge( "IOException while reading suggestions file:" + suggestionsListFile.getAbsolutePath()); } }
public void savePreferences() { Messages.log("Saving PDEX prefs"); Preferences.setBoolean(prefErrorCheck, errorCheckEnabled); Preferences.setBoolean(prefWarnings, warningsEnabled); Preferences.setBoolean(prefCodeCompletionEnabled, codeCompletionsEnabled); // Preferences.setBoolean(prefDebugOP, DEBUG); Preferences.setBoolean(prefErrorLogs, errorLogsEnabled); Preferences.setInteger(prefAutoSaveInterval, autoSaveInterval); // Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); Preferences.setBoolean(prefAutoSave, autoSaveEnabled); Preferences.setBoolean(prefAutoSavePrompt, autoSavePromptEnabled); Preferences.setBoolean(prefDefaultAutoSave, defaultAutoSaveEnabled); Preferences.setBoolean(prefCCTriggerEnabled, ccTriggerEnabled); Preferences.setBoolean(prefImportSuggestEnabled, importSuggestEnabled); }
public void loadPreferences() { Messages.log("Load PDEX prefs"); ensurePrefsExist(); errorCheckEnabled = Preferences.getBoolean(prefErrorCheck); warningsEnabled = Preferences.getBoolean(prefWarnings); codeCompletionsEnabled = Preferences.getBoolean(prefCodeCompletionEnabled); // DEBUG = Preferences.getBoolean(prefDebugOP); errorLogsEnabled = Preferences.getBoolean(prefErrorLogs); autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval); // untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave); autoSaveEnabled = Preferences.getBoolean(prefAutoSave); autoSavePromptEnabled = Preferences.getBoolean(prefAutoSavePrompt); defaultAutoSaveEnabled = Preferences.getBoolean(prefDefaultAutoSave); ccTriggerEnabled = Preferences.getBoolean(prefCCTriggerEnabled); importSuggestEnabled = Preferences.getBoolean(prefImportSuggestEnabled); loadSuggestionsMap(); }
/** Build the sketch and run it on a device with the debugger connected. */ public void handleRunDevice() { if (Platform.isWindows() && !Preferences.getBoolean("usbDriverWarningShown")) { Preferences.setBoolean("usbDriverWarningShown", true); String message = ""; File usbDriverFile = new File( ((AndroidMode) sketch.getMode()).getSDK().getSdkFolder(), "extras/google/usb_driver"); if (usbDriverFile.exists()) { message = "<html><body>" + "You might need to install Google USB Driver to run the sketch on your device.<br>" + "Please follow the guide at <a href='http://developer.android.com/tools/extras/oem-usb.html#InstallingDriver'>http://developer.android.com/tools/extras/oem-usb.html#InstallingDriver</a> to install the driver.<br>" + "For your reference, the driver is located in: " + usbDriverFile.getAbsolutePath(); } else { message = "<html><body>" + "You might need to install Google USB Driver to run the sketch on your device.<br>" + "Please follow the guide at <a href='http://developer.android.com/tools/extras/oem-usb.html#InstallingDriver'>http://developer.android.com/tools/extras/oem-usb.html#InstallingDriver</a> to install the driver.<br>" + "You will also need to download the driver from <a href='http://developer.android.com/sdk/win-usb.html'>http://developer.android.com/sdk/win-usb.html</a>"; } Messages.showWarning("USB Driver warning", message); } else { new Thread() { public void run() { toolbar.activateRun(); // toolbar.activate(AndroidToolbar.RUN); startIndeterminate(); prepareRun(); try { androidMode.handleRunDevice(sketch, AndroidEditor.this); } catch (SketchException e) { statusError(e); } catch (IOException e) { statusError(e); } stopIndeterminate(); } }.start(); } }
protected static String parsePhrase(final String lineText) { boolean overloading = false; { // Check if we can provide suggestions for this phrase ending String trimmedLineText = lineText.trim(); if (trimmedLineText.length() == 0) return null; char lastChar = trimmedLineText.charAt(trimmedLineText.length() - 1); if (lastChar == '.') { trimmedLineText = trimmedLineText.substring(0, trimmedLineText.length() - 1).trim(); if (trimmedLineText.length() == 0) return null; lastChar = trimmedLineText.charAt(trimmedLineText.length() - 1); switch (lastChar) { case ')': case ']': case '"': break; // We can suggest for these default: if (!Character.isJavaIdentifierPart(lastChar)) { return null; // Not something we can suggest } break; } } else if (lastChar == '(') { overloading = true; // We can suggest overloaded methods } else if (!Character.isJavaIdentifierPart(lastChar)) { return null; // Not something we can suggest } } final int currentCharIndex = lineText.length() - 1; { // Check if the caret is in the comment int commentStart = lineText.indexOf("//", 0); if (commentStart >= 0 && currentCharIndex > commentStart) { return null; } } // Index the line BitSet isInLiteral = new BitSet(lineText.length()); BitSet isInBrackets = new BitSet(lineText.length()); { // Mark parts in literals boolean inString = false; boolean inChar = false; boolean inEscaped = false; for (int i = 0; i < lineText.length(); i++) { if (!inEscaped) { switch (lineText.charAt(i)) { case '\"': if (!inChar) inString = !inString; break; case '\'': if (!inString) inChar = !inChar; break; case '\\': if (inString || inChar) { inEscaped = true; } break; } } else { inEscaped = false; } isInLiteral.set(i, inString || inChar); } } if (isInLiteral.get(currentCharIndex)) return null; { // Mark parts in top level brackets int depth = overloading ? 1 : 0; int bracketStart = overloading ? lineText.length() : 0; int squareDepth = 0; int squareBracketStart = 0; bracketLoop: for (int i = lineText.length() - 1; i >= 0; i--) { if (!isInLiteral.get(i)) { switch (lineText.charAt(i)) { case ')': if (depth == 0) bracketStart = i; depth++; break; case '(': depth--; if (depth == 0) { isInBrackets.set(i, bracketStart); } else if (depth < 0) { break bracketLoop; } break; case ']': if (squareDepth == 0) squareBracketStart = i; squareDepth++; break; case '[': squareDepth--; if (squareDepth == 0) { isInBrackets.set(i, squareBracketStart); } else if (squareDepth < 0) { break bracketLoop; } break; } } } if (depth > 0) isInBrackets.set(0, bracketStart); if (squareDepth > 0) isInBrackets.set(0, squareBracketStart); } // Walk the line from the end while it makes sense int position = currentCharIndex; parseLoop: while (position >= 0) { int currChar = lineText.charAt(position); switch (currChar) { case '.': // Grab it position--; break; case '[': break parseLoop; // End of scope case ']': // Grab the whole region in square brackets position = isInBrackets.previousClearBit(position - 1); break; case '(': if (isInBrackets.get(position)) { position--; // This checks for first bracket while overloading break; } break parseLoop; // End of scope case ')': // Grab the whole region in brackets position = isInBrackets.previousClearBit(position - 1); break; case '"': // Grab the whole literal and quit position = isInLiteral.previousClearBit(position - 1); break parseLoop; default: if (Character.isJavaIdentifierPart(currChar)) { position--; // Grab the identifier } else if (Character.isWhitespace(currChar)) { position--; // Grab whitespace too } else { break parseLoop; // Got a char ending the phrase } break; } } position++; // Extract phrase String phrase = lineText.substring(position, lineText.length()).trim(); Messages.log(phrase); if (phrase.length() == 0 || Character.isDigit(phrase.charAt(0))) { return null; // Can't suggest for numbers or empty phrases } return phrase; }
/** Handles KeyEvents for TextArea (code completion begins from here). */ public void processKeyEvent(KeyEvent evt) { if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) { if (suggestion != null) { if (suggestion.isVisible()) { Messages.log("esc key"); hideSuggestion(); evt.consume(); return; } } } else if (evt.getKeyCode() == KeyEvent.VK_ENTER && evt.getID() == KeyEvent.KEY_PRESSED) { if (suggestion != null && suggestion.isVisible() && suggestion.insertSelection(CompletionPanel.KEYBOARD_COMPLETION)) { evt.consume(); // Still try to show suggestions after inserting if it's // the case of overloaded methods. See #2755 if (suggestion.isVisible()) { prepareSuggestions(evt); } return; } } if (evt.getID() == KeyEvent.KEY_PRESSED) { switch (evt.getKeyCode()) { case KeyEvent.VK_DOWN: if (suggestion != null) if (suggestion.isVisible()) { // log("KeyDown"); suggestion.moveDown(); return; } break; case KeyEvent.VK_UP: if (suggestion != null) if (suggestion.isVisible()) { // log("KeyUp"); suggestion.moveUp(); return; } break; case KeyEvent.VK_BACK_SPACE: Messages.log("BK Key"); break; case KeyEvent.VK_SPACE: if (suggestion != null) { if (suggestion.isVisible()) { Messages.log("Space bar, hide completion list"); suggestion.setInvisible(); } } break; } } super.processKeyEvent(evt); // code completion disabled if Java tabs present if (!editor.hasJavaTabs()) { if (evt.getID() == KeyEvent.KEY_TYPED) { processCompletionKeys(evt); } else if (!Platform.isMacOS() && evt.getID() == KeyEvent.KEY_RELEASED) { processCompletionKeys(evt); } else if (Platform.isMacOS() && evt.getID() == KeyEvent.KEY_RELEASED) { processControlSpace(evt); } } }
/** Start a sketch in tweak mode */ public Runner handleTweak(Sketch sketch, RunnerListener listener, final boolean present) throws SketchException { final JavaEditor editor = (JavaEditor) listener; if (isSketchModified(sketch)) { editor.deactivateRun(); Messages.showMessage( Language.text("menu.file.save"), Language.text("tweak_mode.save_before_tweak")); return null; } // first try to build the unmodified code JavaBuild build = new JavaBuild(sketch); // String appletClassName = build.build(false); String appletClassName = build.build(true); if (appletClassName == null) { // unmodified build failed, so fail return null; } // if compilation passed, modify the code and build again // save the original sketch code of the user editor.initBaseCode(); // check for "// tweak" comment in the sketch boolean requiresTweak = SketchParser.containsTweakComment(editor.baseCode); // parse the saved sketch to get all (or only with "//tweak" comment) numbers final SketchParser parser = new SketchParser(editor.baseCode, requiresTweak); // add our code to the sketch final boolean launchInteractive = editor.automateSketch(sketch, parser); build = new JavaBuild(sketch); appletClassName = build.build(false); if (appletClassName != null) { final Runner runtime = new Runner(build, listener); new Thread( new Runnable() { public void run() { // these block until finished if (present) { runtime.present(null); } else { runtime.launch(null); } // next lines are executed when the sketch quits if (launchInteractive) { editor.initEditorCode(parser.allHandles, false); editor.stopTweakMode(parser.allHandles); } } }) .start(); if (launchInteractive) { // replace editor code with baseCode editor.initEditorCode(parser.allHandles, false); editor.updateInterface(parser.allHandles, parser.colorBoxes); editor.startTweakMode(); } return runtime; } return null; }