@@ -902,7 +860,7 @@ public boolean addFile(File sourceFile) {
}
if (codeExtension != null) {
- SketchCode newCode = (new SketchCodeDocument(destFile)).getCode();
+ SketchCode newCode = (new SketchCodeDocument(this, destFile)).getCode();
if (replacement) {
data.replaceCode(newCode);
@@ -930,10 +888,6 @@ public boolean addFile(File sourceFile) {
}
- public void importLibrary(Library lib) throws IOException {
- importLibrary(lib.getSrcFolder());
- }
-
/**
* Add import statements to the current tab for all of packages inside
* the specified jar file.
@@ -941,7 +895,7 @@ public void importLibrary(Library lib) throws IOException {
public void importLibrary(File jarPath) throws IOException {
// make sure the user didn't hide the sketch folder
ensureExistence();
-
+
String list[] = Base.headerListFromIncludePath(jarPath);
// import statements into the main sketch file (code[0])
@@ -998,19 +952,6 @@ public void setCurrentCode(int which) {
}
- /**
- * Internal helper function to set the current tab based on a name.
- * @param findName the file name (not pretty name) to be shown
- */
- protected void setCurrentCode(String findName) {
- for (SketchCode code : data.getCodes()) {
- if (findName.equals(code.getFileName()) ||
- findName.equals(code.getPrettyName())) {
- setCurrentCode(data.indexOfCode(code));
- return;
- }
- }
- }
/**
@@ -1234,207 +1175,10 @@ protected boolean upload(String buildPath, String suggestedClassName, boolean us
}
- public boolean exportApplicationPrompt() throws IOException, RunnerException {
- return false;
- }
-
-
- /**
- * Export to application via GUI.
- */
- protected boolean exportApplication() throws IOException, RunnerException {
- return false;
- }
-
-
- /**
- * Export to application without GUI.
- */
- public boolean exportApplication(String destPath,
- int exportPlatform) throws IOException, RunnerException {
- return false;
- }
-
-
- /**
- * Make sure the sketch hasn't been moved or deleted by some
- * nefarious user. If they did, try to re-create it and save.
- * Only checks to see if the main folder is still around,
- * but not its contents.
- */
- protected void ensureExistence() {
- if (data.getFolder().exists()) return;
-
- Base.showWarning(_("Sketch Disappeared"),
- _("The sketch folder has disappeared.\n " +
- "Will attempt to re-save in the same location,\n" +
- "but anything besides the code will be lost."), null);
- try {
- data.getFolder().mkdirs();
- modified = true;
-
- for (SketchCode code : data.getCodes()) {
- code.save(); // this will force a save
- }
- calcModified();
-
- } catch (Exception e) {
- Base.showWarning(_("Could not re-save sketch"),
- _("Could not properly re-save the sketch. " +
- "You may be in trouble at this point,\n" +
- "and it might be time to copy and paste " +
- "your code to another text editor."), e);
- }
- }
-
-
- /**
- * Returns true if this is a read-only sketch. Used for the
- * examples directory, or when sketches are loaded from read-only
- * volumes or folders without appropriate permissions.
- */
- public boolean isReadOnly() {
- String apath = data.getFolder().getAbsolutePath();
- for (File folder : Base.getLibrariesPath()) {
- if (apath.startsWith(folder.getAbsolutePath()))
- return true;
- }
- if (apath.startsWith(Base.getExamplesPath()) ||
- apath.startsWith(Base.getSketchbookLibrariesPath())) {
- return true;
- }
-
- // canWrite() doesn't work on directories
- // } else if (!folder.canWrite()) {
-
- // check to see if each modified code file can be written to
- for (SketchCode code : data.getCodes()) {
- if (code.isModified() && code.fileReadOnly() && code.fileExists()) {
- // System.err.println("found a read-only file " + code[i].file);
- return true;
- }
- }
- return false;
- }
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- // Breaking out extension types in order to clean up the code, and make it
- // easier for other environments (like Arduino) to incorporate changes.
-
- /**
- * True if the specified code has the default file extension.
- */
- public boolean hasDefaultExtension(SketchCode code) {
- return code.isExtension(getDefaultExtension());
- }
-
-
- /**
- * True if the specified extension is the default file extension.
- */
- public boolean isDefaultExtension(String what) {
- return what.equals(getDefaultExtension());
- }
-
-
- /**
- * Check this extension (no dots, please) against the list of valid
- * extensions.
- */
- public boolean validExtension(String what) {
- return data.getExtensions().contains(what);
- }
-
-
- /**
- * Returns the default extension for this editor setup.
- */
- public String getDefaultExtension() {
- return data.getDefaultExtension();
- }
-
- static private List
- *
- * This class provides all the necessary support code for an input
- * handler, but doesn't actually do any key binding logic. It is up
- * to the implementations of this class to do so.
- *
- * @author Slava Pestov
- */
-public abstract class InputHandler extends KeyAdapter
-{
- /**
- * If this client property is set to Boolean.TRUE on the text area,
- * the home/end keys will support 'smart' BRIEF-like behaviour
- * (one press = start/end of line, two presses = start/end of
- * viewscreen, three presses = start/end of document). By default,
- * this property is not set.
- */
- public static final String SMART_HOME_END_PROPERTY = "InputHandler.homeEnd";
-
- public static final ActionListener BACKSPACE = new backspace();
- public static final ActionListener BACKSPACE_WORD = new backspace_word();
- public static final ActionListener DELETE = new delete();
- public static final ActionListener DELETE_WORD = new delete_word();
- public static final ActionListener END = new end(false);
- public static final ActionListener DOCUMENT_END = new document_end(false);
- public static final ActionListener SELECT_END = new end(true);
- public static final ActionListener SELECT_DOC_END = new document_end(true);
- public static final ActionListener INSERT_BREAK = new insert_break();
- public static final ActionListener INSERT_TAB = new insert_tab();
- public static final ActionListener HOME = new home(false);
- public static final ActionListener DOCUMENT_HOME = new document_home(false);
- public static final ActionListener SELECT_HOME = new home(true);
- public static final ActionListener SELECT_DOC_HOME = new document_home(true);
- public static final ActionListener NEXT_CHAR = new next_char(false);
- public static final ActionListener NEXT_LINE = new next_line(false);
- public static final ActionListener NEXT_PAGE = new next_page(false);
- public static final ActionListener NEXT_WORD = new next_word(false);
- public static final ActionListener SELECT_NEXT_CHAR = new next_char(true);
- public static final ActionListener SELECT_NEXT_LINE = new next_line(true);
- public static final ActionListener SELECT_NEXT_PAGE = new next_page(true);
- public static final ActionListener SELECT_NEXT_WORD = new next_word(true);
- public static final ActionListener OVERWRITE = new overwrite();
- public static final ActionListener PREV_CHAR = new prev_char(false);
- public static final ActionListener PREV_LINE = new prev_line(false);
- public static final ActionListener PREV_PAGE = new prev_page(false);
- public static final ActionListener PREV_WORD = new prev_word(false);
- public static final ActionListener SELECT_PREV_CHAR = new prev_char(true);
- public static final ActionListener SELECT_PREV_LINE = new prev_line(true);
- public static final ActionListener SELECT_PREV_PAGE = new prev_page(true);
- public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
- public static final ActionListener REPEAT = new repeat();
- public static final ActionListener TOGGLE_RECT = new toggle_rect();
- public static final ActionListener CLIPBOARD_CUT = new clipboard_cut(); // [fry]
- public static final ActionListener CLIPBOARD_COPY = new clipboard_copy();
- public static final ActionListener CLIPBOARD_PASTE = new clipboard_paste();
-
- // Default action
- public static final ActionListener INSERT_CHAR = new insert_char();
-
- private static Hashtable actions;
-
- static
- {
- actions = new Hashtable();
- actions.put("backspace",BACKSPACE);
- actions.put("backspace-word",BACKSPACE_WORD);
- actions.put("delete",DELETE);
- actions.put("delete-word",DELETE_WORD);
- actions.put("end",END);
- actions.put("select-end",SELECT_END);
- actions.put("document-end",DOCUMENT_END);
- actions.put("select-doc-end",SELECT_DOC_END);
- actions.put("insert-break",INSERT_BREAK);
- actions.put("insert-tab",INSERT_TAB);
- actions.put("home",HOME);
- actions.put("select-home",SELECT_HOME);
- actions.put("document-home",DOCUMENT_HOME);
- actions.put("select-doc-home",SELECT_DOC_HOME);
- actions.put("next-char",NEXT_CHAR);
- actions.put("next-line",NEXT_LINE);
- actions.put("next-page",NEXT_PAGE);
- actions.put("next-word",NEXT_WORD);
- actions.put("select-next-char",SELECT_NEXT_CHAR);
- actions.put("select-next-line",SELECT_NEXT_LINE);
- actions.put("select-next-page",SELECT_NEXT_PAGE);
- actions.put("select-next-word",SELECT_NEXT_WORD);
- actions.put("overwrite",OVERWRITE);
- actions.put("prev-char",PREV_CHAR);
- actions.put("prev-line",PREV_LINE);
- actions.put("prev-page",PREV_PAGE);
- actions.put("prev-word",PREV_WORD);
- actions.put("select-prev-char",SELECT_PREV_CHAR);
- actions.put("select-prev-line",SELECT_PREV_LINE);
- actions.put("select-prev-page",SELECT_PREV_PAGE);
- actions.put("select-prev-word",SELECT_PREV_WORD);
- actions.put("repeat",REPEAT);
- actions.put("toggle-rect",TOGGLE_RECT);
- actions.put("insert-char",INSERT_CHAR);
- actions.put("clipboard-cut",CLIPBOARD_CUT);
- actions.put("clipboard-copy",CLIPBOARD_COPY);
- actions.put("clipboard-paste",CLIPBOARD_PASTE);
- }
-
- /**
- * Returns a named text area action.
- * @param name The action name
- */
- public static ActionListener getAction(String name)
- {
- return (ActionListener)actions.get(name);
- }
-
- /**
- * Returns the name of the specified text area action.
- * @param listener The action
- */
- public static String getActionName(ActionListener listener)
- {
- Enumeration en = getActions();
- while(en.hasMoreElements())
- {
- String name = (String)en.nextElement();
- ActionListener _listener = getAction(name);
- if(_listener == listener) {
- return name;
- }
- }
- return null;
- }
-
- /**
- * Returns an enumeration of all available actions.
- */
- public static Enumeration getActions()
- {
- return actions.keys();
- }
-
- /**
- * Adds the default key bindings to this input handler.
- * This should not be called in the constructor of this
- * input handler, because applications might load the
- * key bindings from a file, etc.
- */
- public abstract void addDefaultKeyBindings();
-
- /**
- * Adds a key binding to this input handler.
- * @param keyBinding The key binding (the format of this is
- * input-handler specific)
- * @param action The action
- */
- public abstract void addKeyBinding(String keyBinding, ActionListener action);
-
- /**
- * Removes a key binding from this input handler.
- * @param keyBinding The key binding
- */
- public abstract void removeKeyBinding(String keyBinding);
-
- /**
- * Removes all key bindings from this input handler.
- */
- public abstract void removeAllKeyBindings();
-
- /**
- * Grabs the next key typed event and invokes the specified
- * action with the key as a the action command.
- */
- public void grabNextKeyStroke(ActionListener listener)
- {
- grabAction = listener;
- }
-
- /**
- * Returns if repeating is enabled. When repeating is enabled,
- * actions will be executed multiple times. This is usually
- * invoked with a special key stroke in the input handler.
- */
- public boolean isRepeatEnabled()
- {
- return repeat;
- }
-
- /**
- * Enables repeating. When repeating is enabled, actions will be
- * executed multiple times. Once repeating is enabled, the input
- * handler should read a number from the keyboard.
- */
- public void setRepeatEnabled(boolean repeat)
- {
- this.repeat = repeat;
- }
-
- /**
- * Returns the number of times the next action will be repeated.
- */
- public int getRepeatCount()
- {
- return (repeat ? Math.max(1,repeatCount) : 1);
- }
-
- /**
- * Sets the number of times the next action will be repeated.
- * @param repeatCount The repeat count
- */
- public void setRepeatCount(int repeatCount)
- {
- this.repeatCount = repeatCount;
- }
-
- /**
- * Returns the macro recorder. If this is non-null, all executed
- * actions should be forwarded to the recorder.
- */
- public InputHandler.MacroRecorder getMacroRecorder()
- {
- return recorder;
- }
-
- /**
- * Sets the macro recorder. If this is non-null, all executed
- * actions should be forwarded to the recorder.
- * @param recorder The macro recorder
- */
- public void setMacroRecorder(InputHandler.MacroRecorder recorder)
- {
- this.recorder = recorder;
- }
-
- /**
- * Returns a copy of this input handler that shares the same
- * key bindings. Setting key bindings in the copy will also
- * set them in the original.
- */
- public abstract InputHandler copy();
-
- /**
- * Executes the specified action, repeating and recording it as
- * necessary.
- * @param listener The action listener
- * @param source The event source
- * @param actionCommand The action command
- */
- public void executeAction(ActionListener listener, Object source,
- String actionCommand)
- {
- // create event
- ActionEvent evt = new ActionEvent(source,
- ActionEvent.ACTION_PERFORMED,
- actionCommand);
-
- // don't do anything if the action is a wrapper
- // (like EditAction.Wrapper)
- if(listener instanceof Wrapper)
- {
- listener.actionPerformed(evt);
- return;
- }
-
- // remember old values, in case action changes them
- boolean _repeat = repeat;
- int _repeatCount = getRepeatCount();
-
- // execute the action
- if(listener instanceof InputHandler.NonRepeatable)
- listener.actionPerformed(evt);
- else
- {
- for(int i = 0; i < Math.max(1,repeatCount); i++)
- listener.actionPerformed(evt);
- }
-
- // do recording. Notice that we do no recording whatsoever
- // for actions that grab keys
- if(grabAction == null)
- {
- if(recorder != null)
- {
- if(!(listener instanceof InputHandler.NonRecordable))
- {
- if(_repeatCount != 1)
- recorder.actionPerformed(REPEAT,String.valueOf(_repeatCount));
-
- recorder.actionPerformed(listener,actionCommand);
- }
- }
-
- // If repeat was true originally, clear it
- // Otherwise it might have been set by the action, etc
- if(_repeat)
- {
- repeat = false;
- repeatCount = 0;
- }
- }
- }
-
- /**
- * Returns the text area that fired the specified event.
- * @param evt The event
- */
- public static JEditTextArea getTextArea(EventObject evt)
- {
- if(evt != null)
- {
- Object o = evt.getSource();
- if(o instanceof Component)
- {
- // find the parent text area
- Component c = (Component)o;
- for(;;)
- {
- if(c instanceof JEditTextArea)
- return (JEditTextArea)c;
- else if(c == null)
- break;
- if(c instanceof JPopupMenu)
- c = ((JPopupMenu)c)
- .getInvoker();
- else
- c = c.getParent();
- }
- }
- }
-
- // this shouldn't happen
- System.err.println("BUG: getTextArea() returning null");
- System.err.println("Report this to Slava Pestov
- *
- * To use it in your app, treat it like any other component, for example:
- *
- * This class is used by
- * Uses getKeywords() method because that's part of the
- * TokenMarker classes.
- *
- * It is recommended that a # sign be used for comments
- * inside keywords.txt.
- */
- static public KeywordMap getKeywords() {
- if (keywordColoring == null) {
- try {
- keywordColoring = new KeywordMap(false);
- keywordToReference = new Hashtable();
- getKeywords(Base.getLibStream("keywords.txt"));
- for (Library lib : Base.getLibraries()) {
- File keywords = new File(lib.getFolder(), "keywords.txt");
- if (keywords.exists()) getKeywords(new FileInputStream(keywords));
+
+ public static HashMap
+ * It is recommended that a # sign be used for comments
+ * inside keywords.txt.
+ */
+ static public TokenMap getKeywords() {
+ if (extraTokens == null) {
+ try {
+ extraTokens = new TokenMap(false);
+
+ extraTokens.put("setup", TokenTypes.RESERVED_WORD);
+ extraTokens.put("loop", TokenTypes.RESERVED_WORD);
+
+ extraTokens.put("HIGH", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("LOW", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("OUTPUT", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("INPUT", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("INPUT_PULLUP", TokenTypes.RESERVED_WORD_2);
+
+ extraTokens.put("CHANGE", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("FALLING", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("RISING", TokenTypes.RESERVED_WORD_2);
+
+ extraTokens.put("PI", TokenTypes.LITERAL_NUMBER_FLOAT);
+ extraTokens.put("HALF_PI", TokenTypes.LITERAL_NUMBER_FLOAT);
+ extraTokens.put("TWO_PI", TokenTypes.LITERAL_NUMBER_FLOAT);
+ extraTokens.put("DEG_TO_RAD", TokenTypes.LITERAL_NUMBER_FLOAT);
+ extraTokens.put("RAD_TO_DEG", TokenTypes.LITERAL_NUMBER_FLOAT);
+ extraTokens.put("EULER", TokenTypes.LITERAL_NUMBER_FLOAT);
+
+ // Print.
+ extraTokens.put("DEC", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("HEX", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("OCT", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("BIN", TokenTypes.RESERVED_WORD_2);
+
+ extraTokens.put("true", TokenTypes.LITERAL_BOOLEAN);
+ extraTokens.put("false", TokenTypes.LITERAL_BOOLEAN);
+
+ // Related IO
+ extraTokens.put("pinMode", TokenTypes.FUNCTION);
+ extraTokens.put("digitalWrite", TokenTypes.FUNCTION);
+ extraTokens.put("digitalRead", TokenTypes.FUNCTION);
+ extraTokens.put("analogRead", TokenTypes.FUNCTION);
+ extraTokens.put("analogReference", TokenTypes.FUNCTION);
+ extraTokens.put("analogWrite", TokenTypes.FUNCTION);
+
+ // Others.
+ extraTokens.put("DIGITAL", TokenTypes.RESERVED_WORD_2);
+ extraTokens.put("ANALOG", TokenTypes.RESERVED_WORD_2);
+
+/*
+ HashMap
- *
- * For performance reasons, the linked list of tokens is reused after each
- * line is tokenized. Therefore, the return value of
- *
- * For example if the current line contains the start of a
- * multiline comment that doesn't end on that line, this method
- * should return the comment token type so that it continues on
- * the next line.
- *
- * @param token The initial token type for this line
- * @param line The line to be tokenized
- * @param lineIndex The index of the line in the document,
- * starting at 0
- * @return The initial token type for the next line
- */
- protected abstract byte markTokensImpl(byte token, Segment line,
- int lineIndex);
-
- /**
- * Returns if the token marker supports tokens that span multiple
- * lines. If this is true, the object using this token marker is
- * required to pass all lines in the document to the
- *
- *
- * The default implementation returns true; it should be overridden
- * to return false on simpler token markers for increased speed.
- */
- public boolean supportsMultilineTokens()
- {
- return true;
- }
-
- /**
- * Informs the token marker that lines have been inserted into
- * the document. This inserts a gap in the
- *
- * It should be unnecessary to call this under normal
- * circumstances; KeyEvent
class, without
- * the VK_
prefix.
- * @param keyStroke A string description of the key stroke
- */
- public static KeyStroke parseKeyStroke(String keyStroke)
- {
- if(keyStroke == null)
- return null;
- int modifiers = 0;
- int index = keyStroke.indexOf('+');
- if(index != -1)
- {
- for(int i = 0; i < index; i++)
- {
- switch(Character.toUpperCase(keyStroke
- .charAt(i)))
- {
- case 'A':
- modifiers |= InputEvent.ALT_MASK;
- break;
- case 'C':
- modifiers |= InputEvent.CTRL_MASK;
- break;
- case 'M':
- modifiers |= InputEvent.META_MASK;
- break;
- case 'S':
- modifiers |= InputEvent.SHIFT_MASK;
- break;
- }
- }
- }
- String key = keyStroke.substring(index + 1);
- if(key.length() == 1)
- {
- char ch = Character.toUpperCase(key.charAt(0));
- if(modifiers == 0)
- return KeyStroke.getKeyStroke(ch);
- else
- return KeyStroke.getKeyStroke(ch,modifiers);
- }
- else if(key.length() == 0)
- {
- System.err.println("Invalid key stroke: " + keyStroke);
- return null;
- }
- else
- {
- int ch;
-
- try
- {
- ch = KeyEvent.class.getField("VK_".concat(key))
- .getInt(null);
- }
- catch(Exception e)
- {
- System.err.println("Invalid key stroke: "
- + keyStroke);
- return null;
- }
-
- return KeyStroke.getKeyStroke(ch,modifiers);
- }
- }
-
- // private members
- private Hashtable bindings;
- private Hashtable currentBindings;
-
- private DefaultInputHandler(DefaultInputHandler copy)
- {
- bindings = currentBindings = copy.bindings;
- }
-}
diff --git a/app/src/processing/app/syntax/InputHandler.java b/app/src/processing/app/syntax/InputHandler.java
deleted file mode 100644
index e146713484b..00000000000
--- a/app/src/processing/app/syntax/InputHandler.java
+++ /dev/null
@@ -1,1135 +0,0 @@
-/*
- * InputHandler.java - Manages key bindings and executes actions
- * Copyright (C) 1999 Slava Pestov
- *
- * You may use and modify this package for any purpose. Redistribution is
- * permitted, in both source and binary form, provided that this notice
- * remains intact in all source distributions of this package.
- */
-
-package processing.app.syntax;
-
-import javax.swing.text.*;
-import javax.swing.JPopupMenu;
-import java.awt.event.*;
-import java.awt.Component;
-import java.util.*;
-
-/**
- * An input handler converts the user's key strokes into concrete actions.
- * It also takes care of macro recording and action repetition.
- *
- * It is also faster and doesn't have as many problems. It can be used
- * in other applications; the only other part of jEdit it depends on is
- * the syntax package.JEditTextArea ta = new JEditTextArea();
- * ta.setTokenMarker(new JavaTokenMarker());
- * ta.setText("public class Test {\n"
- * + " public static void main(String[] args) {\n"
- * + " System.out.println(\"Hello World\");\n"
- * + " }\n"
- * + "}");
- *
- * @author Slava Pestov
- */
-public class JEditTextArea extends JComponent
-{
- /**
- * Adding components with this name to the text area will place
- * them left of the horizontal scroll bar. In jEdit, the status
- * bar is added this way.
- */
- public static String LEFT_OF_SCROLLBAR = "los";
-
- /**
- * Creates a new JEditTextArea with the default settings.
- */
- /*
- public JEditTextArea()
- {
- this(TextAreaDefaults.getDefaults());
- }
- */
-
- /**
- * Creates a new JEditTextArea with the specified settings.
- * @param defaults The default settings
- */
- public JEditTextArea(TextAreaDefaults defaults)
- {
- // Enable the necessary events
- enableEvents(AWTEvent.KEY_EVENT_MASK);
-
- // Initialize some misc. stuff
- painter = new TextAreaPainter(this,defaults);
- editorLineNumbers = new TextAreaLineNumbers(this,defaults);
- documentHandler = new DocumentHandler();
- eventListenerList = new EventListenerList();
- caretEvent = new MutableCaretEvent();
- lineSegment = new Segment();
- bracketLine = bracketPosition = -1;
- blink = true;
-
- // Initialize the GUI
- setLayout(new ScrollLayout());
- add(LEFT, editorLineNumbers);
- add(CENTER, painter);
- add(RIGHT, vertical = new JScrollBar(JScrollBar.VERTICAL));
- add(BOTTOM, horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
-
- // Add some event listeners
- vertical.addAdjustmentListener(new AdjustHandler());
- horizontal.addAdjustmentListener(new AdjustHandler());
- painter.addComponentListener(new ComponentHandler());
- painter.addMouseListener(new MouseHandler());
- painter.addMouseMotionListener(new DragHandler());
- addFocusListener(new FocusHandler());
- // send tab keys through to the text area
- // http://dev.processing.org/bugs/show_bug.cgi?id=1267
- setFocusTraversalKeysEnabled(false);
-
- // Load the defaults
- setInputHandler(defaults.inputHandler);
- setDocument(defaults.document);
- editable = defaults.editable;
- caretVisible = defaults.caretVisible;
- caretBlinks = defaults.caretBlinks;
- electricScroll = defaults.electricScroll;
-
- // We don't seem to get the initial focus event?
- focusedComponent = this;
-
- addMouseWheelListener(new MouseWheelListener() {
- public void mouseWheelMoved(MouseWheelEvent e) {
- if (!scrollBarsInitialized) return;
- int amt = e.getWheelRotation();
- vertical.setValue(vertical.getValue() + amt * 3);
- }
- });
- }
-
- /**
- * Inline Input Method Support for Japanese.
- */
- private InputMethodSupport inputMethodSupport = null;
- public InputMethodRequests getInputMethodRequests() {
- if (inputMethodSupport == null) {
- inputMethodSupport = new InputMethodSupport(this);
- }
- return inputMethodSupport;
- }
-
- /**
- * Get current position of the vertical scroll bar. [fry]
- */
- public int getScrollPosition() {
- return vertical.getValue();
- }
-
-
- /**
- * Set position of the vertical scroll bar. [fry]
- */
- public void setScrollPosition(int what) {
- vertical.setValue(what);
- }
-
-
- /**
- * Returns if this component can be traversed by pressing
- * the Tab key. This returns false.
- */
-// public final boolean isManagingFocus() {
-// return true;
-// }
-
- /**
- * Returns the object responsible for painting this text area.
- */
- public final TextAreaPainter getPainter() {
- return painter;
- }
-
- /**
- * Returns the input handler.
- */
- public final InputHandler getInputHandler() {
- return inputHandler;
- }
-
- /**
- * Sets the input handler.
- * @param inputHandler The new input handler
- */
- public void setInputHandler(InputHandler inputHandler) {
- this.inputHandler = inputHandler;
- }
-
- /**
- * Returns true if the caret is blinking, false otherwise.
- */
- public final boolean isCaretBlinkEnabled() {
- return caretBlinks;
- }
-
- /**
- * Toggles caret blinking.
- * @param caretBlinks True if the caret should blink, false otherwise
- */
- public void setCaretBlinkEnabled(boolean caretBlinks) {
- this.caretBlinks = caretBlinks;
- if(!caretBlinks)
- blink = false;
-
- painter.invalidateSelectedLines();
- }
-
- /**
- * Returns true if the caret is visible, false otherwise.
- */
- public final boolean isCaretVisible() {
- return (!caretBlinks || blink) && caretVisible;
- }
-
- /**
- * Sets if the caret should be visible.
- * @param caretVisible True if the caret should be visible, false
- * otherwise
- */
- public void setCaretVisible(boolean caretVisible) {
- this.caretVisible = caretVisible;
- blink = true;
-
- painter.invalidateSelectedLines();
- }
-
- /**
- * Blinks the caret.
- */
- public final void blinkCaret() {
- if (caretBlinks) {
- blink = !blink;
- painter.invalidateSelectedLines();
- } else {
- blink = true;
- }
- }
-
- /**
- * Returns the number of lines from the top and button of the
- * text area that are always visible.
- */
- public final int getElectricScroll() {
- return electricScroll;
- }
-
- /**
- * Sets the number of lines from the top and bottom of the text
- * area that are always visible
- * @param electricScroll The number of lines always visible from
- * the top or bottom
- */
- public final void setElectricScroll(int electricScroll) {
- this.electricScroll = electricScroll;
- }
-
-
- /**
- * Updates the state of the scroll bars. This should be called
- * if the number of lines in the document changes, or when the
- * size of the text are changes.
- */
- public void updateScrollBars() {
- if (vertical != null && visibleLines != 0) {
- vertical.setValues(firstLine,visibleLines,0,getLineCount());
- vertical.setUnitIncrement(2);
- vertical.setBlockIncrement(visibleLines);
- }
-
- //if (horizontal != null && width != 0) {
- if ((horizontal != null) && (painter.getWidth() != 0)) {
- //int value = horizontal.getValue();
- //System.out.println("updateScrollBars");
- //int width = painter.getWidth();
- int lineCount = getLineCount();
- int maxLineLength = 0;
- for (int i = 0; i < lineCount; i++) {
- int lineLength = getLineLength(i);
- if (lineLength > maxLineLength) {
- maxLineLength = lineLength;
- }
- }
- int charWidth = painter.getFontMetrics().charWidth('w');
- int width = maxLineLength * charWidth;
- int painterWidth = painter.getWidth();
- //System.out.println("max line len " + maxLineLength);
- //System.out.println("width " + width);
- //System.out.println("text area width " + painter.getWidth());
-
- // this was the default, but it's enormous
- //horizontal.setValues(-horizontalOffset,width,0,width * 5);
-
- // something more reasonable, though this is a bad solution
- //horizontal.setValues(-horizontalOffset,width,0,width * 2);
-
- // in general.. time to start looking at that other syntax pkg
- // since most code should fit the window horizontally, just use
- // the default settings for the width, this is a nicer solution
- // until a better update mechanism can be implemented [fry]
-
- //horizontal.setValues(0, width, 0, width);
- //0, width - horizontalOffset);
- // works, from pre-75 versions of p5
- //horizontal.setValues(-horizontalOffset, width, 0, width);
-
- // gets weird when writing to the end of lines
- //horizontal.setValues(value, painterWidth, 0, width);
-
- // seems to work, implemented for 0075
- horizontal.setValues(-horizontalOffset, painterWidth, 0, width);
-
- //horizontal.setUnitIncrement(painter.getFontMetrics().charWidth('w'));
- horizontal.setUnitIncrement(charWidth);
- horizontal.setBlockIncrement(width / 2);
- }
- updateLineNumbers();
- }
-
- private void updateLineNumbers() {
- if (editorLineNumbers != null) {
- editorLineNumbers.updateLineNumbers(getFirstLine() + 1, Math.min(getFirstLine() + getVisibleLines() + 1, getLineCount()));
- editorLineNumbers.updateWidthForNumDigits(String.valueOf(getLineCount()).length());
- }
- }
-
- /**
- * Returns the line displayed at the text area's origin.
- */
- public final int getFirstLine() {
- return firstLine;
- }
-
- /**
- * Sets the line displayed at the text area's origin without
- * updating the scroll bars.
- */
- public void setFirstLine(int firstLine) {
- if (firstLine == this.firstLine) return;
-
- this.firstLine = firstLine;
- if (firstLine != vertical.getValue()) {
- updateScrollBars();
- }
- repaintEditor();
- }
-
- /**
- * Returns the number of lines visible in this text area.
- */
- public final int getVisibleLines() {
- return visibleLines;
- }
-
- /**
- * Recalculates the number of visible lines. This should not
- * be called directly.
- */
- public final void recalculateVisibleLines() {
- if (painter == null) return;
-
- int height = painter.getHeight();
- int lineHeight = painter.getFontMetrics().getHeight();
- visibleLines = height / lineHeight;
- updateScrollBars();
- }
-
- /**
- * Returns the horizontal offset of drawn lines.
- */
- public final int getHorizontalOffset() {
- return horizontalOffset;
- }
-
- /**
- * Sets the horizontal offset of drawn lines. This can be used to
- * implement horizontal scrolling.
- * @param horizontalOffset offset The new horizontal offset
- */
- public void setHorizontalOffset(int horizontalOffset)
- {
- if(horizontalOffset == this.horizontalOffset)
- return;
- this.horizontalOffset = horizontalOffset;
- if(horizontalOffset != horizontal.getValue())
- updateScrollBars();
- repaintEditor();
- }
-
- /**
- * A fast way of changing both the first line and horizontal
- * offset.
- * @param firstLine The new first line
- * @param horizontalOffset The new horizontal offset
- * @return True if any of the values were changed, false otherwise
- */
- public boolean setOrigin(int firstLine, int horizontalOffset)
- {
- boolean changed = false;
- //int oldFirstLine = this.firstLine;
-
- if(horizontalOffset != this.horizontalOffset)
- {
- this.horizontalOffset = horizontalOffset;
- changed = true;
- }
-
- if(firstLine != this.firstLine)
- {
- this.firstLine = firstLine;
- changed = true;
- }
-
- if(changed)
- {
- updateScrollBars();
- repaintEditor();
- }
-
- return changed;
- }
-
- private void repaintEditor() {
- painter.repaint();
- updateLineNumbers();
- }
-
- /**
- * Ensures that the caret is visible by scrolling the text area if
- * necessary.
- * @return True if scrolling was actually performed, false if the
- * caret was already visible
- */
- public boolean scrollToCaret()
- {
- int line = getCaretLine();
- int lineStart = getLineStartOffset(line);
- int offset = Math.max(0,Math.min(getLineLength(line) - 1,
- getCaretPosition() - lineStart));
-
- return scrollTo(line,offset);
- }
-
- /**
- * Ensures that the specified line and offset is visible by scrolling
- * the text area if necessary.
- * @param line The line to scroll to
- * @param offset The offset in the line to scroll to
- * @return True if scrolling was actually performed, false if the
- * line and offset was already visible
- */
- public boolean scrollTo(int line, int offset)
- {
- // visibleLines == 0 before the component is realized
- // we can't do any proper scrolling then, so we have
- // this hack...
- if (visibleLines == 0) {
- setFirstLine(Math.max(0,line - electricScroll));
- return true;
- }
-
- int newFirstLine = firstLine;
- int newHorizontalOffset = horizontalOffset;
-
- if(line < firstLine + electricScroll) {
- newFirstLine = Math.max(0,line - electricScroll);
-
- } else if(line + electricScroll >= firstLine + visibleLines) {
- newFirstLine = (line - visibleLines) + electricScroll + 1;
- if(newFirstLine + visibleLines >= getLineCount())
- newFirstLine = getLineCount() - visibleLines;
- if(newFirstLine < 0)
- newFirstLine = 0;
- }
-
- int x = _offsetToX(line,offset);
- int width = painter.getFontMetrics().charWidth('w');
-
- if(x < 0) {
- newHorizontalOffset = Math.min(0,horizontalOffset - x + width + 5);
- } else if(x + width >= painter.getWidth()) {
- newHorizontalOffset = horizontalOffset +
- (painter.getWidth() - x) - width - 5;
- }
-
- return setOrigin(newFirstLine,newHorizontalOffset);
- }
-
- /**
- * Converts a line index to a y co-ordinate.
- * @param line The line
- */
- public int lineToY(int line)
- {
- FontMetrics fm = painter.getFontMetrics();
- return (line - firstLine) * fm.getHeight()
- - (fm.getLeading() + fm.getMaxDescent());
- }
-
- /**
- * Converts a y co-ordinate to a line index.
- * @param y The y co-ordinate
- */
- public int yToLine(int y)
- {
- FontMetrics fm = painter.getFontMetrics();
- int height = fm.getHeight();
- return Math.max(0,Math.min(getLineCount() - 1,
- y / height + firstLine));
- }
-
- /**
- * Converts an offset in a line into an x co-ordinate. This is a
- * slow version that can be used any time.
- * @param line The line
- * @param offset The offset, from the start of the line
- */
- public final int offsetToX(int line, int offset)
- {
- // don't use cached tokens
- painter.currentLineTokens = null;
- return _offsetToX(line,offset);
- }
-
- /**
- * Converts an offset in a line into an x co-ordinate. This is a
- * fast version that should only be used if no changes were made
- * to the text since the last repaint.
- * @param line The line
- * @param offset The offset, from the start of the line
- */
- public int _offsetToX(int line, int offset)
- {
- TokenMarker tokenMarker = getTokenMarker();
-
- /* Use painter's cached info for speed */
- FontMetrics fm = painter.getFontMetrics();
-
- getLineText(line,lineSegment);
-
- int segmentOffset = lineSegment.offset;
- int x = horizontalOffset;
-
- /* If syntax coloring is disabled, do simple translation */
- if(tokenMarker == null)
- {
- lineSegment.count = offset;
- return x + Utilities.getTabbedTextWidth(lineSegment,
- fm,x,painter,0);
- }
- /* If syntax coloring is enabled, we have to do this because
- * tokens can vary in width */
- else
- {
- Token tokens;
- if(painter.currentLineIndex == line
- && painter.currentLineTokens != null)
- tokens = painter.currentLineTokens;
- else
- {
- painter.currentLineIndex = line;
- tokens = painter.currentLineTokens
- = tokenMarker.markTokens(lineSegment,line);
- }
-
- //Toolkit toolkit = painter.getToolkit();
- Font defaultFont = painter.getFont();
- SyntaxStyle[] styles = painter.getStyles();
-
- for(;;)
- {
- byte id = tokens.id;
- if(id == Token.END)
- {
- return x;
- }
-
- if(id == Token.NULL)
- fm = painter.getFontMetrics();
- else
- fm = styles[id].getFontMetrics(defaultFont, this);
-
- int length = tokens.length;
-
- if(offset + segmentOffset < lineSegment.offset + length)
- {
- lineSegment.count = offset - (lineSegment.offset - segmentOffset);
- return x + Utilities.getTabbedTextWidth(
- lineSegment,fm,x,painter,0);
- }
- else
- {
- lineSegment.count = length;
- x += Utilities.getTabbedTextWidth(
- lineSegment,fm,x,painter,0);
- lineSegment.offset += length;
- }
- tokens = tokens.next;
- }
- }
- }
-
- /**
- * Converts an x co-ordinate to an offset within a line.
- * @param line The line
- * @param x The x co-ordinate
- */
- public int xToOffset(int line, int x)
- {
- TokenMarker tokenMarker = getTokenMarker();
-
- /* Use painter's cached info for speed */
- FontMetrics fm = painter.getFontMetrics();
-
- getLineText(line,lineSegment);
-
- char[] segmentArray = lineSegment.array;
- int segmentOffset = lineSegment.offset;
- int segmentCount = lineSegment.count;
-
- int width = horizontalOffset;
-
- if(tokenMarker == null)
- {
- for(int i = 0; i < segmentCount; i++)
- {
- char c = segmentArray[i + segmentOffset];
- int charWidth;
- if(c == '\t')
- charWidth = (int)painter.nextTabStop(width,i)
- - width;
- else
- charWidth = fm.charWidth(c);
-
- if(painter.isBlockCaretEnabled())
- {
- if(x - charWidth <= width)
- return i;
- }
- else
- {
- if(x - charWidth / 2 <= width)
- return i;
- }
-
- width += charWidth;
- }
-
- return segmentCount;
- }
- else
- {
- Token tokens;
- if(painter.currentLineIndex == line && painter
- .currentLineTokens != null)
- tokens = painter.currentLineTokens;
- else
- {
- painter.currentLineIndex = line;
- tokens = painter.currentLineTokens
- = tokenMarker.markTokens(lineSegment,line);
- }
-
- int offset = 0;
- //Toolkit toolkit = painter.getToolkit();
- Font defaultFont = painter.getFont();
- SyntaxStyle[] styles = painter.getStyles();
-
- for(;;)
- {
- byte id = tokens.id;
- if(id == Token.END)
- return offset;
-
- if(id == Token.NULL)
- fm = painter.getFontMetrics();
- else
- fm = styles[id].getFontMetrics(defaultFont, this);
-
- int length = tokens.length;
-
- for(int i = 0; i < length; i++)
- {
- char c = segmentArray[segmentOffset + offset + i];
- int charWidth;
- if(c == '\t')
- charWidth = (int)painter.nextTabStop(width,offset + i)
- - width;
- else
- charWidth = fm.charWidth(c);
-
- if(painter.isBlockCaretEnabled())
- {
- if(x - charWidth <= width)
- return offset + i;
- }
- else
- {
- if(x - charWidth / 2 <= width)
- return offset + i;
- }
-
- width += charWidth;
- }
-
- offset += length;
- tokens = tokens.next;
- }
- }
- }
-
- /**
- * Converts a point to an offset, from the start of the text.
- * @param x The x co-ordinate of the point
- * @param y The y co-ordinate of the point
- */
- public int xyToOffset(int x, int y)
- {
- int line = yToLine(y);
- int start = getLineStartOffset(line);
- return start + xToOffset(line,x);
- }
-
- /**
- * Returns the document this text area is editing.
- */
- public final SyntaxDocument getDocument()
- {
- return document;
- }
-
- /**
- * Sets the document this text area is editing.
- * @param document The document
- */
- public void setDocument(SyntaxDocument document) {
- if (this.document == document)
- return;
- if (this.document != null)
- this.document.removeDocumentListener(documentHandler);
- this.document = document;
-
- document.addDocumentListener(documentHandler);
-
- select(0, 0);
- updateScrollBars();
- repaintEditor();
- }
-
-
- /**
- * Set document with a twist, includes the old caret
- * and scroll positions, added for p5. [fry]
- */
- public void setDocument(SyntaxDocument document,
- int start, int stop, int scroll) {
- if (this.document == document)
- return;
- if (this.document != null)
- this.document.removeDocumentListener(documentHandler);
- this.document = document;
-
- document.addDocumentListener(documentHandler);
-
- select(start, stop);
- updateScrollBars();
- setScrollPosition(scroll);
- repaintEditor();
- }
-
-
- /**
- * Returns the document's token marker. Equivalent to calling
- * getDocument().getTokenMarker()
.
- */
- public final TokenMarker getTokenMarker()
- {
- return document.getTokenMarker();
- }
-
- /**
- * Sets the document's token marker. Equivalent to caling
- * getDocument().setTokenMarker()
.
- * @param tokenMarker The token marker
- */
- public final void setTokenMarker(TokenMarker tokenMarker)
- {
- document.setTokenMarker(tokenMarker);
- }
-
- /**
- * Returns the length of the document. Equivalent to calling
- * getDocument().getLength()
.
- */
- public final int getDocumentLength()
- {
- return document.getLength();
- }
-
- /**
- * Returns the number of lines in the document.
- */
- public final int getLineCount()
- {
- if (document != null) {
- return document.getDefaultRootElement().getElementCount();
- } else {
- return 0;
- }
- }
-
- /**
- * Returns the line containing the specified offset.
- * @param offset The offset
- */
- public final int getLineOfOffset(int offset)
- {
- return document.getDefaultRootElement().getElementIndex(offset);
- }
-
- /**
- * Returns the start offset of the specified line.
- * @param line The line
- * @return The start offset of the specified line, or -1 if the line is
- * invalid
- */
- public int getLineStartOffset(int line)
- {
- Element lineElement = document.getDefaultRootElement()
- .getElement(line);
- if(lineElement == null)
- return -1;
- else
- return lineElement.getStartOffset();
- }
-
- /**
- * Returns the end offset of the specified line.
- * @param line The line
- * @return The end offset of the specified line, or -1 if the line is
- * invalid.
- */
- public int getLineStopOffset(int line)
- {
- Element lineElement = document.getDefaultRootElement()
- .getElement(line);
- if(lineElement == null)
- return -1;
- else
- return lineElement.getEndOffset();
- }
-
- /**
- * Returns the end offset of the specified line, but not past the end of the text
- * @param line The line
- * @return The end offset of the specified line, safe to use for a selection, or -1 if the line is
- * invalid.
- */
- public int getSafeLineStopOffset(int line)
- {
- return Math.min(getLineStopOffset(line),getDocumentLength());
- }
-
- /**
- * Returns the length of the specified line.
- * @param line The line
- */
- public int getLineLength(int line)
- {
- Element lineElement = document.getDefaultRootElement()
- .getElement(line);
- if(lineElement == null)
- return -1;
- else
- return lineElement.getEndOffset()
- - lineElement.getStartOffset() - 1;
- }
-
- /**
- * Returns the entire text of this text area.
- */
- public String getText()
- {
- try
- {
- return document.getText(0,document.getLength());
- }
- catch(BadLocationException bl)
- {
- bl.printStackTrace();
- return null;
- }
- }
-
-
- /**
- * Sets the entire text of this text area.
- */
- public void setText(String text)
- {
- try {
- document.beginCompoundEdit();
- document.remove(0,document.getLength());
- document.insertString(0,text,null);
-
- } catch (BadLocationException bl) {
- bl.printStackTrace();
-
- } finally {
- document.endCompoundEdit();
- }
- }
-
-
- /**
- * Returns the specified substring of the document.
- * @param start The start offset
- * @param len The length of the substring
- * @return The substring, or null if the offsets are invalid
- */
- public final String getText(int start, int len)
- {
- try
- {
- return document.getText(start,len);
- }
- catch(BadLocationException bl)
- {
- bl.printStackTrace();
- return null;
- }
- }
-
- /**
- * Copies the specified substring of the document into a segment.
- * If the offsets are invalid, the segment will contain a null string.
- * @param start The start offset
- * @param len The length of the substring
- * @param segment The segment
- */
- public final void getText(int start, int len, Segment segment)
- {
- try
- {
- document.getText(start,len,segment);
- }
- catch(BadLocationException bl)
- {
- bl.printStackTrace();
- segment.offset = segment.count = 0;
- }
- }
-
- /**
- * Returns the text on the specified line.
- * @param lineIndex The line
- * @return The text, or null if the line is invalid
- */
- public final String getLineText(int lineIndex)
- {
- int start = getLineStartOffset(lineIndex);
- return getText(start,getLineStopOffset(lineIndex) - start - 1);
- }
-
- /**
- * Copies the text on the specified line into a segment. If the line
- * is invalid, the segment will contain a null string.
- * @param lineIndex The line
- */
- public final void getLineText(int lineIndex, Segment segment)
- {
- int start = getLineStartOffset(lineIndex);
- getText(start,getLineStopOffset(lineIndex) - start - 1,segment);
- }
-
- /**
- * Returns the selection start offset.
- */
- public final int getSelectionStart()
- {
- return selectionStart;
- }
-
- /**
- * Returns the offset where the selection starts on the specified
- * line.
- */
- public int getSelectionStart(int line)
- {
- if(line == selectionStartLine)
- return selectionStart;
- else if(rectSelect)
- {
- Element map = document.getDefaultRootElement();
- int start = selectionStart - map.getElement(selectionStartLine)
- .getStartOffset();
-
- Element lineElement = map.getElement(line);
- int lineStart = lineElement.getStartOffset();
- int lineEnd = lineElement.getEndOffset() - 1;
- return Math.min(lineEnd,lineStart + start);
- }
- else
- return getLineStartOffset(line);
- }
-
- /**
- * Returns the selection start line.
- */
- public final int getSelectionStartLine()
- {
- return selectionStartLine;
- }
-
- /**
- * Sets the selection start. The new selection will be the new
- * selection start and the old selection end.
- * @param selectionStart The selection start
- * @see #select(int,int)
- */
- public final void setSelectionStart(int selectionStart)
- {
- select(selectionStart,selectionEnd);
- }
-
- /**
- * Returns the selection end offset.
- */
- public final int getSelectionStop()
- {
- return selectionEnd;
- }
-
- /**
- * Returns the offset where the selection ends on the specified
- * line.
- */
- public int getSelectionStop(int line)
- {
- if(line == selectionEndLine)
- return selectionEnd;
- else if(rectSelect)
- {
- Element map = document.getDefaultRootElement();
- int end = selectionEnd - map.getElement(selectionEndLine)
- .getStartOffset();
-
- Element lineElement = map.getElement(line);
- int lineStart = lineElement.getStartOffset();
- int lineEnd = lineElement.getEndOffset() - 1;
- return Math.min(lineEnd,lineStart + end);
- }
- else
- return getLineStopOffset(line) - 1;
- }
-
- /**
- * Returns the selection end line.
- */
- public final int getSelectionStopLine()
- {
- return selectionEndLine;
- }
-
- /**
- * Sets the selection end. The new selection will be the old
- * selection start and the bew selection end.
- * @param selectionEnd The selection end
- * @see #select(int,int)
- */
- public final void setSelectionEnd(int selectionEnd)
- {
- select(selectionStart,selectionEnd);
- }
-
-
- public final boolean isSelectionActive()
- {
- return(selectionStart != selectionEnd);
- }
-
- /**
- * Returns the caret position. This will either be the selection
- * start or the selection end, depending on which direction the
- * selection was made in.
- */
- public final int getCaretPosition()
- {
- return (biasLeft ? selectionStart : selectionEnd);
- }
-
- /**
- * Returns the caret line.
- */
- public final int getCaretLine()
- {
- return (biasLeft ? selectionStartLine : selectionEndLine);
- }
-
- /**
- * Returns the mark position. This will be the opposite selection
- * bound to the caret position.
- * @see #getCaretPosition()
- */
- public final int getMarkPosition()
- {
- return (biasLeft ? selectionEnd : selectionStart);
- }
-
- /**
- * Returns the mark line.
- */
- public final int getMarkLine()
- {
- return (biasLeft ? selectionEndLine : selectionStartLine);
- }
-
- /**
- * Sets the caret position. The new selection will consist of the
- * caret position only (hence no text will be selected)
- * @param caret The caret position
- * @see #select(int,int)
- */
- public final void setCaretPosition(int caret)
- {
- select(caret,caret);
- }
-
- /**
- * Selects all text in the document.
- */
- public final void selectAll()
- {
- select(0,getDocumentLength());
- }
-
- /**
- * Moves the mark to the caret position.
- */
- public final void selectNone()
- {
- select(getCaretPosition(),getCaretPosition());
- }
-
- /**
- * Selects from the start offset to the end offset. This is the
- * general selection method used by all other selecting methods.
- * The caret position will be start if start < end, and end
- * if end > start.
- * @param start The start offset
- * @param end The end offset
- */
- public void select(int start, int end)
- {
- int newStart, newEnd;
- boolean newBias;
- if(start <= end)
- {
- newStart = start;
- newEnd = end;
- newBias = false;
- }
- else
- {
- newStart = end;
- newEnd = start;
- newBias = true;
- }
-
- if (newEnd > getDocumentLength()) {
- newEnd = getDocumentLength();
- }
-
- if(newStart < 0)
- {
- throw new IllegalArgumentException("Bounds out of"
- + " range: " + newStart + "," +
- newEnd + " [" + getDocumentLength() + "]");
- }
-
- // If the new position is the same as the old, we don't
- // do all this crap, however we still do the stuff at
- // the end (clearing magic position, scrolling)
- if(newStart != selectionStart || newEnd != selectionEnd
- || newBias != biasLeft)
- {
- int newStartLine = getLineOfOffset(newStart);
- int newEndLine = getLineOfOffset(newEnd);
-
- if(painter.isBracketHighlightEnabled())
- {
- if(bracketLine != -1)
- painter.invalidateLine(bracketLine);
- updateBracketHighlight(end);
- if(bracketLine != -1)
- painter.invalidateLine(bracketLine);
- }
-
- painter.invalidateLineRange(selectionStartLine,selectionEndLine);
- painter.invalidateLineRange(newStartLine,newEndLine);
-
- document.addUndoableEdit(new CaretUndo(selectionStart,selectionEnd));
-
- selectionStart = newStart;
- selectionEnd = newEnd;
- selectionStartLine = newStartLine;
- selectionEndLine = newEndLine;
- biasLeft = newBias;
-
- if (newStart != newEnd) {
- Clipboard unixclipboard = getToolkit().getSystemSelection();
- if (unixclipboard != null) {
- String selection = getSelectedText();
- if (selection != null) {
- unixclipboard.setContents(new StringSelection(selection), null);
- }
- }
- }
-
- fireCaretEvent();
- }
-
- // When the user is typing, etc, we don't want the caret
- // to blink
- blink = true;
- caretTimer.restart();
-
- // Disable rectangle select if selection start = selection end
- if(selectionStart == selectionEnd)
- rectSelect = false;
-
- // Clear the `magic' caret position used by up/down
- magicCaret = -1;
-
- scrollToCaret();
-
- // notify the line number feller
- if (editorLineStatus != null) {
- editorLineStatus.set(selectionStartLine, selectionEndLine);
- //System.out.println("why " + selectionStartLine + " " + selectionEndLine);
- //System.out.println(getLineOfOffset(start) + " " +
- // getLineOfOffset(end));
- }
- }
-
- private boolean isWordCharacter( char ch, String noWordSep )
- {
- return Character.isLetterOrDigit(ch) || ch=='_' || noWordSep.indexOf(ch) != -1;
- }
-
- protected void setNewSelectionWord( int line, int offset )
- {
- if (getLineLength(line) == 0) {
- newSelectionStart = getLineStartOffset(line);
- newSelectionEnd = newSelectionStart;
- return;
- }
-
- String noWordSep = (String)document.getProperty("noWordSep");
- if(noWordSep == null)
- noWordSep = "";
-
- String lineText = getLineText(line);
-
- int wordStart = 0;
- int wordEnd = lineText.length();
-
- char ch = lineText.charAt(Math.max(0,offset - 1));
-
- // special case for whitespace (fry 0122, bug #348)
- // this is really nasty.. turns out that double-clicking any non-letter
- // or digit char gets lumped together.. sooo, this quickly gets messy,
- // because really it needs to check whether the chars are of the same
- // type.. so a double space or double - might be grouped together,
- // but what about a +=1? do + and - get grouped but not the 1? blech,
- // coming back to this later. it's not a difficult fix, just a
- // time-consuming one to track down all the proper cases.
- /*
- if (ch == ' ') {
- //System.out.println("yeehaa");
-
- for(int i = offset - 1; i >= 0; i--) {
- if (lineText.charAt(i) == ' ') {
- wordStart = i;
- } else {
- break;
- }
- }
- for(int i = offset; i < lineText.length(); i++) {
- if (lineText.charAt(i) == ' ') {
- wordEnd = i + 1;
- } else {
- break;
- }
- }
-
- } else {
- */
-
- // If the user clicked on a non-letter char,
- // we select the surrounding non-letters
- boolean selectNoLetter = !isWordCharacter(ch,noWordSep);
-
- for(int i = offset - 1; i >= 0; i--) {
- ch = lineText.charAt(i);
- if (selectNoLetter ^ !isWordCharacter(ch,noWordSep)) {
- wordStart = i + 1;
- break;
- }
- }
-
- for(int i = offset; i < lineText.length(); i++) {
- ch = lineText.charAt(i);
- if(selectNoLetter ^ !isWordCharacter(ch,noWordSep)) {
- wordEnd = i;
- break;
- }
- }
- //}
- int lineStart = getLineStartOffset(line);
-
- newSelectionStart = lineStart + wordStart;
- newSelectionEnd = lineStart + wordEnd;
- }
-
-
- /**
- * Returns the selected text, or null if no selection is active.
- */
- public final String getSelectedText()
- {
- if(selectionStart == selectionEnd)
- return null;
-
- if(rectSelect)
- {
- // Return each row of the selection on a new line
-
- Element map = document.getDefaultRootElement();
-
- int start = selectionStart - map.getElement(selectionStartLine)
- .getStartOffset();
- int end = selectionEnd - map.getElement(selectionEndLine)
- .getStartOffset();
-
- // Certain rectangles satisfy this condition...
- if(end < start)
- {
- int tmp = end;
- end = start;
- start = tmp;
- }
-
- StringBuffer buf = new StringBuffer();
- Segment seg = new Segment();
-
- for(int i = selectionStartLine; i <= selectionEndLine; i++)
- {
- Element lineElement = map.getElement(i);
- int lineStart = lineElement.getStartOffset();
- int lineEnd = lineElement.getEndOffset() - 1;
- int lineLen = lineEnd - lineStart;
-
- lineStart = Math.min(lineStart + start,lineEnd);
- lineLen = Math.min(end - start,lineEnd - lineStart);
-
- getText(lineStart,lineLen,seg);
- buf.append(seg.array,seg.offset,seg.count);
-
- if(i != selectionEndLine)
- buf.append('\n');
- }
-
- return buf.toString();
- }
- else
- {
- return getText(selectionStart,
- selectionEnd - selectionStart);
- }
- }
-
- /**
- * Replaces the selection with the specified text.
- * @param selectedText The replacement text for the selection
- */
- public void setSelectedText(String selectedText)
- {
- if(!editable)
- {
- throw new InternalError("Text component"
- + " read only");
- }
-
- document.beginCompoundEdit();
-
- try
- {
- if(rectSelect)
- {
- Element map = document.getDefaultRootElement();
-
- int start = selectionStart - map.getElement(selectionStartLine)
- .getStartOffset();
- int end = selectionEnd - map.getElement(selectionEndLine)
- .getStartOffset();
-
- // Certain rectangles satisfy this condition...
- if(end < start)
- {
- int tmp = end;
- end = start;
- start = tmp;
- }
-
- int lastNewline = 0;
- int currNewline = 0;
-
- for(int i = selectionStartLine; i <= selectionEndLine; i++)
- {
- Element lineElement = map.getElement(i);
- int lineStart = lineElement.getStartOffset();
- int lineEnd = lineElement.getEndOffset() - 1;
- int rectStart = Math.min(lineEnd,lineStart + start);
-
- document.remove(rectStart,Math.min(lineEnd - rectStart,
- end - start));
-
- if(selectedText == null)
- continue;
-
- currNewline = selectedText.indexOf('\n',lastNewline);
- if(currNewline == -1)
- currNewline = selectedText.length();
-
- document.insertString(rectStart,selectedText
- .substring(lastNewline,currNewline),null);
-
- lastNewline = Math.min(selectedText.length(),
- currNewline + 1);
- }
-
- if(selectedText != null &&
- currNewline != selectedText.length())
- {
- int offset = map.getElement(selectionEndLine)
- .getEndOffset() - 1;
- document.insertString(offset,"\n",null);
- document.insertString(offset + 1,selectedText
- .substring(currNewline + 1),null);
- }
- }
- else
- {
- document.remove(selectionStart,
- selectionEnd - selectionStart);
- if(selectedText != null)
- {
- document.insertString(selectionStart,
- selectedText,null);
- }
- }
- }
- catch(BadLocationException bl)
- {
- bl.printStackTrace();
- throw new InternalError("Cannot replace"
- + " selection");
- }
- // No matter what happends... stops us from leaving document
- // in a bad state
- finally
- {
- document.endCompoundEdit();
- }
-
- setCaretPosition(selectionEnd);
- }
-
- /**
- * Returns true if this text area is editable, false otherwise.
- */
- public final boolean isEditable()
- {
- return editable;
- }
-
- /**
- * Sets if this component is editable.
- * @param editable True if this text area should be editable,
- * false otherwise
- */
- public final void setEditable(boolean editable)
- {
- this.editable = editable;
- }
-
- /**
- * Returns the right click popup menu.
- */
- public final JPopupMenu getRightClickPopup()
- {
- return popup;
- }
-
- /**
- * Sets the right click popup menu.
- * @param popup The popup
- */
- //public final void setRightClickPopup(EditPopupMenu popup)
- public final void setRightClickPopup(JPopupMenu popup)
- {
- this.popup = popup;
- }
-
-
- /**
- * Returns the `magic' caret position. This can be used to preserve
- * the column position when moving up and down lines.
- */
- public final int getMagicCaretPosition()
- {
- return magicCaret;
- }
-
- /**
- * Sets the `magic' caret position. This can be used to preserve
- * the column position when moving up and down lines.
- * @param magicCaret The magic caret position
- */
- public final void setMagicCaretPosition(int magicCaret)
- {
- this.magicCaret = magicCaret;
- }
-
- /**
- * Similar to setSelectedText()
, but overstrikes the
- * appropriate number of characters if overwrite mode is enabled.
- * @param str The string
- * @see #setSelectedText(String)
- * @see #isOverwriteEnabled()
- */
- public void overwriteSetSelectedText(String str)
- {
- // Don't overstrike if there is a selection
- if(!overwrite || selectionStart != selectionEnd)
- {
- setSelectedText(str);
- return;
- }
-
- // Don't overstrike if we're on the end of
- // the line
- int caret = getCaretPosition();
- int caretLineEnd = getLineStopOffset(getCaretLine());
- if(caretLineEnd - caret <= str.length())
- {
- setSelectedText(str);
- return;
- }
-
- document.beginCompoundEdit();
-
- try
- {
- document.remove(caret,str.length());
- document.insertString(caret,str,null);
- }
- catch(BadLocationException bl)
- {
- bl.printStackTrace();
- }
- finally
- {
- document.endCompoundEdit();
- }
- }
-
- /**
- * Returns true if overwrite mode is enabled, false otherwise.
- */
- public final boolean isOverwriteEnabled()
- {
- return overwrite;
- }
-
- /**
- * Sets if overwrite mode should be enabled.
- * @param overwrite True if overwrite mode should be enabled,
- * false otherwise.
- */
- public final void setOverwriteEnabled(boolean overwrite)
- {
- this.overwrite = overwrite;
- painter.invalidateSelectedLines();
- }
-
- /**
- * Returns true if the selection is rectangular, false otherwise.
- */
- public final boolean isSelectionRectangular()
- {
- return rectSelect;
- }
-
- /**
- * Sets if the selection should be rectangular.
- * @param rectSelect True if the selection should be rectangular,
- * false otherwise.
- */
- public final void setSelectionRectangular(boolean rectSelect)
- {
- this.rectSelect = rectSelect;
- painter.invalidateSelectedLines();
- }
-
- /**
- * Returns the position of the highlighted bracket (the bracket
- * matching the one before the caret)
- */
- public final int getBracketPosition()
- {
- return bracketPosition;
- }
-
- /**
- * Returns the line of the highlighted bracket (the bracket
- * matching the one before the caret)
- */
- public final int getBracketLine()
- {
- return bracketLine;
- }
-
- /**
- * Adds a caret change listener to this text area.
- * @param listener The listener
- */
- public final void addCaretListener(CaretListener listener)
- {
- eventListenerList.add(CaretListener.class,listener);
- }
-
- /**
- * Removes a caret change listener from this text area.
- * @param listener The listener
- */
- public final void removeCaretListener(CaretListener listener)
- {
- eventListenerList.remove(CaretListener.class,listener);
- }
-
- /**
- * Deletes the selected text from the text area and places it
- * into the clipboard.
- */
- public void cut()
- {
- if(editable)
- {
- copy();
- setSelectedText("");
- }
- }
-
- /**
- * Places the selected text into the clipboard.
- */
- public void copy()
- {
- if(selectionStart != selectionEnd)
- {
- Clipboard clipboard = getToolkit().getSystemClipboard();
-
- String selection = getSelectedText();
-
- int repeatCount = inputHandler.getRepeatCount();
- StringBuffer buf = new StringBuffer();
- for(int i = 0; i < repeatCount; i++)
- buf.append(selection);
-
- Transferable t = new StringSelection(buf.toString());
- clipboard.setContents(t, null);
-
- Clipboard unixclipboard = getToolkit().getSystemSelection();
- if (unixclipboard != null) unixclipboard.setContents(t, null);
- }
- }
-
- /**
- * Inserts the clipboard contents into the text.
- */
- public void paste() {
- if (editable) {
- Clipboard clipboard = getToolkit().getSystemClipboard();
- try {
- // The MacOS MRJ doesn't convert \r to \n, so do it here
- String selection = ((String)clipboard.getContents(this).getTransferData(DataFlavor.stringFlavor)).replace('\r','\n');
-
- // particularly on macosx when pasting from safari,
- // replace unicode x00A0 (non-breaking space)
- // with just a plain space. [fry 030929]
- selection = selection.replace('\u00A0', ' ');
-
- int repeatCount = inputHandler.getRepeatCount();
- StringBuffer buf = new StringBuffer();
- for (int i = 0; i < repeatCount; i++)
- buf.append(selection);
- selection = buf.toString();
- setSelectedText(selection);
-
- } catch(Exception e) {
- getToolkit().beep();
- System.err.println("Clipboard does not contain a string");
- }
- }
- }
-
- /**
- * Called by the AWT when this component is removed from it's parent.
- * This stops clears the currently focused component.
- */
- public void removeNotify()
- {
- super.removeNotify();
- if(focusedComponent == this)
- focusedComponent = null;
- }
-
- /**
- * Forwards key events directly to the input handler.
- * This is slightly faster than using a KeyListener
- * because some Swing overhead is avoided.
- */
- public EditorListener editorListener;
-
- /**
- * The component that tracks the current line number.
- */
- public EditorLineStatus editorLineStatus;
-
-
- public void processKeyEvent(KeyEvent evt) {
- // this had to be added in Processing 007X, because the menu key
- // events weren't making it up to the frame.
- super.processKeyEvent(evt);
-
- //System.out.println("jedittextarea: " + evt);
- //System.out.println();
- if (inputHandler == null) return;
-
- switch(evt.getID()) {
- case KeyEvent.KEY_TYPED:
- if ((editorListener == null) || !editorListener.keyTyped(evt)) {
- inputHandler.keyTyped(evt);
- }
- break;
- case KeyEvent.KEY_PRESSED:
- if ((editorListener == null) || !editorListener.keyPressed(evt)) {
- inputHandler.keyPressed(evt);
- }
- break;
- case KeyEvent.KEY_RELEASED:
- inputHandler.keyReleased(evt);
- break;
- }
- }
-
- // protected members
- protected static String LEFT = "left";
- protected static String CENTER = "center";
- protected static String RIGHT = "right";
- protected static String BOTTOM = "bottom";
-
- protected static JEditTextArea focusedComponent;
- protected static Timer caretTimer;
-
- protected TextAreaPainter painter;
- protected TextAreaLineNumbers editorLineNumbers;
-
- //protected EditPopupMenu popup;
- protected JPopupMenu popup;
-
- protected EventListenerList eventListenerList;
- protected MutableCaretEvent caretEvent;
-
- protected boolean caretBlinks;
- protected boolean caretVisible;
- protected boolean blink;
-
- protected boolean editable;
-
- protected int firstLine;
- protected int visibleLines;
- protected int electricScroll;
-
- protected int horizontalOffset;
-
- protected JScrollBar vertical;
- protected JScrollBar horizontal;
- protected boolean scrollBarsInitialized;
-
- protected InputHandler inputHandler;
- protected SyntaxDocument document;
- protected DocumentHandler documentHandler;
-
- protected Segment lineSegment;
-
- protected int selectionStart;
- protected int selectionStartLine;
- protected int selectionEnd;
- protected int selectionEndLine;
- protected boolean biasLeft;
-
- protected int newSelectionStart; // hack to get around lack of multiple returns in Java
- protected int newSelectionEnd;
-
- protected boolean selectWord;
- protected boolean selectLine;
- protected int selectionAncorStart;
- protected int selectionAncorEnd;
-
- protected int bracketPosition;
- protected int bracketLine;
-
- protected int magicCaret;
- protected boolean overwrite;
- protected boolean rectSelect;
-
-
- protected void fireCaretEvent()
- {
- Object[] listeners = eventListenerList.getListenerList();
- for(int i = listeners.length - 2; i >= 0; i--)
- {
- if(listeners[i] == CaretListener.class)
- {
- ((CaretListener)listeners[i+1]).caretUpdate(caretEvent);
- }
- }
- }
-
- protected void updateBracketHighlight(int newCaretPosition)
- {
- if(newCaretPosition == 0)
- {
- bracketPosition = bracketLine = -1;
- return;
- }
-
- try
- {
- int offset = TextUtilities.findMatchingBracket(
- document,newCaretPosition - 1);
- if(offset != -1)
- {
- bracketLine = getLineOfOffset(offset);
- bracketPosition = offset - getLineStartOffset(bracketLine);
- return;
- }
- }
- catch(BadLocationException bl)
- {
- bl.printStackTrace();
- }
-
- bracketLine = bracketPosition = -1;
- }
-
- protected void documentChanged(DocumentEvent evt)
- {
- DocumentEvent.ElementChange ch =
- evt.getChange(document.getDefaultRootElement());
-
- int count;
- if(ch == null)
- count = 0;
- else
- count = ch.getChildrenAdded().length -
- ch.getChildrenRemoved().length;
-
- int line = getLineOfOffset(evt.getOffset());
- if(count == 0)
- {
- painter.invalidateLine(line);
- }
- // do magic stuff
- else if(line < firstLine)
- {
- setFirstLine(firstLine + count);
- }
- // end of magic stuff
- else
- {
- painter.invalidateLineRange(line,firstLine + visibleLines);
- updateScrollBars();
- }
- }
-
- class ScrollLayout implements LayoutManager
- {
- //final int LEFT_EXTRA = 5;
-
- public void addLayoutComponent(String name, Component comp)
- {
- if(name.equals(LEFT))
- left = comp;
- else if(name.equals(CENTER))
- center = comp;
- else if(name.equals(RIGHT))
- right = comp;
- else if(name.equals(BOTTOM))
- bottom = comp;
- else if(name.equals(LEFT_OF_SCROLLBAR))
- leftOfScrollBar.addElement(comp);
- }
-
- public void removeLayoutComponent(Component comp)
- {
- if(left == comp)
- left = null;
- if(center == comp)
- center = null;
- if(right == comp)
- right = null;
- if(bottom == comp)
- bottom = null;
- else
- leftOfScrollBar.removeElement(comp);
- }
-
- public Dimension preferredLayoutSize(Container parent)
- {
- Dimension dim = new Dimension();
- Insets insets = getInsets();
- dim.width = insets.left + insets.right;
- dim.height = insets.top + insets.bottom;
-
- Dimension centerPref = center.getPreferredSize();
- dim.width += centerPref.width;
- dim.height += centerPref.height;
- Dimension leftPref = left.getPreferredSize();
- dim.width += leftPref.width;
- Dimension rightPref = right.getPreferredSize();
- dim.width += rightPref.width;
- Dimension bottomPref = bottom.getPreferredSize();
- dim.height += bottomPref.height;
-
- return dim;
- }
-
- public Dimension minimumLayoutSize(Container parent)
- {
- Dimension dim = new Dimension();
- Insets insets = getInsets();
- dim.width = insets.left + insets.right;
- dim.height = insets.top + insets.bottom;
-
- Dimension centerPref = center.getMinimumSize();
- dim.width += centerPref.width;
- dim.height += centerPref.height;
- Dimension leftPref = left.getMinimumSize();
- dim.width += leftPref.width;
- Dimension rightPref = right.getMinimumSize();
- dim.width += rightPref.width;
- Dimension bottomPref = bottom.getMinimumSize();
- dim.height += bottomPref.height;
-
- dim.height += 5;
-
- return dim;
- }
-
- public void layoutContainer(Container parent)
- {
- Dimension size = parent.getSize();
- Insets insets = parent.getInsets();
- int itop = insets.top;
- int ileft = insets.left;
- int ibottom = insets.bottom;
- int iright = insets.right;
-
- int leftWidth = left.getSize().width;
- int rightWidth = right.getPreferredSize().width;
- int bottomHeight = bottom.getPreferredSize().height;
- int centerWidth = size.width - leftWidth - rightWidth - ileft - iright;
- int centerHeight = size.height - bottomHeight - itop - ibottom;
-
- left.setBounds(ileft,
- itop,
- leftWidth,
- centerHeight);
-
- ileft += leftWidth;
-
- center.setBounds(ileft, // + LEFT_EXTRA,
- itop,
- centerWidth, // - LEFT_EXTRA,
- centerHeight);
-
- right.setBounds(ileft + centerWidth,
- itop,
- rightWidth,
- centerHeight);
-
- // Lay out all status components, in order
- Enumeration status = leftOfScrollBar.elements();
- while (status.hasMoreElements()) {
- Component comp = (Component)status.nextElement();
- Dimension dim = comp.getPreferredSize();
- comp.setBounds(ileft,
- itop + centerHeight,
- dim.width,
- bottomHeight);
- ileft += dim.width;
- }
-
- bottom.setBounds(ileft,
- itop + centerHeight,
- size.width - rightWidth - ileft - iright,
- bottomHeight);
- }
-
- // private members
- private Component left;
- private Component center;
- private Component right;
- private Component bottom;
- private Vector leftOfScrollBar = new Vector();
- }
-
- static class CaretBlinker implements ActionListener
- {
- public void actionPerformed(ActionEvent evt)
- {
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- if(focusedComponent != null
- && focusedComponent.hasFocus())
- focusedComponent.blinkCaret();
- }
- });
- }
- }
-
- class MutableCaretEvent extends CaretEvent
- {
- MutableCaretEvent()
- {
- super(JEditTextArea.this);
- }
-
- public int getDot()
- {
- return getCaretPosition();
- }
-
- public int getMark()
- {
- return getMarkPosition();
- }
- }
-
-/*
-#ifdef JDK14
- class WheelHandler implements MouseWheelListener {
-
- public void mouseWheelMoved(MouseWheelEvent e) {
- if (!scrollBarsInitialized) return;
-
- int amt = e.getWheelRotation();
- //System.out.println(amt);
- vertical.setValue(vertical.getValue() + amt * wheelMultiplier);
- }
- }
-#endif
-*/
-
- class AdjustHandler implements AdjustmentListener
- {
- public void adjustmentValueChanged(final AdjustmentEvent evt)
- {
- if(!scrollBarsInitialized)
- return;
-
- // If this is not done, mousePressed events accumilate
- // and the result is that scrolling doesn't stop after
- // the mouse is released
- SwingUtilities.invokeLater(new Runnable() {
- public void run()
- {
- if(evt.getAdjustable() == vertical)
- setFirstLine(vertical.getValue());
- else
- setHorizontalOffset(-horizontal.getValue());
- }
- });
- }
- }
-
- class ComponentHandler extends ComponentAdapter
- {
- public void componentResized(ComponentEvent evt)
- {
- recalculateVisibleLines();
- scrollBarsInitialized = true;
- }
- }
-
- class DocumentHandler implements DocumentListener
- {
- public void insertUpdate(DocumentEvent evt)
- {
- documentChanged(evt);
-
- int offset = evt.getOffset();
- int length = evt.getLength();
-
- int newStart;
- int newEnd;
-
- if (selectionStart > offset ||
- (selectionStart == selectionEnd && selectionStart == offset))
- newStart = selectionStart + length;
- else
- newStart = selectionStart;
-
- if(selectionEnd >= offset)
- newEnd = selectionEnd + length;
- else
- newEnd = selectionEnd;
-
- select(newStart,newEnd);
- }
-
- public void removeUpdate(DocumentEvent evt)
- {
- documentChanged(evt);
-
- int offset = evt.getOffset();
- int length = evt.getLength();
-
- int newStart;
- int newEnd;
-
- if(selectionStart > offset)
- {
- if(selectionStart > offset + length)
- newStart = selectionStart - length;
- else
- newStart = offset;
- }
- else
- newStart = selectionStart;
-
- if(selectionEnd > offset)
- {
- if(selectionEnd > offset + length)
- newEnd = selectionEnd - length;
- else
- newEnd = offset;
- }
- else
- newEnd = selectionEnd;
-
- select(newStart,newEnd);
- }
-
- public void changedUpdate(DocumentEvent evt)
- {
- }
- }
-
- class DragHandler implements MouseMotionListener
- {
- public void mouseDragged(MouseEvent evt)
- {
- if (popup != null && popup.isVisible()) return;
-
- if ( !selectWord && !selectLine ) {
- setSelectionRectangular((evt.getModifiers()
- & InputEvent.CTRL_MASK) != 0);
- select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
- } else {
- int line = yToLine(evt.getY());
- if ( selectWord ) {
- setNewSelectionWord( line, xToOffset(line,evt.getX()) );
- } else {
- newSelectionStart = getLineStartOffset(line);
- newSelectionEnd = getSafeLineStopOffset(line);
- }
- if ( newSelectionStart < selectionAncorStart ) {
- select(newSelectionStart,selectionAncorEnd);
- } else if ( newSelectionEnd > selectionAncorEnd ) {
- select(selectionAncorStart,newSelectionEnd);
- } else {
- select(newSelectionStart,newSelectionEnd);
- }
- }
- }
-
- final Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
- final Cursor handCursor = new Cursor(Cursor.HAND_CURSOR);
-
- public void mouseMoved(MouseEvent evt) {
- int line = yToLine(evt.getY());
- int offset = xToOffset(line, evt.getX());
- boolean wantHandCursor = checkClickedURL(getLineText(line), offset) != null;
- JComponent src = (JComponent) evt.getSource();
- if (wantHandCursor)
- src.setCursor(handCursor);
- else
- src.setCursor(normalCursor);
- }
- }
-
- class FocusHandler implements FocusListener
- {
- public void focusGained(FocusEvent evt)
- {
- //System.out.println("JEditTextArea: focusGained");
- setCaretVisible(true);
- focusedComponent = JEditTextArea.this;
- }
-
- public void focusLost(FocusEvent evt)
- {
- //System.out.println("JEditTextArea: focusLost");
- setCaretVisible(false);
- focusedComponent = null;
- }
- }
-
- public String checkClickedURL(String line, int offset) {
- String[] parse = SyntaxUtilities.parseCommentUrls(line);
- if (parse==null)
- return null;
- int start = parse[0].length();
- int stop = start + parse[1].length();
- if (offsetKeywordMap
is similar to a hashtable in that it maps keys
- * to values. However, the `keys' are Swing segments. This allows lookups of
- * text substrings without the overhead of creating a new string object.
- * CTokenMarker
to map keywords to ids.
- *
- * @author Slava Pestov, Mike Dillon
- */
-public class KeywordMap
-{
- /**
- * Creates a new KeywordMap
.
- * @param ignoreCase True if keys are case insensitive
- */
- public KeywordMap(boolean ignoreCase)
- {
- this(ignoreCase, 52);
- this.ignoreCase = ignoreCase;
- }
-
- /**
- * Creates a new KeywordMap
.
- * @param ignoreCase True if the keys are case insensitive
- * @param mapLength The number of `buckets' to create.
- * A value of 52 will give good performance for most maps.
- */
- public KeywordMap(boolean ignoreCase, int mapLength)
- {
- this.mapLength = mapLength;
- this.ignoreCase = ignoreCase;
- map = new Keyword[mapLength];
- }
-
- /**
- * Looks up a key.
- * @param text The text segment
- * @param offset The offset of the substring within the text segment
- * @param length The length of the substring
- */
- public byte lookup(Segment text, int offset, int length)
- {
- if(length == 0)
- return Token.NULL;
- Keyword k = map[getSegmentMapKey(text, offset, length)];
- while(k != null)
- {
- if(length != k.keyword.length)
- {
- k = k.next;
- continue;
- }
- if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
- k.keyword))
- return k.id;
- k = k.next;
- }
- return Token.NULL;
- }
-
- /**
- * Adds a key-value mapping.
- * @param keyword The key
- * @param id The value
- */
- public void add(String keyword, byte id)
- {
- int key = getStringMapKey(keyword);
- map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
- }
-
- /**
- * Returns true if the keyword map is set to be case insensitive,
- * false otherwise.
- */
- public boolean getIgnoreCase()
- {
- return ignoreCase;
- }
-
- /**
- * Sets if the keyword map should be case insensitive.
- * @param ignoreCase True if the keyword map should be case
- * insensitive, false otherwise
- */
- public void setIgnoreCase(boolean ignoreCase)
- {
- this.ignoreCase = ignoreCase;
- }
-
- // protected members
- protected int mapLength;
-
- protected int getStringMapKey(String s)
- {
- return (Character.toUpperCase(s.charAt(0)) +
- Character.toUpperCase(s.charAt(s.length()-1)))
- % mapLength;
- }
-
- protected int getSegmentMapKey(Segment s, int off, int len)
- {
- return (Character.toUpperCase(s.array[off]) +
- Character.toUpperCase(s.array[off + len - 1]))
- % mapLength;
- }
-
- // private members
- class Keyword
- {
- public Keyword(char[] keyword, byte id, Keyword next)
- {
- this.keyword = keyword;
- this.id = id;
- this.next = next;
- }
-
- public char[] keyword;
- public byte id;
- public Keyword next;
- }
-
- private Keyword[] map;
- private boolean ignoreCase;
-}
diff --git a/app/src/processing/app/syntax/PdeKeywords.java b/app/src/processing/app/syntax/PdeKeywords.java
old mode 100644
new mode 100755
index ccf52531cfd..84868ee7382
--- a/app/src/processing/app/syntax/PdeKeywords.java
+++ b/app/src/processing/app/syntax/PdeKeywords.java
@@ -24,58 +24,59 @@
package processing.app.syntax;
-import processing.app.*;
-import processing.app.legacy.PApplet;
-import processing.app.packages.Library;
-
-import java.io.*;
-import java.util.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import org.fife.ui.rsyntaxtextarea.TokenTypes;
-public class PdeKeywords extends CTokenMarker {
+import processing.app.Base;
+import processing.app.legacy.PApplet;
+import processing.app.packages.Library;
- // lookup table for the TokenMarker subclass, handles coloring
- static KeywordMap keywordColoring;
- // lookup table that maps keywords to their html reference pages
- static Hashtable keywordToReference;
+public class PdeKeywords {
- public PdeKeywords() {
- super(false, getKeywords());
+ // Value is org.fife.ui.rsyntaxtextarea.TokenTypes
+ private static HashMap
+ * Only well ugly syntax errors will be caught (because of the nature of the analysis to be made).
+ * @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ */
+public class SyntaxErrorMarker extends AbstractParser implements LibraryIndexListener {
+
+ private TLibrary sketchLibrary;
+ private DefaultParseResult result;
+ private SketchTextArea textarea;
+
+ // TODO: this can be removed on fix: https://github.com/bobbylight/RSyntaxTextArea/issues/87
+ private Gutter gutter;
+ private ListSegment
is equal to a
- * string.
- * @param ignoreCase True if case should be ignored, false otherwise
- * @param text The segment
- * @param offset The offset into the segment
- * @param match The string to match
- */
- public static boolean regionMatches(boolean ignoreCase, Segment text,
- int offset, String match)
- {
- int length = offset + match.length();
- char[] textArray = text.array;
- if(length > text.offset + text.count)
- return false;
- for(int i = offset, j = 0; i < length; i++, j++)
- {
- char c1 = textArray[i];
- char c2 = match.charAt(j);
- if(ignoreCase)
- {
- c1 = Character.toUpperCase(c1);
- c2 = Character.toUpperCase(c2);
- }
- if(c1 != c2)
- return false;
- }
- return true;
- }
-
-
- /**
- * Checks if a subregion of a Segment
is equal to a
- * character array.
- * @param ignoreCase True if case should be ignored, false otherwise
- * @param text The segment
- * @param offset The offset into the segment
- * @param match The character array to match
- */
- public static boolean regionMatches(boolean ignoreCase, Segment text,
- int offset, char[] match)
- {
- int length = offset + match.length;
- char[] textArray = text.array;
- if(length > text.offset + text.count)
- return false;
- for(int i = offset, j = 0; i < length; i++, j++)
- {
- char c1 = textArray[i];
- char c2 = match[j];
- if(ignoreCase)
- {
- c1 = Character.toUpperCase(c1);
- c2 = Character.toUpperCase(c2);
- }
- if(c1 != c2)
- return false;
- }
- return true;
- }
-
-
- /**
- * Returns the default style table. This can be passed to the
- * setStyles()
method of SyntaxDocument
- * to use the default syntax styles.
- */
- public static SyntaxStyle[] getDefaultSyntaxStyles()
- {
- SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
-
- styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false,false);
- styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false,false);
- styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true,false);
- styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false,false);
- styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false,false);
- styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false,false);
- styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true,false);
- styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true,false);
- styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true,false);
- styles[Token.URL] = new SyntaxStyle(Color.blue,true,false,false);
- styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true,false);
-
- return styles;
- }
-
-
- /**
- * Paints the specified line onto the graphics context. Note that this
- * method munges the offset and count values of the segment.
- * @param line The line segment
- * @param tokens The token list for the line
- * @param styles The syntax style list
- * @param expander The tab expander used to determine tab stops. May
- * be null
- * @param gfx The graphics context
- * @param x The x co-ordinate
- * @param y The y co-ordinate
- * @return The x co-ordinate, plus the width of the painted string
- */
- public static int paintSyntaxLine(Segment line, Token tokens,
- SyntaxStyle[] styles,
- TabExpander expander, Graphics gfx,
- int x, int y)
- {
- Font defaultFont = gfx.getFont();
- Color defaultColor = gfx.getColor();
-
- for(;;)
- {
- byte id = tokens.id;
- if(id == Token.END)
- break;
-
- int length = tokens.length;
- if(id == Token.NULL)
- {
- if(!defaultColor.equals(gfx.getColor()))
- gfx.setColor(defaultColor);
- if(!defaultFont.equals(gfx.getFont()))
- gfx.setFont(defaultFont);
- }
- else
- styles[id].setGraphicsFlags(gfx,defaultFont);
-
- line.count = length;
- if (id == Token.COMMENT1 || id == Token.COMMENT2)
- x = drawTabbedCommentsText(line, x, y, gfx, expander, styles, styles[id]);
- else
- x = Utilities.drawTabbedText(line, x, y, gfx, expander, 0);
- line.offset += length;
-
- tokens = tokens.next;
- }
-
- return x;
- }
-
- /**
- * Parse comments and identify "@schematics <something>" pattern.
- *
- * @param line
- * A string to parse
- * @return null if the pattern is not found, otherwise an array of
- * String is returned: the elements with index 0, 1 and 2 are
- * respectively the preamble, the <something> stuff, and
- * the remaining part of the string.
- */
- public static String[] parseCommentUrls(String line) {
- Matcher m = urlPattern.matcher(line.toString());
- if (!m.find())
- return null;
-
- String res[] = new String[3];
- res[0] = line.substring(0, m.start(1));
- res[1] = line.substring(m.start(1), m.end(1));
- res[2] = line.substring(m.end(1));
- // System.out.println("0 =>"+res[0]+"<\n1 =>"+res[1]+"< \n2 =>"+res[2]+"<");
- return res;
- }
-
- static private Pattern urlPattern = Pattern.compile(
- "((?:https?|ftp)://" + // ( Protocol
- "(?:(?:[\\w_\\-]+:)?[\\w_\\-]+@)?" + // Username and password
- "(?:[\\w_\\-]+\\.)+[\\w_\\-]+" + // Domain name
- "(?::[0-9]{1,5})?" + // Port
- "(?:/[\\w_\\-./?%&=+]*)?)" + // Path )
- "(?:\\s|$)"); // whitespace or EOL
-
- public static Segment stringToSegment(String v) {
- return new Segment(v.toCharArray(), 0, v.length());
- }
-
- private static int drawTabbedCommentsText(Segment line, int x, int y,
- Graphics gfx, TabExpander expander, SyntaxStyle[] styles,
- SyntaxStyle commentStyle) {
-
- String parse[] = parseCommentUrls(line.toString());
- if (parse == null)
- // Revert to plain writing.
- return Utilities.drawTabbedText(line, x, y, gfx, expander, 0);
- Segment pre = stringToSegment(parse[0]);
- Segment tag = stringToSegment(parse[1]);
- Segment post = stringToSegment(parse[2]);
-
- if (pre.count>0)
- x = Utilities.drawTabbedText(pre, x, y, gfx, expander, 0);
-
- Font f = gfx.getFont();
- styles[Token.URL].setGraphicsFlags(gfx, f);
- x = Utilities.drawTabbedText(tag, x, y, gfx, expander, 0);
-
- commentStyle.setGraphicsFlags(gfx, f);
- if (post.count>0)
- x = Utilities.drawTabbedText(post, x, y, gfx, expander, 0);
- return x;
- }
-
- // private members
- private SyntaxUtilities() {}
-}
diff --git a/app/src/processing/app/syntax/TextAreaDefaults.java b/app/src/processing/app/syntax/TextAreaDefaults.java
deleted file mode 100644
index c2e878578db..00000000000
--- a/app/src/processing/app/syntax/TextAreaDefaults.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * TextAreaDefaults.java - Encapsulates default values for various settings
- * Copyright (C) 1999 Slava Pestov
- *
- * You may use and modify this package for any purpose. Redistribution is
- * permitted, in both source and binary form, provided that this notice
- * remains intact in all source distributions of this package.
- */
-
-package processing.app.syntax;
-
-import java.awt.*;
-//import javax.swing.JPopupMenu;
-
-/**
- * Encapsulates default settings for a text area. This can be passed
- * to the constructor once the necessary fields have been filled out.
- * The advantage of doing this over calling lots of set() methods after
- * creating the text area is that this method is faster.
- */
-public class TextAreaDefaults
-{
- private static TextAreaDefaults DEFAULTS;
-
- public InputHandler inputHandler;
- public SyntaxDocument document;
- public boolean editable;
-
- public boolean caretVisible;
- public boolean caretBlinks;
- public boolean blockCaret;
- public int electricScroll;
-
- public int cols;
- public int rows;
- public SyntaxStyle[] styles;
- public Color caretColor;
- public Color selectionColor;
- public Color lineHighlightColor;
- public boolean lineHighlight;
- public Color bracketHighlightColor;
- public boolean bracketHighlight;
- public Color eolMarkerColor;
- public boolean eolMarkers;
- public boolean paintInvalid;
-
-
- // moved from TextAreaPainter [fry]
- public Font font;
- public Color fgcolor;
- public Color bgcolor;
-
- //public JPopupMenu popup;
-
-
- /**
- * Returns a new TextAreaDefaults object with the default values filled
- * in.
- */
- public static TextAreaDefaults getDefaults()
- {
- if (DEFAULTS == null) {
- DEFAULTS = new TextAreaDefaults();
-
- DEFAULTS.inputHandler = new DefaultInputHandler();
- DEFAULTS.inputHandler.addDefaultKeyBindings();
- DEFAULTS.document = new SyntaxDocument();
- DEFAULTS.editable = true;
-
- DEFAULTS.caretVisible = true;
- DEFAULTS.caretBlinks = true;
- DEFAULTS.electricScroll = 3;
-
- DEFAULTS.cols = 80;
- DEFAULTS.rows = 25;
- DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
- DEFAULTS.caretColor = Color.red;
- DEFAULTS.selectionColor = new Color(0xccccff);
- DEFAULTS.lineHighlightColor = new Color(0xe0e0e0);
- DEFAULTS.lineHighlight = true;
- DEFAULTS.bracketHighlightColor = Color.black;
- DEFAULTS.bracketHighlight = true;
- DEFAULTS.eolMarkerColor = new Color(0x009999);
- DEFAULTS.eolMarkers = true;
- DEFAULTS.paintInvalid = true;
- }
-
- return DEFAULTS;
- }
-}
diff --git a/app/src/processing/app/syntax/TextAreaLineNumbers.java b/app/src/processing/app/syntax/TextAreaLineNumbers.java
deleted file mode 100644
index 39f7438f281..00000000000
--- a/app/src/processing/app/syntax/TextAreaLineNumbers.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * TextAreaLineNumbers.java - Show line numbers for the open file in the editor
- * Copyright (C) 2013 Cayci Gorlitsky
- *
- * You may use and modify this package for any purpose. Redistribution is
- * permitted, in both source and binary form, provided that this notice
- * remains intact in all source distributions of this package.
- */
-
-package processing.app.syntax;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Rectangle;
-
-import javax.swing.border.MatteBorder;
-
-public class TextAreaLineNumbers extends TextAreaPainter {
-
- private final int LEFT_INDENT = 6;
- private final int RIGHT_INDENT = 6;
- private final int RIGHT_BORDER_WIDTH = 1;
- private final int PADDING_WIDTH = LEFT_INDENT + RIGHT_INDENT + RIGHT_BORDER_WIDTH;
-
- private final int MIN_WIDTH;
- private final int DIGIT_WIDTH;
- private final int MIN_NUM_DIGITS = 2;
-
- private int currStartNum = 0;
- private int currEndNum = 0;
- private int currNumDigits = MIN_NUM_DIGITS;
-
-
-
- public TextAreaLineNumbers(JEditTextArea textArea, TextAreaDefaults defaults) {
- super(textArea, defaults);
- DIGIT_WIDTH = getFontMetrics(getFont()).stringWidth("0");
- MIN_WIDTH = DIGIT_WIDTH * MIN_NUM_DIGITS + PADDING_WIDTH;
- setEnabled(false);
- setBorder(new MatteBorder(0, 0, 0, RIGHT_BORDER_WIDTH, new Color(240, 240, 240)));
- }
-
- public void updateLineNumbers(int startNum, int endNum) {
- if (currStartNum == startNum && currEndNum == endNum) {
- return;
- }
- currStartNum = startNum;
- currEndNum = endNum;
-
- invalidate();
- repaint();
- }
-
- @Override
- public void paint(Graphics gfx) {
- super.paint(gfx);
- getBorder().paintBorder(this, gfx, 0, 0, getSize().width, getSize().height);
- }
-
- @Override
- protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
- int line, int x)
- {
- currentLineIndex = line;
- gfx.setFont(getFont());
- gfx.setColor(Color.GRAY);
- int y = textArea.lineToY(line);
- int startX = getBounds().x + getBounds().width;
- if (line >= 0 && line < textArea.getLineCount()) {
- String lineNumberString = String.valueOf(line+1);
- int lineStartX = startX - RIGHT_BORDER_WIDTH - RIGHT_INDENT - fm.stringWidth(lineNumberString);
- gfx.drawString(lineNumberString,lineStartX,y + fm.getHeight());
- }
- }
-
- public void updateWidthForNumDigits(int numDigits) {
- if (currNumDigits == numDigits) {
- return;
- }
- currNumDigits = numDigits;
-
- if (isVisible()) {
- updateBounds();
- invalidate();
- repaint();
- }
- }
-
- public void setDisplayLineNumbers(boolean displayLineNumbers) {
- setVisible(displayLineNumbers);
- if (displayLineNumbers) {
- updateBounds();
- } else {
- setBounds(new Rectangle(0, getHeight()));
- }
- invalidate();
- repaint();
- }
-
- private void updateBounds() {
- if (isVisible()) {
- setBounds(new Rectangle(Math.max(MIN_WIDTH, DIGIT_WIDTH * currNumDigits + PADDING_WIDTH), getHeight()));
- textArea.validate();
- }
- }
-}
diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java
deleted file mode 100644
index e9932952604..00000000000
--- a/app/src/processing/app/syntax/TextAreaPainter.java
+++ /dev/null
@@ -1,787 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- * TextAreaPainter.java - Paints the text area
- * Copyright (C) 1999 Slava Pestov
- *
- * You may use and modify this package for any purpose. Redistribution is
- * permitted, in both source and binary form, provided that this notice
- * remains intact in all source distributions of this package.
- */
-
-package processing.app.syntax;
-
-import processing.app.*;
-import processing.app.syntax.im.CompositionTextPainter;
-
-import javax.swing.ToolTipManager;
-import javax.swing.text.*;
-import javax.swing.JComponent;
-import java.awt.event.MouseEvent;
-import java.awt.*;
-import java.awt.print.*;
-
-/**
- * The text area repaint manager. It performs double buffering and paints
- * lines of text.
- * @author Slava Pestov
- */
-public class TextAreaPainter extends JComponent
-implements TabExpander, Printable
-{
- /** True if inside printing, will handle disabling the highlight */
- boolean printing;
- /** Current setting for editor.antialias preference */
- boolean antialias;
-
- /** A specific painter composed by the InputMethod.*/
- protected CompositionTextPainter compositionTextPainter;
-
- /**
- * Creates a new repaint manager. This should be not be called
- * directly.
- */
- public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
- {
- this.textArea = textArea;
-
- setAutoscrolls(true);
- setDoubleBuffered(true);
- setOpaque(true);
-
- ToolTipManager.sharedInstance().registerComponent(this);
-
- currentLine = new Segment();
- currentLineIndex = -1;
-
- setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
-
- setFont(defaults.font);
- setForeground(defaults.fgcolor);
- setBackground(defaults.bgcolor);
-
- antialias = Preferences.getBoolean("editor.antialias");
-
- blockCaret = defaults.blockCaret;
- styles = defaults.styles;
- cols = defaults.cols;
- rows = defaults.rows;
- caretColor = defaults.caretColor;
- selectionColor = defaults.selectionColor;
- lineHighlightColor = defaults.lineHighlightColor;
- lineHighlight = defaults.lineHighlight;
- bracketHighlightColor = defaults.bracketHighlightColor;
- bracketHighlight = defaults.bracketHighlight;
- paintInvalid = defaults.paintInvalid;
- eolMarkerColor = defaults.eolMarkerColor;
- eolMarkers = defaults.eolMarkers;
- }
-
- /**
- * Get CompositionTextPainter. if CompositionTextPainter is not created, create it.
- */
- public CompositionTextPainter getCompositionTextpainter(){
- if(compositionTextPainter == null){
- compositionTextPainter = new CompositionTextPainter(textArea);
- }
- return compositionTextPainter;
- }
-
- /**
- * Returns if this component can be traversed by pressing the
- * Tab key. This returns false.
- */
-// public final boolean isManagingFocus()
-// {
-// return false;
-// }
-
- /**
- * Returns the syntax styles used to paint colorized text. Entry n
- * will be used to paint tokens with id = n.
- * @see processing.app.syntax.Token
- */
- public final SyntaxStyle[] getStyles()
- {
- return styles;
- }
-
- /**
- * Sets the syntax styles used to paint colorized text. Entry n
- * will be used to paint tokens with id = n.
- * @param styles The syntax styles
- * @see processing.app.syntax.Token
- */
- public final void setStyles(SyntaxStyle[] styles)
- {
- this.styles = styles;
- repaint();
- }
-
- /**
- * Returns the caret color.
- */
- public final Color getCaretColor()
- {
- return caretColor;
- }
-
- /**
- * Sets the caret color.
- * @param caretColor The caret color
- */
- public final void setCaretColor(Color caretColor)
- {
- this.caretColor = caretColor;
- invalidateSelectedLines();
- }
-
- /**
- * Returns the selection color.
- */
- public final Color getSelectionColor()
- {
- return selectionColor;
- }
-
- /**
- * Sets the selection color.
- * @param selectionColor The selection color
- */
- public final void setSelectionColor(Color selectionColor)
- {
- this.selectionColor = selectionColor;
- invalidateSelectedLines();
- }
-
- /**
- * Returns the line highlight color.
- */
- public final Color getLineHighlightColor()
- {
- return lineHighlightColor;
- }
-
- /**
- * Sets the line highlight color.
- * @param lineHighlightColor The line highlight color
- */
- public final void setLineHighlightColor(Color lineHighlightColor)
- {
- this.lineHighlightColor = lineHighlightColor;
- invalidateSelectedLines();
- }
-
- /**
- * Returns true if line highlight is enabled, false otherwise.
- */
- public final boolean isLineHighlightEnabled()
- {
- return lineHighlight;
- }
-
- /**
- * Enables or disables current line highlighting.
- * @param lineHighlight True if current line highlight
- * should be enabled, false otherwise
- */
- public final void setLineHighlightEnabled(boolean lineHighlight)
- {
- this.lineHighlight = lineHighlight;
- invalidateSelectedLines();
- }
-
- /**
- * Returns the bracket highlight color.
- */
- public final Color getBracketHighlightColor()
- {
- return bracketHighlightColor;
- }
-
- /**
- * Sets the bracket highlight color.
- * @param bracketHighlightColor The bracket highlight color
- */
- public final void setBracketHighlightColor(Color bracketHighlightColor)
- {
- this.bracketHighlightColor = bracketHighlightColor;
- invalidateLine(textArea.getBracketLine());
- }
-
- /**
- * Returns true if bracket highlighting is enabled, false otherwise.
- * When bracket highlighting is enabled, the bracket matching the
- * one before the caret (if any) is highlighted.
- */
- public final boolean isBracketHighlightEnabled()
- {
- return bracketHighlight;
- }
-
- /**
- * Enables or disables bracket highlighting.
- * When bracket highlighting is enabled, the bracket matching the
- * one before the caret (if any) is highlighted.
- * @param bracketHighlight True if bracket highlighting should be
- * enabled, false otherwise
- */
- public final void setBracketHighlightEnabled(boolean bracketHighlight)
- {
- this.bracketHighlight = bracketHighlight;
- invalidateLine(textArea.getBracketLine());
- }
-
- /**
- * Returns true if the caret should be drawn as a block, false otherwise.
- */
- public final boolean isBlockCaretEnabled()
- {
- return blockCaret;
- }
-
- /**
- * Sets if the caret should be drawn as a block, false otherwise.
- * @param blockCaret True if the caret should be drawn as a block,
- * false otherwise.
- */
- public final void setBlockCaretEnabled(boolean blockCaret)
- {
- this.blockCaret = blockCaret;
- invalidateSelectedLines();
- }
-
- /**
- * Returns the EOL marker color.
- */
- public final Color getEOLMarkerColor()
- {
- return eolMarkerColor;
- }
-
- /**
- * Sets the EOL marker color.
- * @param eolMarkerColor The EOL marker color
- */
- public final void setEOLMarkerColor(Color eolMarkerColor)
- {
- this.eolMarkerColor = eolMarkerColor;
- repaint();
- }
-
- /**
- * Returns true if EOL markers are drawn, false otherwise.
- */
- public final boolean getEOLMarkersPainted()
- {
- return eolMarkers;
- }
-
- /**
- * Sets if EOL markers are to be drawn.
- * @param eolMarkers True if EOL markers should be drawn, false otherwise
- */
- public final void setEOLMarkersPainted(boolean eolMarkers)
- {
- this.eolMarkers = eolMarkers;
- repaint();
- }
-
- /**
- * Returns true if invalid lines are painted as red tildes (~),
- * false otherwise.
- */
- public boolean getInvalidLinesPainted()
- {
- return paintInvalid;
- }
-
- /**
- * Sets if invalid lines are to be painted as red tildes.
- * @param paintInvalid True if invalid lines should be drawn, false otherwise
- */
- public void setInvalidLinesPainted(boolean paintInvalid)
- {
- this.paintInvalid = paintInvalid;
- }
-
- /**
- * Adds a custom highlight painter.
- * @param highlight The highlight
- */
- public void addCustomHighlight(Highlight highlight)
- {
- highlight.init(textArea,highlights);
- highlights = highlight;
- }
-
- /**
- * Highlight interface.
- */
- public interface Highlight
- {
- /**
- * Called after the highlight painter has been added.
- * @param textArea The text area
- * @param next The painter this one should delegate to
- */
- void init(JEditTextArea textArea, Highlight next);
-
- /**
- * This should paint the highlight and delgate to the
- * next highlight painter.
- * @param gfx The graphics context
- * @param line The line number
- * @param y The y co-ordinate of the line
- */
- void paintHighlight(Graphics gfx, int line, int y);
-
- /**
- * Returns the tool tip to display at the specified
- * location. If this highlighter doesn't know what to
- * display, it should delegate to the next highlight
- * painter.
- * @param evt The mouse event
- */
- String getToolTipText(MouseEvent evt);
- }
-
- /**
- * Returns the tool tip to display at the specified location.
- * @param evt The mouse event
- */
- public String getToolTipText(MouseEvent evt)
- {
- if(highlights != null)
- return highlights.getToolTipText(evt);
- else
- return null;
- }
-
- /**
- * Returns the font metrics used by this component.
- */
- public FontMetrics getFontMetrics()
- {
- return fm;
- }
-
- /**
- * Sets the font for this component. This is overridden to update the
- * cached font metrics and to recalculate which lines are visible.
- * @param font The font
- */
- public void setFont(Font font)
- {
- super.setFont(font);
- fm = super.getFontMetrics(font);
- textArea.recalculateVisibleLines();
- }
-
- /**
- * Repaints the text.
- * @param gfx The graphics context
- */
- public void paint(Graphics gfx)
- {
- Graphics2D g2 = (Graphics2D) gfx;
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- antialias ?
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
- RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
-
- tabSize = fm.charWidth(' ') * ((Integer)textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue();
-
- Rectangle clipRect = gfx.getClipBounds();
-
- gfx.setColor(getBackground());
- gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
-
- // We don't use yToLine() here because that method doesn't
- // return lines past the end of the document
- int height = fm.getHeight();
- int firstLine = textArea.getFirstLine();
- int firstInvalid = firstLine + clipRect.y / height;
- // Because the clipRect's height is usually an even multiple
- // of the font height, we subtract 1 from it, otherwise one
- // too many lines will always be painted.
- int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
-
- try {
- TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
- int x = textArea.getHorizontalOffset();
-
- for (int line = firstInvalid; line <= lastInvalid; line++) {
- paintLine(gfx,tokenMarker,line,x);
- }
-
- if (tokenMarker != null && tokenMarker.isNextLineRequested()) {
- int h = clipRect.y + clipRect.height;
- repaint(0,h,getWidth(),getHeight() - h);
- }
- } catch (Exception e) {
- System.err.println("Error repainting line"
- + " range {" + firstInvalid + ","
- + lastInvalid + "}:");
- e.printStackTrace();
- }
- }
-
-
- public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
- int lineHeight = fm.getHeight();
- int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight);
- int lineCount = textArea.getLineCount();
- int lastPage = lineCount / linesPerPage;
-
- if (pageIndex > lastPage) {
- return NO_SUCH_PAGE;
-
- } else {
- Graphics2D g2d = (Graphics2D)g;
- TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
- int firstLine = pageIndex*linesPerPage;
- g2d.translate(Math.max(54, pageFormat.getImageableX()),
- pageFormat.getImageableY() - firstLine*lineHeight);
- printing = true;
- for (int line = firstLine; line < firstLine + linesPerPage; line++) {
- paintLine(g2d, tokenMarker, line, 0);
- }
- printing = false;
- return PAGE_EXISTS;
- }
- }
-
-
- /**
- * Marks a line as needing a repaint.
- * @param line The line to invalidate
- */
- public final void invalidateLine(int line)
- {
- repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
- getWidth(),fm.getHeight());
- }
-
- /**
- * Marks a range of lines as needing a repaint.
- * @param firstLine The first line to invalidate
- * @param lastLine The last line to invalidate
- */
- public final void invalidateLineRange(int firstLine, int lastLine)
- {
- repaint(0,textArea.lineToY(firstLine) +
- fm.getMaxDescent() + fm.getLeading(),
- getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
- }
-
- /**
- * Repaints the lines containing the selection.
- */
- public final void invalidateSelectedLines()
- {
- invalidateLineRange(textArea.getSelectionStartLine(),
- textArea.getSelectionStopLine());
- }
-
- /**
- * Implementation of TabExpander interface. Returns next tab stop after
- * a specified point.
- * @param x The x co-ordinate
- * @param tabOffset Ignored
- * @return The next tab stop after x
- */
- public float nextTabStop(float x, int tabOffset)
- {
- int offset = textArea.getHorizontalOffset();
- int ntabs = ((int)x - offset) / tabSize;
- return (ntabs + 1) * tabSize + offset;
- }
-
- /**
- * Returns the painter's preferred size.
- */
- public Dimension getPreferredSize()
- {
- Dimension dim = new Dimension();
- dim.width = fm.charWidth('w') * cols;
- dim.height = fm.getHeight() * rows;
- return dim;
- }
-
-
- /**
- * Returns the painter's minimum size.
- */
- public Dimension getMinimumSize()
- {
- Dimension dim = new Dimension();
- dim.width = fm.charWidth('w') * 10;
- dim.height = fm.getHeight() * 4;
- return dim;
- }
-
- // package-private members
- int currentLineIndex;
- Token currentLineTokens;
- Segment currentLine;
-
- /**
- * Accessor used by tools that want to hook in and grab the formatting.
- */
- public int getCurrentLineIndex() {
- return currentLineIndex;
- }
-
- /**
- * Accessor used by tools that want to hook in and grab the formatting.
- */
- public void setCurrentLineIndex(int what) {
- currentLineIndex = what;
- }
-
- /**
- * Accessor used by tools that want to hook in and grab the formatting.
- */
- public Token getCurrentLineTokens() {
- return currentLineTokens;
- }
-
- /**
- * Accessor used by tools that want to hook in and grab the formatting.
- */
- public void setCurrentLineTokens(Token tokens) {
- currentLineTokens = tokens;
- }
-
- /**
- * Accessor used by tools that want to hook in and grab the formatting.
- */
- public Segment getCurrentLine() {
- return currentLine;
- }
-
-
- // protected members
- protected JEditTextArea textArea;
-
- protected SyntaxStyle[] styles;
- protected Color caretColor;
- protected Color selectionColor;
- protected Color lineHighlightColor;
- protected Color bracketHighlightColor;
- protected Color eolMarkerColor;
-
- protected boolean blockCaret;
- protected boolean lineHighlight;
- protected boolean bracketHighlight;
- protected boolean paintInvalid;
- protected boolean eolMarkers;
- protected int cols;
- protected int rows;
-
- protected int tabSize;
- protected FontMetrics fm;
-
- protected Highlight highlights;
-
- protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
- int line, int x)
- {
- Font defaultFont = getFont();
- Color defaultColor = getForeground();
-
- currentLineIndex = line;
- int y = textArea.lineToY(line);
-
- if (line < 0 || line >= textArea.getLineCount()) {
- if (paintInvalid) {
- paintHighlight(gfx,line,y);
- styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
- gfx.drawString("~",0,y + fm.getHeight());
- }
- } else if(tokenMarker == null) {
- paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
- } else {
- paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
- defaultColor,x,y);
- }
- }
-
- protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
- Color defaultColor, int x, int y)
- {
- paintHighlight(gfx,line,y);
- textArea.getLineText(line,currentLine);
-
- gfx.setFont(defaultFont);
- gfx.setColor(defaultColor);
-
- y += fm.getHeight();
- x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
- /*
- * Draw characters via input method.
- */
- if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
- compositionTextPainter.draw(gfx, lineHighlightColor);
- }
- if (eolMarkers) {
- gfx.setColor(eolMarkerColor);
- gfx.drawString(".",x,y);
- }
- }
-
- protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
- int line, Font defaultFont,
- Color defaultColor, int x, int y)
- {
- textArea.getLineText(currentLineIndex,currentLine);
- currentLineTokens = tokenMarker.markTokens(currentLine,
- currentLineIndex);
-
- paintHighlight(gfx,line,y);
-
- gfx.setFont(defaultFont);
- gfx.setColor(defaultColor);
- y += fm.getHeight();
- x = SyntaxUtilities.paintSyntaxLine(currentLine,
- currentLineTokens,
- styles, this, gfx, x, y);
- /*
- * Draw characters via input method.
- */
- if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
- compositionTextPainter.draw(gfx, lineHighlightColor);
- }
- if (eolMarkers) {
- gfx.setColor(eolMarkerColor);
- gfx.drawString(".",x,y);
- }
- }
-
- protected void paintHighlight(Graphics gfx, int line, int y)
- {
- if (!printing) {
- if (line >= textArea.getSelectionStartLine()
- && line <= textArea.getSelectionStopLine())
- paintLineHighlight(gfx,line,y);
-
- if (highlights != null)
- highlights.paintHighlight(gfx,line,y);
-
- if (bracketHighlight && line == textArea.getBracketLine())
- paintBracketHighlight(gfx,line,y);
-
- if (line == textArea.getCaretLine())
- paintCaret(gfx,line,y);
- }
- }
-
- protected void paintLineHighlight(Graphics gfx, int line, int y)
- {
- int height = fm.getHeight();
- y += fm.getLeading() + fm.getMaxDescent();
-
- int selectionStart = textArea.getSelectionStart();
- int selectionEnd = textArea.getSelectionStop();
-
- if (selectionStart == selectionEnd) {
- if (lineHighlight) {
- gfx.setColor(lineHighlightColor);
- gfx.fillRect(0,y,getWidth(),height);
- }
- } else {
- gfx.setColor(selectionColor);
-
- int selectionStartLine = textArea.getSelectionStartLine();
- int selectionEndLine = textArea.getSelectionStopLine();
- int lineStart = textArea.getLineStartOffset(line);
-
- int x1, x2;
- if (textArea.isSelectionRectangular()) {
- int lineLen = textArea.getLineLength(line);
- x1 = textArea._offsetToX(line,Math.min(lineLen, selectionStart - textArea.getLineStartOffset(selectionStartLine)));
- x2 = textArea._offsetToX(line,Math.min(lineLen, selectionEnd - textArea.getLineStartOffset(selectionEndLine)));
- if (x1 == x2)
- x2++;
- } else if(selectionStartLine == selectionEndLine) {
- x1 = textArea._offsetToX(line, selectionStart - lineStart);
- x2 = textArea._offsetToX(line, selectionEnd - lineStart);
- } else if(line == selectionStartLine) {
- x1 = textArea._offsetToX(line, selectionStart - lineStart);
- x2 = getWidth();
- } else if(line == selectionEndLine) {
- //x1 = 0;
- // hack from stendahl to avoid doing weird side selection thing
- x1 = textArea._offsetToX(line, 0);
- // attempt at getting the gutter too, but doesn't seem to work
- //x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
- x2 = textArea._offsetToX(line, selectionEnd - lineStart);
- } else {
- //x1 = 0;
- // hack from stendahl to avoid doing weird side selection thing
- x1 = textArea._offsetToX(line, 0);
- // attempt at getting the gutter too, but doesn't seem to work
- //x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
- x2 = getWidth();
- }
-
- // "inlined" min/max()
- gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
- (x1 - x2) : (x2 - x1),height);
- }
-
- }
-
- protected void paintBracketHighlight(Graphics gfx, int line, int y)
- {
- int position = textArea.getBracketPosition();
- if(position == -1)
- return;
- y += fm.getLeading() + fm.getMaxDescent();
- int x = textArea._offsetToX(line,position);
- gfx.setColor(bracketHighlightColor);
- // Hack!!! Since there is no fast way to get the character
- // from the bracket matching routine, we use ( since all
- // brackets probably have the same width anyway
- gfx.drawRect(x,y,fm.charWidth('(') - 1,
- fm.getHeight() - 1);
- }
-
- protected void paintCaret(Graphics gfx, int line, int y)
- {
- //System.out.println("painting caret " + line + " " + y);
- if (textArea.isCaretVisible()) {
- //System.out.println("caret is visible");
- int offset =
- textArea.getCaretPosition() - textArea.getLineStartOffset(line);
- int caretX = textArea._offsetToX(line, offset);
- int caretWidth = ((blockCaret ||
- textArea.isOverwriteEnabled()) ?
- fm.charWidth('w') : 1);
- y += fm.getLeading() + fm.getMaxDescent();
- int height = fm.getHeight();
-
- //System.out.println("caretX, width = " + caretX + " " + caretWidth);
-
- gfx.setColor(caretColor);
-
- if (textArea.isOverwriteEnabled()) {
- gfx.fillRect(caretX,y + height - 1, caretWidth,1);
-
- } else {
- // some machines don't like the drawRect for the single
- // pixel caret.. this caused a lot of hell because on that
- // minority of machines, the caret wouldn't show up past
- // the first column. the fix is to use drawLine() in
- // those cases, as a workaround.
- if (caretWidth == 1) {
- gfx.drawLine(caretX, y, caretX, y + height - 1);
- } else {
- gfx.drawRect(caretX, y, caretWidth - 1, height - 1);
- }
- //gfx.drawRect(caretX, y, caretWidth, height - 1);
- }
- }
- }
-}
diff --git a/app/src/processing/app/syntax/TextUtilities.java b/app/src/processing/app/syntax/TextUtilities.java
deleted file mode 100644
index f009cd0513d..00000000000
--- a/app/src/processing/app/syntax/TextUtilities.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * TextUtilities.java - Utility functions used by the text area classes
- * Copyright (C) 1999 Slava Pestov
- *
- * You may use and modify this package for any purpose. Redistribution is
- * permitted, in both source and binary form, provided that this notice
- * remains intact in all source distributions of this package.
- */
-
-package processing.app.syntax;
-
-import javax.swing.text.*;
-
-/**
- * Class with several utility functions used by the text area component.
- * @author Slava Pestov
- */
-public class TextUtilities
-{
- /**
- * Returns the offset of the bracket matching the one at the
- * specified offset of the document, or -1 if the bracket is
- * unmatched (or if the character is not a bracket).
- * @param doc The document
- * @param offset The offset
- * @exception BadLocationException If an out-of-bounds access
- * was attempted on the document text
- */
- public static int findMatchingBracket(Document doc, int offset)
- throws BadLocationException
- {
- if(doc.getLength() == 0)
- return -1;
- char c = doc.getText(offset,1).charAt(0);
- char cprime; // c` - corresponding character
- boolean direction; // true = back, false = forward
-
- switch(c)
- {
- case '(': cprime = ')'; direction = false; break;
- case ')': cprime = '('; direction = true; break;
- case '[': cprime = ']'; direction = false; break;
- case ']': cprime = '['; direction = true; break;
- case '{': cprime = '}'; direction = false; break;
- case '}': cprime = '{'; direction = true; break;
- default: return -1;
- }
-
- int count;
-
- // How to merge these two cases is left as an exercise
- // for the reader.
-
- // Go back or forward
- if(direction)
- {
- // Count is 1 initially because we have already
- // `found' one closing bracket
- count = 1;
-
- // Get text[0,offset-1];
- String text = doc.getText(0,offset);
-
- // Scan backwards
- for(int i = offset - 1; i >= 0; i--)
- {
- // If text[i] == c, we have found another
- // closing bracket, therefore we will need
- // two opening brackets to complete the
- // match.
- char x = text.charAt(i);
- if(x == c)
- count++;
-
- // If text[i] == cprime, we have found a
- // opening bracket, so we return i if
- // --count == 0
- else if(x == cprime)
- {
- if(--count == 0)
- return i;
- }
- }
- }
- else
- {
- // Count is 1 initially because we have already
- // `found' one opening bracket
- count = 1;
-
- // So we don't have to + 1 in every loop
- offset++;
-
- // Number of characters to check
- int len = doc.getLength() - offset;
-
- // Get text[offset+1,len];
- String text = doc.getText(offset,len);
-
- // Scan forwards
- for(int i = 0; i < len; i++)
- {
- // If text[i] == c, we have found another
- // opening bracket, therefore we will need
- // two closing brackets to complete the
- // match.
- char x = text.charAt(i);
-
- if(x == c)
- count++;
-
- // If text[i] == cprime, we have found an
- // closing bracket, so we return i if
- // --count == 0
- else if(x == cprime)
- {
- if(--count == 0)
- return i + offset;
- }
- }
- }
-
- // Nothing found
- return -1;
- }
-
- /**
- * Locates the start of the word at the specified position.
- * @param line The text
- * @param pos The position
- */
- public static int findWordStart(String line, int pos, String noWordSep)
- {
- char ch = line.charAt(pos - 1);
-
- if(noWordSep == null)
- noWordSep = "";
- boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
- && noWordSep.indexOf(ch) == -1);
-
- int wordStart = 0;
- for(int i = pos - 1; i >= 0; i--)
- {
- ch = line.charAt(i);
- if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
- noWordSep.indexOf(ch) == -1))
- {
- wordStart = i + 1;
- break;
- }
- }
-
- return wordStart;
- }
-
- /**
- * Locates the end of the word at the specified position.
- * @param line The text
- * @param pos The position
- */
- public static int findWordEnd(String line, int pos, String noWordSep)
- {
- char ch = line.charAt(pos);
-
- if(noWordSep == null)
- noWordSep = "";
- boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
- && noWordSep.indexOf(ch) == -1);
-
- int wordEnd = line.length();
- for(int i = pos; i < line.length(); i++)
- {
- ch = line.charAt(i);
- if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
- noWordSep.indexOf(ch) == -1))
- {
- wordEnd = i;
- break;
- }
- }
- return wordEnd;
- }
-}
diff --git a/app/src/processing/app/syntax/TokenErrorMarker.java b/app/src/processing/app/syntax/TokenErrorMarker.java
new file mode 100755
index 00000000000..914240bd426
--- /dev/null
+++ b/app/src/processing/app/syntax/TokenErrorMarker.java
@@ -0,0 +1,91 @@
+package processing.app.syntax;
+
+import java.awt.Color;
+
+import javax.swing.text.Element;
+
+import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
+import org.fife.ui.rsyntaxtextarea.Token;
+import org.fife.ui.rsyntaxtextarea.TokenMaker;
+import org.fife.ui.rsyntaxtextarea.modes.CPlusPlusTokenMaker;
+import org.fife.ui.rsyntaxtextarea.parser.AbstractParser;
+import org.fife.ui.rsyntaxtextarea.parser.DefaultParseResult;
+import org.fife.ui.rsyntaxtextarea.parser.DefaultParserNotice;
+import org.fife.ui.rsyntaxtextarea.parser.ParseResult;
+import org.fife.ui.rsyntaxtextarea.parser.ParserNotice;
+
+/**
+ * Displays Syntax errors at the level of tokens, these errors are generated by {@link TokenMaker} like {@link CPlusPlusTokenMaker}
+ * TODO: Currently he is the parser of the entire document, I am waiting for the resolution of the bug below. (maybe this class is to removed)
+ * https://github.com/bobbylight/RSyntaxTextArea/issues/86
+ * @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ */
+public class TokenErrorMarker extends AbstractParser {
+
+ private RSyntaxTextArea textarea;
+ private DefaultParseResult result;
+
+ public TokenErrorMarker(RSyntaxTextArea textarea) {
+ setEnabled(true);
+ this.textarea = textarea;
+ result = new DefaultParseResult(this);
+ }
+
+ @Override
+ public ParseResult parse(RSyntaxDocument doc, String style) {
+
+ Element root = doc.getDefaultRootElement();
+ int lineCount = root.getElementCount();
+
+ result.clearNotices();
+ result.setParsedLines(0, lineCount-1);
+
+ for (int line=0; linemarkTokens
- * should only be used for immediate painting. Notably, it cannot be
- * cached.
- *
- * @author Slava Pestov
- */
-public abstract class TokenMarker
-{
- /**
- * A wrapper for the lower-level markTokensImpl
method
- * that is called to split a line up into tokens.
- * @param line The line
- * @param lineIndex The line number
- */
- public Token markTokens(Segment line, int lineIndex)
- {
- if(lineIndex >= length)
- {
- throw new IllegalArgumentException("Tokenizing invalid line: "
- + lineIndex);
- }
-
- lastToken = null;
-
- LineInfo info = lineInfo[lineIndex];
- LineInfo prev;
- if(lineIndex == 0)
- prev = null;
- else
- prev = lineInfo[lineIndex - 1];
-
- byte oldToken = info.token;
- byte token = markTokensImpl(prev == null ?
- Token.NULL : prev.token,line,lineIndex);
-
- info.token = token;
-
- /*
- * This is a foul hack. It stops nextLineRequested
- * from being cleared if the same line is marked twice.
- *
- * Why is this necessary? It's all JEditTextArea's fault.
- * When something is inserted into the text, firing a
- * document event, the insertUpdate() method shifts the
- * caret (if necessary) by the amount inserted.
- *
- * All caret movement is handled by the select() method,
- * which eventually pipes the new position to scrollTo()
- * and calls repaint().
- *
- * Note that at this point in time, the new line hasn't
- * yet been painted; the caret is moved first.
- *
- * scrollTo() calls offsetToX(), which tokenizes the line
- * unless it is being called on the last line painted
- * (in which case it uses the text area's painter cached
- * token list). What scrollTo() does next is irrelevant.
- *
- * After scrollTo() has done it's job, repaint() is
- * called, and eventually we end up in paintLine(), whose
- * job is to paint the changed line. It, too, calls
- * markTokens().
- *
- * The problem was that if the line started a multiline
- * token, the first markTokens() (done in offsetToX())
- * would set nextLineRequested (because the line end
- * token had changed) but the second would clear it
- * (because the line was the same that time) and therefore
- * paintLine() would never know that it needed to repaint
- * subsequent lines.
- *
- * This bug took me ages to track down, that's why I wrote
- * all the relevant info down so that others wouldn't
- * duplicate it.
- */
- if(!(lastLine == lineIndex && nextLineRequested))
- nextLineRequested = (oldToken != token);
-
- lastLine = lineIndex;
-
- addToken(0,Token.END);
-
- return firstToken;
- }
-
- /**
- * An abstract method that splits a line up into tokens. It
- * should parse the line, and call addToken()
to
- * add syntax tokens to the token list. Then, it should return
- * the initial token type for the next line.markTokens()
method (in turn).lineInfo
- * array.
- * @param index The first line number
- * @param lines The number of lines
- */
- public void insertLines(int index, int lines)
- {
- if(lines <= 0)
- return;
- length += lines;
- ensureCapacity(length);
- int len = index + lines;
- System.arraycopy(lineInfo,index,lineInfo,len,
- lineInfo.length - len);
-
- for(int i = index + lines - 1; i >= index; i--)
- {
- lineInfo[i] = new LineInfo();
- }
- }
-
- /**
- * Informs the token marker that line have been deleted from
- * the document. This removes the lines in question from the
- * lineInfo
array.
- * @param index The first line number
- * @param lines The number of lines
- */
- public void deleteLines(int index, int lines)
- {
- if (lines <= 0)
- return;
- int len = index + lines;
- length -= lines;
- System.arraycopy(lineInfo,len,lineInfo,
- index,lineInfo.length - len);
- }
-
- /**
- * Returns the number of lines in this token marker.
- */
- public int getLineCount()
- {
- return length;
- }
-
- /**
- * Returns true if the next line should be repainted. This
- * will return true after a line has been tokenized that starts
- * a multiline token that continues onto the next line.
- */
- public boolean isNextLineRequested()
- {
- return nextLineRequested;
- }
-
- // protected members
-
- /**
- * The first token in the list. This should be used as the return
- * value from markTokens()
.
- */
- protected Token firstToken;
-
- /**
- * The last token in the list. New tokens are added here.
- * This should be set to null before a new line is to be tokenized.
- */
- protected Token lastToken;
-
- /**
- * An array for storing information about lines. It is enlarged and
- * shrunk automatically by the insertLines()
and
- * deleteLines()
methods.
- */
- protected LineInfo[] lineInfo;
-
- /**
- * The number of lines in the model being tokenized. This can be
- * less than the length of the lineInfo
array.
- */
- protected int length;
-
- /**
- * The last tokenized line.
- */
- protected int lastLine;
-
- /**
- * True if the next line should be painted.
- */
- protected boolean nextLineRequested;
-
- /**
- * Creates a new TokenMarker
. This DOES NOT create
- * a lineInfo array; an initial call to insertLines()
- * does that.
- */
- protected TokenMarker()
- {
- lastLine = -1;
- }
-
- /**
- * Ensures that the lineInfo
array can contain the
- * specified index. This enlarges it if necessary. No action is
- * taken if the array is large enough already.insertLine()
should take care of
- * enlarging the line info array automatically.
- *
- * @param index The array index
- */
- protected void ensureCapacity(int index)
- {
- if(lineInfo == null)
- lineInfo = new LineInfo[index + 1];
- else if(lineInfo.length <= index)
- {
- LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
- System.arraycopy(lineInfo,0,lineInfoN,0,
- lineInfo.length);
- lineInfo = lineInfoN;
- }
- }
-
- /**
- * Adds a token to the token list.
- * @param length The length of the token
- * @param id The id of the token
- */
- protected void addToken(int length, byte id)
- {
- if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
- throw new InternalError("Invalid id: " + id);
-
- if(length == 0 && id != Token.END)
- return;
-
- if(firstToken == null)
- {
- firstToken = new Token(length,id);
- lastToken = firstToken;
- }
- else if(lastToken == null)
- {
- lastToken = firstToken;
- firstToken.length = length;
- firstToken.id = id;
- }
- else if(lastToken.next == null)
- {
- lastToken.next = new Token(length,id);
- lastToken = lastToken.next;
- }
- else
- {
- lastToken = lastToken.next;
- lastToken.length = length;
- lastToken.id = id;
- }
- }
-
- /**
- * Inner class for storing information about tokenized lines.
- */
- public class LineInfo
- {
- /**
- * Creates a new LineInfo object with token = Token.NULL
- * and obj = null.
- */
- public LineInfo()
- {
- }
-
- /**
- * Creates a new LineInfo object with the specified
- * parameters.
- */
- public LineInfo(byte token, Object obj)
- {
- this.token = token;
- this.obj = obj;
- }
-
- /**
- * The id of the last token of the line.
- */
- public byte token;
-
- /**
- * This is for use by the token marker implementations
- * themselves. It can be used to store anything that
- * is an object and that needs to exist on a per-line
- * basis.
- */
- public Object obj;
- }
-}
diff --git a/app/src/processing/app/syntax/im/CompositionTextManager.java b/app/src/processing/app/syntax/im/CompositionTextManager.java
deleted file mode 100644
index ba9ee155f7f..00000000000
--- a/app/src/processing/app/syntax/im/CompositionTextManager.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package processing.app.syntax.im;
-
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Graphics2D;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.font.FontRenderContext;
-import java.awt.font.TextAttribute;
-import java.awt.font.TextLayout;
-import java.text.AttributedCharacterIterator;
-import java.text.AttributedString;
-
-import javax.swing.text.BadLocationException;
-
-import processing.app.syntax.JEditTextArea;
-import processing.app.syntax.TextAreaPainter;
-
-/**
- * This class Manage texts from input method
- * by begin-process-end steps.
- *
- * First, if a user start inputing via input method,
- * beginCompositionText is called from InputMethodSupport.
- * Second, the user continues from input method, processCompositionText is called
- * and reflect user inputs to text area.
- * Finally the user try to commit text, endCompositionText is called.
- *
- * @author Takashi Maekawa (takachin@generative.info)
- */
-
-public class CompositionTextManager {
- private JEditTextArea textArea;
- private String prevComposeString;
- private int prevCommittedCount;
- private boolean isInputProcess;
- private int initialCaretPosition;
- public static final int COMPOSING_UNDERBAR_HEIGHT = 5;
-
- /**
- * Create text manager class with a textarea.
- * @param textArea texarea component for PDE.
- */
- public CompositionTextManager(JEditTextArea textArea) {
- this.textArea = textArea;
- prevComposeString = "";
- isInputProcess = false;
- prevCommittedCount = 0;
- }
-
- /**
- * Get this text manager is whether in input process or not.
- */
- public boolean getIsInputProcess() {
- return isInputProcess;
- }
- /**
- * Insert full width space
- */
- public void insertFullWidthSpace() {
- initialCaretPosition = textArea.getCaretPosition();
- int layoutCaretPosition = initialCaretPosition;
- try {
- textArea.getDocument().insertString(layoutCaretPosition, "\u3000", null);
- } catch (BadLocationException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Called when a user begins input from input method.
- * This method initializes text manager.
- *
- * @param text Text from InputMethodEvent.
- * @param commited_count Numbers of committed characters in text.
- */
- public void beginCompositionText(AttributedCharacterIterator text, int committed_count) {
- isInputProcess = true;
- prevComposeString = "";
- initialCaretPosition = textArea.getCaretPosition();
- processCompositionText(text, committed_count);
- }
-
- /**
- * Called when a user processing input characters and
- * select candidates from input method.
- *
- * @param text Text from InputMethodEvent.
- * @param commited_count Numbers of committed characters in text.
- */
- public void processCompositionText(AttributedCharacterIterator text, int committed_count) {
- int layoutCaretPosition = initialCaretPosition + committed_count;
- CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
- compositionPainter.setComposedTextLayout(getTextLayout(text, committed_count), layoutCaretPosition);
- int textLength = text.getEndIndex() - text.getBeginIndex() - committed_count;
- StringBuffer unCommitedStringBuf = new StringBuffer(textLength);
- char c;
- for (c = text.setIndex(committed_count); c != AttributedCharacterIterator.DONE
- && textLength > 0; c = text.next(), --textLength) {
- unCommitedStringBuf.append(c);
- }
- String unCommittedString = unCommitedStringBuf.toString();
- try {
- if(canRemovePreviousInput(committed_count)){
- textArea.getDocument().remove(layoutCaretPosition, prevComposeString.length());
- }
- textArea.getDocument().insertString(layoutCaretPosition, unCommittedString, null);
- if(committed_count > 0){
- initialCaretPosition = initialCaretPosition + committed_count;
- }
- prevComposeString = unCommittedString;
- prevCommittedCount = committed_count;
- } catch (BadLocationException e) {
- e.printStackTrace();
- }
- }
-
- private boolean canRemovePreviousInput(int committed_count){
- return (prevCommittedCount == committed_count || prevCommittedCount > committed_count);
- }
-
- /**
- * Called when a user fixed text from input method or delete all
- * composition text. This method resets CompositionTextPainter.
- *
- * @param text Text from InputMethodEvent.
- * @param commited_count Numbers of committed characters in text.
- */
- public void endCompositionText(AttributedCharacterIterator text, int committed_count) {
- /*
- * If there are no committed characters, remove it all from textarea.
- * This case will happen if a user delete all composing characters by backspace or delete key.
- * If it does, these previous characters are needed to be deleted.
- */
- if(committed_count == 0){
- removeNotCommittedText(text);
- }
- CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
- compositionPainter.invalidateComposedTextLayout(initialCaretPosition + committed_count);
- prevComposeString = "";
- isInputProcess = false;
- }
-
- private void removeNotCommittedText(AttributedCharacterIterator text){
- if (prevComposeString.length() == 0) {
- return;
- }
- try {
- textArea.getDocument().remove(initialCaretPosition, prevComposeString.length());
- } catch (BadLocationException e) {
- e.printStackTrace();
- }
- }
-
- private TextLayout getTextLayout(AttributedCharacterIterator text, int committed_count) {
- AttributedString composed = new AttributedString(text, committed_count, text.getEndIndex());
- Font font = textArea.getPainter().getFont();
- FontRenderContext context = ((Graphics2D) (textArea.getPainter().getGraphics())).getFontRenderContext();
- composed.addAttribute(TextAttribute.FONT, font);
- TextLayout layout = new TextLayout(composed.getIterator(), context);
- return layout;
- }
-
- private Point getCaretLocation() {
- Point loc = new Point();
- TextAreaPainter painter = textArea.getPainter();
- FontMetrics fm = painter.getFontMetrics();
- int offsetY = fm.getHeight() - COMPOSING_UNDERBAR_HEIGHT;
- int lineIndex = textArea.getCaretLine();
- loc.y = lineIndex * fm.getHeight() + offsetY;
- int offsetX = textArea.getCaretPosition()
- - textArea.getLineStartOffset(lineIndex);
- loc.x = textArea.offsetToX(lineIndex, offsetX);
- return loc;
- }
-
- public Rectangle getTextLocation() {
- Point caret = getCaretLocation();
- return getCaretRectangle(caret.x, caret.y);
- }
-
- private Rectangle getCaretRectangle(int x, int y) {
- TextAreaPainter painter = textArea.getPainter();
- Point origin = painter.getLocationOnScreen();
- int height = painter.getFontMetrics().getHeight();
- return new Rectangle(origin.x + x, origin.y + y, 0, height);
- }
-
- public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex) {
- int length = endIndex - beginIndex;
- String textAreaString = textArea.getText(beginIndex, length);
- return new AttributedString(textAreaString).getIterator();
- }
-
- public int getInsertPositionOffset() {
- return textArea.getCaretPosition() * -1;
- }
-}
diff --git a/app/src/processing/app/syntax/im/CompositionTextPainter.java b/app/src/processing/app/syntax/im/CompositionTextPainter.java
deleted file mode 100644
index 0084f491f92..00000000000
--- a/app/src/processing/app/syntax/im/CompositionTextPainter.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package processing.app.syntax.im;
-
-import java.awt.Color;
-import java.awt.FontMetrics;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Point;
-import java.awt.font.TextLayout;
-
-import processing.app.syntax.JEditTextArea;
-import processing.app.syntax.TextAreaPainter;
-
-/**
- * Paint texts from input method. Text via input method are transmitted by
- * AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter
- * to handle AttributedCaharacterIterator.
- *
- * For practical purposes, paint to textarea is done by TextLayout class.
- * Because TextLayout class is easy to draw composing texts. (For example,
- * draw underline composing texts, focus when select from candidates text.)
- *
- * @author Takashi Maekawa (takachin@generative.info)
- */
-public class CompositionTextPainter {
- private TextLayout composedTextLayout;
- private int composedBeginCaretPosition = 0;
- private JEditTextArea textArea;
-
- /**
- * Constructor for painter.
- * @param textarea textarea used by PDE.
- */
- public CompositionTextPainter(JEditTextArea textArea) {
- this.textArea = textArea;
- composedTextLayout = null;
- }
-
- /**
- * Check the painter has TextLayout.
- * If a user input via InputMethod, this result will return true.
- * @param textarea textarea used by PDE.
- */
- public boolean hasComposedTextLayout() {
- return (composedTextLayout != null);
- }
-
- /**
- * Set TextLayout to the painter.
- * TextLayout will be created and set by CompositionTextManager.
- *
- * @see CompositionTextManager
- * @param textarea textarea used by PDE.
- */
- public void setComposedTextLayout(TextLayout composedTextLayout, int composedStartCaretPosition) {
- this.composedTextLayout = composedTextLayout;
- this.composedBeginCaretPosition = composedStartCaretPosition;
- }
-
- /**
- * Invalidate this TextLayout to set null.
- * If a user end input via InputMethod, this method will called from CompositionTextManager.endCompositionText
- */
- public void invalidateComposedTextLayout(int composedEndCaretPosition) {
- this.composedTextLayout = null;
- this.composedBeginCaretPosition = composedEndCaretPosition;
- //this.composedBeginCaretPosition = textArea.getCaretPosition();
- }
-
- /**
- * Draw text via input method with composed text information.
- * This method can draw texts with some underlines to illustrate converting characters.
- *
- * This method is workaround for TextAreaPainter.
- * Because, TextAreaPainter can't treat AttributedCharacterIterator directly.
- * AttributedCharacterIterator has very important information when composing text.
- * It has a map where are converted characters and committed characters.
- * Ideally, changing TextAreaPainter method can treat AttributedCharacterIterator is better. But it's very tough!!
- * So I choose to write some code as a workaround.
- *
- * This draw method is proceeded with the following steps.
- * 1. Original TextAreaPainter draws characters.
- * 2. This refillComposedArea method erase previous paint characters by textarea's background color.
- * The refill area is only square that width and height defined by characters with input method.
- * 3. CompositionTextPainter.draw method paints composed text. It was actually drawn by TextLayout.
- *
- * @param gfx set TextAreaPainter's Graphics object.
- * @param fillBackGroundColor set textarea's background.
- */
- public void draw(Graphics gfx, Color fillBackGroundColor) {
- assert(composedTextLayout != null);
- Point composedLoc = getCaretLocation();
- refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y);
- composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y);
- }
-
- /**
- * Fill color to erase characters drawn by original TextAreaPainter.
- *
- * @param fillColor fill color to erase characters drawn by original TextAreaPainter method.
- * @param x x-coordinate where to fill.
- * @param y y-coordinate where to fill.
- */
- private void refillComposedArea(Color fillColor, int x, int y) {
- Graphics gfx = textArea.getPainter().getGraphics();
- gfx.setColor(fillColor);
- FontMetrics fm = textArea.getPainter().getFontMetrics();
- int newY = y - (fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT);
- int paintHeight = fm.getHeight();
- int paintWidth = (int) composedTextLayout.getBounds().getWidth();
- gfx.fillRect(x, newY, paintWidth, paintHeight);
- }
-
- private Point getCaretLocation() {
- Point loc = new Point();
- TextAreaPainter painter = textArea.getPainter();
- FontMetrics fm = painter.getFontMetrics();
- int offsetY = fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT;
- int lineIndex = textArea.getCaretLine();
- loc.y = lineIndex * fm.getHeight() + offsetY;
- int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(lineIndex);
- loc.x = textArea.offsetToX(lineIndex, offsetX);
- return loc;
- }
-}
diff --git a/app/src/processing/app/syntax/im/InputMethodSupport.java b/app/src/processing/app/syntax/im/InputMethodSupport.java
deleted file mode 100644
index 461be3d1677..00000000000
--- a/app/src/processing/app/syntax/im/InputMethodSupport.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package processing.app.syntax.im;
-
-import java.awt.Rectangle;
-import java.awt.event.InputMethodEvent;
-import java.awt.event.InputMethodListener;
-import java.awt.font.TextHitInfo;
-import java.awt.im.InputMethodRequests;
-import java.text.AttributedCharacterIterator;
-
-import processing.app.syntax.JEditTextArea;
-
-/**
- * Support in-line Japanese input for PDE. (Maybe Chinese, Korean and more)
- * This class is implemented by Java Input Method Framework and handles
- * If you would like to know more about Java Input Method Framework,
- * Please see http://java.sun.com/j2se/1.5.0/docs/guide/imf/
- *
- * This class is implemented to fix Bug #854.
- * http://dev.processing.org/bugs/show_bug.cgi?id=854
- *
- * @author Takashi Maekawa (takachin@generative.info)
- */
-public class InputMethodSupport implements InputMethodRequests,
- InputMethodListener {
-
- private int committed_count = 0;
- private CompositionTextManager textManager;
-
- public InputMethodSupport(JEditTextArea textArea) {
- textManager = new CompositionTextManager(textArea);
- textArea.enableInputMethods(true);
- textArea.addInputMethodListener(this);
- }
-
- public Rectangle getTextLocation(TextHitInfo offset) {
- return textManager.getTextLocation();
- }
-
- public TextHitInfo getLocationOffset(int x, int y) {
- return null;
- }
-
- public int getInsertPositionOffset() {
- return textManager.getInsertPositionOffset();
- }
-
- public AttributedCharacterIterator getCommittedText(int beginIndex,
- int endIndex, AttributedCharacterIterator.Attribute[] attributes) {
- return textManager.getCommittedText(beginIndex, endIndex);
- }
-
- public int getCommittedTextLength() {
- return committed_count;
- }
-
- public AttributedCharacterIterator cancelLatestCommittedText(
- AttributedCharacterIterator.Attribute[] attributes) {
- return null;
- }
-
- public AttributedCharacterIterator getSelectedText(
- AttributedCharacterIterator.Attribute[] attributes) {
- return null;
- }
-
- /**
- * Handles events from InputMethod.
- * This method judges whether beginning of input or
- * progress of input or end and call related method.
- *
- * @param event event from Input Method.
- */
- public void inputMethodTextChanged(InputMethodEvent event) {
- AttributedCharacterIterator text = event.getText();
- committed_count = event.getCommittedCharacterCount();
- if(isFullWidthSpaceInput(text)){
- textManager.insertFullWidthSpace();
- caretPositionChanged(event);
- return;
- }
- if(isBeginInputProcess(text, textManager)){
- textManager.beginCompositionText(text, committed_count);
- caretPositionChanged(event);
- return;
- }
- if (isInputProcess(text)){
- textManager.processCompositionText(text, committed_count);
- caretPositionChanged(event);
- return;
- }
- textManager.endCompositionText(text, committed_count);
- caretPositionChanged(event);
- }
-
- private boolean isFullWidthSpaceInput(AttributedCharacterIterator text){
- if(text == null)
- return false;
- if(textManager.getIsInputProcess())
- return false;
- return (String.valueOf(text.first()).equals("\u3000"));
- }
-
- private boolean isBeginInputProcess(AttributedCharacterIterator text, CompositionTextManager textManager){
- if(text == null)
- return false;
- if(textManager.getIsInputProcess())
- return false;
- return (isInputProcess(text));
- }
-
- private boolean isInputProcess(AttributedCharacterIterator text){
- if(text == null)
- return false;
- return (text.getEndIndex() - (text.getBeginIndex() + committed_count) > 0);
- }
-
- public void caretPositionChanged(InputMethodEvent event) {
- event.consume();
- }
-}
diff --git a/app/src/processing/app/syntax/readme.txt b/app/src/processing/app/syntax/readme.txt
deleted file mode 100644
index 07a825cd7bb..00000000000
--- a/app/src/processing/app/syntax/readme.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-OLDSYNTAX PACKAGE README
-
-I am placing the jEdit 2.2.1 syntax highlighting package in the public
-domain. This means it can be integrated into commercial programs, etc.
-
-This package requires at least Java 1.1 and Swing 1.1. Syntax
-highlighting for the following file types is supported:
-
-- C++, C
-- CORBA IDL
-- Eiffel
-- HTML
-- Java
-- Java properties
-- JavaScript
-- MS-DOS INI
-- MS-DOS batch files
-- Makefile
-- PHP
-- Perl
-- Python
-- TeX
-- Transact-SQL
-- Unix patch/diff
-- Unix shell script
-- XML
-
-This package is undocumented; read the source (start by taking a look at
-JEditTextArea.java) to find out how to use it; it's really simple. Feel
-free to e-mail questions, queries, etc. to me, but keep in mind that
-this code is very old and I no longer maintain it. So if you find a bug,
-don't bother me about it; fix it yourself.
-
-* Copyright
-
-The jEdit 2.2.1 syntax highlighting package contains code that is
-Copyright 1998-1999 Slava Pestov, Artur Biesiadowski, Clancy Malcolm,
-Jonathan Revusky, Juha Lindfors and Mike Dillon.
-
-You may use and modify this package for any purpose. Redistribution is
-permitted, in both source and binary form, provided that this notice
-remains intact in all source distributions of this package.
-
--- Slava Pestov
-25 September 2000
-\n" : "[code]\n");
int selStart = textarea.getSelectionStart();
- int selStop = textarea.getSelectionStop();
-
- int startLine = textarea.getSelectionStartLine();
- int stopLine = textarea.getSelectionStopLine();
+ int selStop = textarea.getSelectionEnd();
+
+ int startLine;
+ int stopLine;
+ try {
+ startLine = textarea.getLineOfOffset(selStart);
+ stopLine = textarea.getLineOfOffset(selStop);
+ } catch (BadLocationException e) {
+ return;
+ }
// If no selection, convert all the lines
if (selStart == selStop) {
@@ -89,8 +100,11 @@ public void show() {
stopLine = textarea.getLineCount() - 1;
} else {
// Make sure the selection doesn't end at the beginning of the last line
- if (textarea.getLineStartOffset(stopLine) == selStop) {
- stopLine--;
+ try {
+ if (textarea.getLineStartOffset(stopLine) == selStop) {
+ stopLine--;
+ }
+ } catch (BadLocationException e) {
}
}
@@ -139,23 +153,15 @@ private void appendToHTML(char c, StringBuilder buffer) {
public void appendFormattedLine(StringBuilder cf, int line) {
Segment segment = new Segment();
- TextAreaPainter painter = textarea.getPainter();
- TokenMarker tokenMarker = textarea.getTokenMarker();
-
- // Use painter's cached info for speed
-// FontMetrics fm = painter.getFontMetrics();
-
// get line text from parent text area
- textarea.getLineText(line, segment);
-
+ textarea.getTextLine(line, segment);
+
char[] segmentArray = segment.array;
- int limit = segment.getEndIndex();
int segmentOffset = segment.offset;
int segmentCount = segment.count;
// int width = 0;
- // If syntax coloring is disabled, do simple translation
- if (tokenMarker == null) {
+ if (!html) {
for (int j = 0; j < segmentCount; j++) {
char c = segmentArray[j + segmentOffset];
appendToHTML(c, cf);
@@ -169,82 +175,19 @@ public void appendFormattedLine(StringBuilder cf, int line) {
}
} else {
- // If syntax coloring is enabled, we have to do this
- // because tokens can vary in width
- Token tokens;
- if ((painter.getCurrentLineIndex() == line) &&
- (painter.getCurrentLineTokens() != null)) {
- tokens = painter.getCurrentLineTokens();
-
- } else {
- painter.setCurrentLineIndex(line);
- painter.setCurrentLineTokens(tokenMarker.markTokens(segment, line));
- tokens = painter.getCurrentLineTokens();
- }
-
- int offset = 0;
-// Font defaultFont = painter.getFont();
- SyntaxStyle[] styles = painter.getStyles();
-
- for (;;) {
- byte id = tokens.id;
- if (id == Token.END) {
- char c = segmentArray[segmentOffset + offset];
- if (segmentOffset + offset < limit) {
- appendToHTML(c, cf);
- } else {
- cf.append('\n');
- }
- return; // cf.toString();
- }
- if (id == Token.NULL) {
-// fm = painter.getFontMetrics();
- } else {
- // Place open tags []
- if (html) {
- cf.append("");
- }
-
- if (html && styles[id].isBold())
- cf.append("");
-
-// fm = styles[id].getFontMetrics(defaultFont);
- }
- int length = tokens.length;
-
- for (int j = 0; j < length; j++) {
- char c = segmentArray[segmentOffset + offset + j];
- if (offset == 0 && c == ' ') {
- // Works on Safari but not Camino 1.6.3 or Firefox 2.x on OS X.
- cf.append(html ? " " : '\u00A0'); //
-// if ((j % 2) == 1) {
-// cf.append("[b]\u00A0[/b]");
-// } else {
-// cf.append(' ');
-// }
- } else {
- appendToHTML(c, cf);
- }
- // Place close tags [/]
- if (html && j == (length - 1) && id != Token.NULL && styles[id].isBold())
- cf.append("");
- if (html && j == (length - 1) && id != Token.NULL)
- cf.append("");
-// int charWidth;
-// if (c == '\t') {
-// charWidth = (int) painter
-// .nextTabStop(width, offset + j)
-// - width;
-// } else {
-// charWidth = fm.charWidth(c);
-// }
-// width += charWidth;
+
+ Token tokenList = textarea.getTokenListForLine(line);
+
+ while(tokenList != null){
+ if(tokenList.getType() == Token.NULL){
+ cf.append('\n');
+ }else if(tokenList.isPaintable()){
+ tokenList.appendHTMLRepresentation(cf, textarea, false);
}
- offset += length;
- tokens = tokens.next;
+
+ tokenList = tokenList.getNextToken();
}
+
}
}
}
diff --git a/app/test/processing/app/AutoformatSavesCaretPositionTest.java b/app/test/processing/app/AutoformatSavesCaretPositionTest.java
index 8ffa03190d1..01a60ecb6b4 100644
--- a/app/test/processing/app/AutoformatSavesCaretPositionTest.java
+++ b/app/test/processing/app/AutoformatSavesCaretPositionTest.java
@@ -2,7 +2,7 @@
import org.fest.swing.fixture.JMenuItemFixture;
import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.RSyntaxTextAreaFixture;
import static org.junit.Assert.assertEquals;
@@ -13,7 +13,7 @@ public void shouldSaveCaretPositionAfterAutoformat() {
JMenuItemFixture menuToolsAutoFormat = window.menuItem("menuToolsAutoFormat");
menuToolsAutoFormat.requireEnabled();
- JEditTextAreaFixture editor = window.jEditTextArea("editor");
+ RSyntaxTextAreaFixture editor = window.RSyntaxTextArea("editor");
editor.setText("void setup() {\n" +
" // put your setup code here, to run once:\n" +
"\n" +
diff --git a/app/test/processing/app/AutoformatTest.java b/app/test/processing/app/AutoformatTest.java
index 51fdc35d6ba..35f71d5918c 100644
--- a/app/test/processing/app/AutoformatTest.java
+++ b/app/test/processing/app/AutoformatTest.java
@@ -2,7 +2,7 @@
import org.fest.swing.fixture.JMenuItemFixture;
import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.RSyntaxTextAreaFixture;
import static org.junit.Assert.assertEquals;
@@ -13,7 +13,7 @@ public void shouldProduceNicelyFormattedCode() throws Exception {
JMenuItemFixture menuToolsAutoFormat = window.menuItem("menuToolsAutoFormat");
menuToolsAutoFormat.requireEnabled();
- JEditTextAreaFixture editor = window.jEditTextArea("editor");
+ RSyntaxTextAreaFixture editor = window.RSyntaxTextArea("editor");
editor.setText("void setup() {\n" +
"// put your setup code here, to run once:\n" +
"int foo[] = { 1, 2, 3, 4, 5};\n" +
diff --git a/app/test/processing/app/HittingEscapeOnCloseConfirmationDialogTest.java b/app/test/processing/app/HittingEscapeOnCloseConfirmationDialogTest.java
index c760ef29be4..d9fa4ed2109 100644
--- a/app/test/processing/app/HittingEscapeOnCloseConfirmationDialogTest.java
+++ b/app/test/processing/app/HittingEscapeOnCloseConfirmationDialogTest.java
@@ -4,7 +4,7 @@
import org.fest.swing.finder.WindowFinder;
import org.fest.swing.fixture.DialogFixture;
import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.RSyntaxTextAreaFixture;
import javax.swing.*;
import java.awt.event.KeyEvent;
@@ -15,7 +15,7 @@ public class HittingEscapeOnCloseConfirmationDialogTest extends AbstractGUITest
@Test
public void shouldJustCloseTheDialog() throws Exception {
- JEditTextAreaFixture editor = window.jEditTextArea("editor");
+ RSyntaxTextAreaFixture editor = window.RSyntaxTextArea("editor");
editor.setText("test");
window.close();
diff --git a/app/test/processing/app/ReduceIndentWith1CharOnLastLineTest.java b/app/test/processing/app/ReduceIndentWith1CharOnLastLineTest.java
index 9ee7e0c5089..49d460cfb57 100644
--- a/app/test/processing/app/ReduceIndentWith1CharOnLastLineTest.java
+++ b/app/test/processing/app/ReduceIndentWith1CharOnLastLineTest.java
@@ -5,7 +5,7 @@
import org.fest.swing.fixture.JMenuItemFixture;
import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.RSyntaxTextAreaFixture;
public class ReduceIndentWith1CharOnLastLineTest extends AbstractGUITest {
@@ -13,7 +13,7 @@ public class ReduceIndentWith1CharOnLastLineTest extends AbstractGUITest {
public void shouldJustCloseTheDialog() throws Exception {
JMenuItemFixture menuDecreaseIndent = window.menuItem("menuDecreaseIndent");
- JEditTextAreaFixture editor = window.jEditTextArea("editor");
+ RSyntaxTextAreaFixture editor = window.RSyntaxTextArea("editor");
editor.setText("void loop()\n{\n Serial.begin(9600)\n}");
editor.selectAll();
diff --git a/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java b/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java
index bd03f1108b0..21cce003bd0 100644
--- a/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java
+++ b/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java
@@ -2,7 +2,7 @@
import org.fest.swing.fixture.JMenuItemFixture;
import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.RSyntaxTextAreaFixture;
import static org.junit.Assert.assertEquals;
@@ -15,19 +15,19 @@ public void shouldUndoAndRedo() throws Exception {
JMenuItemFixture menuEditRedo = window.menuItem("menuEditRedo");
menuEditRedo.requireDisabled();
- JEditTextAreaFixture jEditTextArea = window.jEditTextArea("editor");
+ RSyntaxTextAreaFixture RSyntaxTextArea = window.RSyntaxTextArea("editor");
- jEditTextArea.setText("fake text");
+ RSyntaxTextArea.setText("fake text");
menuEditUndo.requireEnabled();
menuEditUndo.click();
- assertEquals("", jEditTextArea.getText());
+ assertEquals("", RSyntaxTextArea.getText());
menuEditRedo.requireEnabled();
menuEditRedo.click();
- //assertEquals("fake text", jEditTextArea.getText());
+ //assertEquals("fake text", RSyntaxTextArea.getText());
menuEditUndo.requireEnabled();
menuEditUndo.click();
diff --git a/app/test/processing/app/helpers/ArduinoFrameFixture.java b/app/test/processing/app/helpers/ArduinoFrameFixture.java
index aec49a5a89d..54fc2f420db 100644
--- a/app/test/processing/app/helpers/ArduinoFrameFixture.java
+++ b/app/test/processing/app/helpers/ArduinoFrameFixture.java
@@ -1,10 +1,10 @@
package processing.app.helpers;
+import java.awt.Frame;
+
import org.fest.swing.core.Robot;
import org.fest.swing.fixture.FrameFixture;
-import processing.app.syntax.JEditTextArea;
-
-import java.awt.*;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
public class ArduinoFrameFixture extends FrameFixture {
@@ -24,7 +24,7 @@ public ArduinoFrameFixture(String name) {
super(name);
}
- public JEditTextAreaFixture jEditTextArea(String name) {
- return new JEditTextAreaFixture(robot, (JEditTextArea) this.robot.finder().find(new JEditTextAreaComponentMatcher(name)));
+ public RSyntaxTextAreaFixture RSyntaxTextArea(String name) {
+ return new RSyntaxTextAreaFixture(robot, (RSyntaxTextArea) this.robot.finder().find(new RSyntaxTextAreaComponentMatcher(name)));
}
}
diff --git a/app/test/processing/app/helpers/JEditTextAreaComponentMatcher.java b/app/test/processing/app/helpers/JEditTextAreaComponentMatcher.java
deleted file mode 100644
index f168b92b92f..00000000000
--- a/app/test/processing/app/helpers/JEditTextAreaComponentMatcher.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package processing.app.helpers;
-
-import org.fest.swing.core.ComponentMatcher;
-import processing.app.syntax.JEditTextArea;
-
-import java.awt.*;
-
-public class JEditTextAreaComponentMatcher implements ComponentMatcher {
-
- private final String name;
-
- public JEditTextAreaComponentMatcher(String name) {
- this.name = name;
- }
-
- @Override
- public boolean matches(Component component) {
- return component instanceof JEditTextArea && name.equals(component.getName());
- }
-}
diff --git a/app/test/processing/app/helpers/JEditTextAreaFixture.java b/app/test/processing/app/helpers/JEditTextAreaFixture.java
deleted file mode 100644
index 19560d88be9..00000000000
--- a/app/test/processing/app/helpers/JEditTextAreaFixture.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package processing.app.helpers;
-
-import org.fest.swing.core.Robot;
-import org.fest.swing.fixture.ComponentFixture;
-import processing.app.syntax.JEditTextArea;
-
-public class JEditTextAreaFixture extends ComponentFixture {
-
- private final JEditTextAreaComponentDriver driver;
-
- public JEditTextAreaFixture(Robot robot, Class type) {
- super(robot, type);
- this.driver = new JEditTextAreaComponentDriver(robot);
- }
-
- public JEditTextAreaFixture(Robot robot, String name, Class type) {
- super(robot, name, type);
- this.driver = new JEditTextAreaComponentDriver(robot);
- }
-
- public JEditTextAreaFixture(Robot robot, JEditTextArea target) {
- super(robot, target);
- this.driver = new JEditTextAreaComponentDriver(robot);
- }
-
- public JEditTextAreaFixture enterText(String text) {
- driver.enterText((JEditTextArea) target, text);
- return this;
- }
-
- public JEditTextAreaFixture setText(String text) {
- driver.setText((JEditTextArea) target, text);
- return this;
- }
-
- public String getText() {
- return driver.getText((JEditTextArea) target);
- }
-
- public JEditTextAreaFixture selectAll() {
- driver.selectAll((JEditTextArea) target);
- return this;
- }
-
- public int getCaretPosition() {
- return driver.getCaretPosition((JEditTextArea) target);
- }
-
- public void setCaretPosition(int caretPosition) {
- driver.setCaretPosition((JEditTextArea) target, caretPosition);
- }
-}
diff --git a/app/test/processing/app/helpers/JEditTextAreaComponentDriver.java b/app/test/processing/app/helpers/RSyntaxTextAreaComponentDriver.java
similarity index 53%
rename from app/test/processing/app/helpers/JEditTextAreaComponentDriver.java
rename to app/test/processing/app/helpers/RSyntaxTextAreaComponentDriver.java
index f292c399827..73d2694de8c 100644
--- a/app/test/processing/app/helpers/JEditTextAreaComponentDriver.java
+++ b/app/test/processing/app/helpers/RSyntaxTextAreaComponentDriver.java
@@ -4,24 +4,24 @@
import org.fest.swing.driver.JComponentDriver;
import org.fest.swing.edt.GuiActionRunner;
import org.fest.swing.edt.GuiQuery;
-import processing.app.syntax.JEditTextArea;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
-public class JEditTextAreaComponentDriver extends JComponentDriver {
+public class RSyntaxTextAreaComponentDriver extends JComponentDriver {
- public JEditTextAreaComponentDriver(Robot robot) {
+ public RSyntaxTextAreaComponentDriver(Robot robot) {
super(robot);
}
- public void enterText(JEditTextArea target, String text) {
+ public void enterText(RSyntaxTextArea target, String text) {
focusAndWaitForFocusGain(target);
robot.enterText(text);
}
- public void setText(final JEditTextArea target, final String text) {
+ public void setText(final RSyntaxTextArea target, final String text) {
focusAndWaitForFocusGain(target);
- GuiActionRunner.execute(new GuiQuery
+ * For any parameter to the function/method, this object can return possible completions.
+ * @see {@link CompletionProviderBase#setParameterChoicesProvider(org.fife.ui.autocomplete.ParameterChoicesProvider)}
+ * @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ * @date 09/12/2014
+ */
+public class ParameterChoicesProvider implements org.fife.ui.autocomplete.ParameterChoicesProvider {
+
+ private SketchCompletionProvider provider;
+
+ public ParameterChoicesProvider(SketchCompletionProvider provider) {
+ super();
+ this.provider = provider;
+ }
+
+ @Override
+ public List
+ * This listener is registered by: {@link SketchCompletionProvider#onSketchInserted(Sketch, SketchCode)} and {@link PdeTextArea}.
+ * @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ * @date 22/11/2014
+ */
+public class RealtimeCompletionsListener implements KeyListener, DocumentListener {
+
+ private final static Logger LOG = Logger.getLogger(RealtimeCompletionsListener.class.getName());
+
+ private BaseSketch sketch;
+ private Segment segment = new Segment();
+ private Timer debounce;
+ private int startOffs;
+ private int endOffs;
+ private int startLine;
+ private int endLine;
+
+ public RealtimeCompletionsListener(BaseSketch sketch) {
+ this.sketch = sketch;
+ debounce = new Timer(800, new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ analizeModified();
+ }
+ });
+ debounce.setRepeats(false);
+
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ if(e.getKeyChar() == ';' || e.getKeyChar() == '}'){
+ fireParser();
+ }
+ }
+
+
+ protected void fireParser(){
+ SketchCode sketchCode = sketch.getCurrentCode();
+ TLibrary library = sketch.getSketchMetadata();
+ if(library != null){
+
+ long time = System.currentTimeMillis();
+ if(library.getLastUpdate() > 0 && (time - library.getLastUpdate() < 2000 )){
+ LOG.fine("Ignoring parser, a recent parser has been done !");
+ return;
+ }
+
+ library.clear();
+ }
+
+ try {
+ Document document = SketchCompletionProvider.getDocument(sketchCode);
+ String code = document.getText(0, document.getLength());
+ LibraryIndex.scanSource(code, new SketchCodeScanner(sketch.getCurrentCode())); // fire #onLoadLibrary on finish
+ } catch (BadLocationException e) {
+ LOG.severe(e.getMessage());
+ }
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ startOffs = e.getOffset();
+ endOffs = startOffs + e.getLength();
+ Document doc = e.getDocument();
+ Element root = doc.getDefaultRootElement();
+ startLine = root.getElementIndex(startOffs);
+ endLine = root.getElementIndex(endOffs);
+
+ debounce.restart(); // waits for the user stops typing
+
+ try {
+ doc.getText(startOffs, e.getLength(), segment);
+
+ if (startLine != endLine) { // Inserted text covering > 1 line...
+ // fireParser();
+ // System.out.println("RealtimeCompletionsListener.insertUpdate: startLine != endLine");
+
+ } else if (segment.length() > 0&& segment.charAt(segment.length() - 1) == '}') {
+ // System.out.println("RealtimeCompletionsListener.insertUpdate: == '}'");
+ }
+ } catch (BadLocationException e2) {
+ e2.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+
+ debounce.restart(); // waits for the user stops typing
+
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+
+ }
+
+ protected void analizeModified(){
+
+
+ if(sketch != null && sketch.getSketchMetadata() != null){
+ TLibrary metadata = sketch.getSketchMetadata();
+
+ // Check errors
+ if(TError.containsError(startOffs, metadata.getErrors())){
+ LOG.fine("Offset contains erros, firing parser");
+ fireParser();
+ return;
+ }
+
+ // Variables
+ if(TElement.contains(startOffs, metadata.getGlobalVariables())){
+ LOG.fine("Changing a global variable, firing parser");
+ fireParser();
+ return;
+ }
+
+ Set
+ * This class is responsible for the settings required for the logic of autocomplete,
+ * external events such as adding libraries, creating new files, etc .. will be monitored.
+ * Filtering and decision will appear in the autocomplete is up to the: {@link CompletionProviderWithContext}.
+ * Another class that works together is the: {@link RealtimeCompletionsListener} ,
+ * that monitor real-time changes to the text and notifies when it should be made a new parser.
+ *
+ * The analysis(parser) of the source code is made by the library cplus-libparser
, Which was specially developed
+ * for the Arduino, more can be used in other projects.
+ *
+ * @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ * @date 22/11/2014
+ */
+public class SketchCompletionProvider extends LanguageAwareCompletionProvider implements LibraryListener, LibraryIndexListener, SketchListener{
+
+ private final static Logger LOG = Logger.getLogger(RealtimeCompletionsListener.class.getName());
+
+ public static final String SKETCH_LIB_PREFIX = BaseSketch.SKETCH_LIB_PREFIX;
+
+ /**
+ * Matches strings like {@code obj.myMethod(params)}
+ * {@code (?U)} lets {@code \\w} also match non-ASCII letters.
+ */
+ public static final Pattern INSTANCE_CALL_REGEX = Pattern.compile("(?U)([.\\w]+)\\.([\\w]+)\\s*\\((.*)\\)");
+
+ public static final Pattern FUNCTION_CALL_REGEX = Pattern.compile("(?U)([.\\w]+)\\s*\\((.*)\\)");
+
+ private TLibrary sketchLibrary; // classes, variables, functions of sketch
+ private BaseSketch sketch;
+ private LibraryList importedLibraries; // same instance in Sketch
+
+ private RealtimeCompletionsListener realtimeCompletionsListener;
+
+
+ private CompletionProviderWithContext provider = new CompletionProviderWithContext(); // Loaded static auto-completes.
+
+ private AutoCompletion autoCompletion;
+
+ public SketchCompletionProvider(BaseSketch sketch) {
+ super();
+ this.sketch = sketch;
+
+ provider.setParameterChoicesProvider(new ParameterChoicesProvider(this));
+ setDefaultCompletionProvider(provider);
+ provider.setParameterizedCompletionParams('(', ", ", ')');
+
+ LibraryIndex.addListener(this);
+ sketch.addListener(this);
+ realtimeCompletionsListener = new RealtimeCompletionsListener(sketch);
+
+ // Import existing...
+
+ // Arduino Core
+ //=======================
+ File folder = BaseNoGui.getTargetPlatform().getFolder();
+ File coreFolder = new File(folder,"cores"+File.separator+"arduino");
+ if(coreFolder.exists()){
+ Library coreLib;
+ try {
+ coreLib = Library.create(coreFolder);
+ LibraryIndex.scanFolder(coreFolder, new ArduinoLibraryScanner(coreLib)); // fire #onLoadLibrary on finish
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ LibraryIndex.scanFolder(sketch.getFolder(), new SketchCodeScanner(sketch)); // fire #onLoadLibrary on finish
+
+
+ onSketchLoad(sketch);
+ for (SketchCode sketchCode : sketch.getCodes()) {
+ onSketchInserted(sketch, sketchCode);
+ }
+
+ loadDefaultAutocompletes();
+ }
+
+
+ /**
+ * Remove all added listeners
+ */
+ public void uninstall() {
+ LibraryIndex.removeListener(this);
+ sketch.removeListener(this);
+ importedLibraries.addListener(this);
+
+ for (SketchCode code : sketch.getCodes()) {
+ Document document = getDocument(code);
+ if(document != null)
+ document.removeDocumentListener(realtimeCompletionsListener);
+ }
+ }
+
+
+ // ==========================================
+ // Sketch Library (importedLibraries) Listener
+ // ==========================================
+
+ @Override
+ public void onInsertLibrary(Library library) {
+
+ if(sketch.isExternalMode()) return;
+
+ LOG.fine("Arduino Lib: " + library);
+ LibraryIndex.scanFolder(library.getFolder(), new ArduinoLibraryScanner(library)); // scan lib and fire #onLoadLibrary
+ }
+
+ @Override
+ public void onRemoveLibrary(Library library) {
+
+ if(sketch.isExternalMode()) return;
+
+ LOG.fine("Arduino Lib: " + library);
+ }
+
+ @Override
+ public void onClearLibraryList() {
+
+ if(sketch.isExternalMode()) return;
+
+ }
+
+
+ // ==========================================
+ // SketchCode Listener
+ // ==========================================
+
+ @Override
+ public void onSketchLoad(BaseSketch sketch) {
+
+ if(sketch.isExternalMode()) return;
+
+ LOG.fine(sketch.getName());
+
+ importedLibraries = sketch.getImportedLibraries();
+ importedLibraries.addListener(this);
+ for (Library library : importedLibraries) {
+ onInsertLibrary(library);
+ }
+ }
+
+
+ @Override
+ public void onSketchInserted(BaseSketch sketch, SketchCode code) {
+
+ if(sketch.isExternalMode()) return;
+
+ LOG.fine(code.getFileName());
+
+ Object metadata = code.getMetadata();
+ if(metadata instanceof SketchDocumentProvider){
+ Document document = ((SketchDocumentProvider) metadata).getDocument();
+ if(document != null)
+ document.addDocumentListener(realtimeCompletionsListener);
+ }
+
+ }
+
+ @Override
+ public void onSketchSaved(BaseSketch sketch, SketchCode code) {
+
+ if(sketch.isExternalMode()) return;
+
+ LOG.fine(code.getFileName());
+
+ if(sketchLibrary != null){
+ sketchLibrary.clear(); // Clear to get the new variables and remove those that no longer exist
+ }
+
+ LibraryIndex.scanFolder(sketch.getFolder(), new SketchCodeScanner(code)); // fire #onLoadLibrary on finish
+ }
+
+
+ // ==========================================
+ // LibraryIndex Listener
+ // ==========================================
+
+ @Override
+ public void onLoadLibrary(TLibrary library) {
+
+ if(sketch.isExternalMode()) return;
+
+ if(library.name().equals(SKETCH_LIB_PREFIX+sketch.getName())){ // Sketch indexing finish
+ sketchLibrary = library;
+ sketchLibrary.setReloadable(true);
+ provider.setSketchLibrary(sketchLibrary);
+ sketch.setSketchMetadata(sketchLibrary);
+ }
+
+ createCompletions(library);
+ }
+
+ @Override
+ public void onUnloadLibrary(TLibrary library) {
+ LOG.fine(library.name());
+
+ }
+
+ @Override
+ public void onReloadLibrary(TLibrary library) {
+
+ Map
+ * This feature is implemented by the swing api ({@link Position})
+ * @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ */
+public class TDynamicLocation extends TElementLocation {
+
+ private Document document;
+ private Position startOffs;
+ private Position endOffs;
+
+ private int lastEndOffs = -1;
+ private int cachedEndLine;
+ private TElementLocation reference;
+
+ public TDynamicLocation(Document document, TElement element) {
+ this(document, element.getLocation());
+ element.setLocation(this);
+ }
+
+ public TDynamicLocation(Document document, TElementLocation reference) {
+ super();
+ this.document = document;
+ try {
+ this.startOffs = document.createPosition(reference.getStartOffset());
+ this.endOffs = document.createPosition(reference.getEndOffset());
+ this.reference = reference;
+ } catch (BadLocationException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+
+ /**
+ * Returns whether the specified offset is "inside". This method
+ * returns true
if the offset is greater than the element start
+ * offset, and no further than the last offset of the last element line.
+ *
+ * @param offs The offset to check.
+ * @return Whether the offset is "inside" the element.
+ * @see #containsLine(int)
+ */
+ public boolean containsOffset(int offs) {
+ boolean contained = false;
+ if (offs>getStartOffset()) {
+ // Use Elements to avoid BadLocationExceptions
+ Element root = document.getDefaultRootElement();
+ int line = root.getElementIndex(offs);
+ contained = line<=getEndLine();
+ }
+ return contained;
+ }
+
+ /**
+ * Returns the end line of this Element.
+ *
+ * The value returned by this method will automatically update as the
+ * text area's contents are modified, to track the ending line of the
+ * code block.
+ *
+ * @return The end line of this code block.
+ * @see #getEndOffset()
+ */
+ public int getEndLine() {
+ int endOffs = getEndOffset();
+ if (lastEndOffs==endOffs) {
+ return cachedEndLine;
+ }
+ lastEndOffs = endOffs;
+ Element root = document.getDefaultRootElement();
+ return cachedEndLine = root.getElementIndex(endOffs);
+ }
+
+
+ /**
+ * Returns the starting offset of this Element.
+ *
+ * The value returned by this method will automatically update as the
+ * text area's contents are modified, to track the starting offset of the
+ * code block.
+ *
+ * @return The start offset of this fold.
+ * @see #getEndOffset()
+ */
+ public int getStartOffset() {
+ return startOffs.getOffset();
+ }
+
+ /**
+ * Returns the end offset of this Element.
+ *
+ * The value returned by this method will automatically update as the
+ * text area's contents are modified, to track the ending offset of the
+ * code block.
+ *
+ * @return The end offset of this code block.
+ * @see #getEndLine()
+ */
+ public int getEndOffset() {
+ return endOffs!=null ? endOffs.getOffset() : Integer.MAX_VALUE;
+ }
+
+
+ @Override
+ public String toString() {
+ return "["+getStartOffset()+", "+getEndOffset()+"], orig: " + reference.toString();
+ }
+
+}
diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TElementCompletion.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TElementCompletion.java
new file mode 100755
index 00000000000..7a53577ef10
--- /dev/null
+++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TElementCompletion.java
@@ -0,0 +1,114 @@
+package cc.arduino.packages.autocomplete;
+
+import org.fife.ui.autocomplete.AbstractCompletion;
+import org.fife.ui.autocomplete.Completion;
+import org.fife.ui.autocomplete.CompletionProvider;
+import org.fife.ui.rsyntaxtextarea.Token;
+
+import br.com.criativasoft.cpluslibparser.metadata.TAttribute;
+import br.com.criativasoft.cpluslibparser.metadata.TClass;
+import br.com.criativasoft.cpluslibparser.metadata.TElement;
+import br.com.criativasoft.cpluslibparser.metadata.TFunction;
+import br.com.criativasoft.cpluslibparser.metadata.TLibrary;
+
+public class TElementCompletion extends AbstractCompletion {
+
+ private TElement element;
+ private String alreadyEntered;
+
+ public TElementCompletion(CompletionProvider provider, TElement element) {
+ super(provider);
+ this.element = element;
+ }
+
+ public TElementCompletion(CompletionProvider provider, TElement element, String alreadyEntered) {
+ super(provider);
+ this.element = element;
+ this.alreadyEntered = alreadyEntered;
+ }
+
+ @Override
+ public String getReplacementText() {
+
+ if(alreadyEntered == null || alreadyEntered.length() == 0) return element.name();
+
+ return alreadyEntered + element.name();
+ }
+
+ @Override
+ public String getSummary() {
+ return element.toString();
+ }
+
+ @Override
+ public String getInputText() {
+ return element.name();
+ }
+
+ public TElement getElement() {
+ return element;
+ }
+
+ public String getShortDescription(){
+ return element.name();
+ }
+
+
+ public CompletionType getType(){
+
+ if(element instanceof TLibrary){
+ return CompletionType.LIBRARY;
+ }
+
+ if(element instanceof TClass){
+ return CompletionType.CLASS;
+ }
+
+ if(element instanceof TFunction){
+ return CompletionType.FUNCTION;
+ }
+
+ if(element instanceof TAttribute){
+ TAttribute attribute = (TAttribute) element;
+ if(attribute.isLocal()) return CompletionType.LOCAL_VAR;
+ if(attribute.isEnum()) return CompletionType.ENUM;
+ if(attribute.isStatic()) return CompletionType.STATIC_VAR;
+ return CompletionType.VARIABLE;
+ }
+
+ return CompletionType.VARIABLE;
+
+ }
+
+
+ @Override
+ public int getRelevance() {
+ if(element instanceof TLibrary){
+ return 1;
+ }
+
+ if(element instanceof TClass){
+ return 2;
+ }
+
+ if(element instanceof TFunction){
+ return 3;
+ }
+
+ if(element instanceof TAttribute){
+ TAttribute attribute = (TAttribute) element;
+ if(attribute.isLocal()) return 7;
+ if(attribute.isEnum()) return 5;
+ if(attribute.isStatic()) return 4;
+ return 6;
+ }
+
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return element.name();
+ }
+
+}
diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TElementFilter.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TElementFilter.java
new file mode 100755
index 00000000000..19b56b4594d
--- /dev/null
+++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TElementFilter.java
@@ -0,0 +1,46 @@
+package cc.arduino.packages.autocomplete;
+
+import processing.app.helpers.IPredicate;
+import br.com.criativasoft.cpluslibparser.metadata.TElement;
+
+/**
+ * Simple collections filter
+ * @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ */
+public class TElementFilter
+ * Generally this is only done once, rather than + * each time a change is made, because otherwise it gets to be + * a nightmare to keep track of what files went where, because + * not all the data will be saved to disk. + *
+ * This also gets called when the main sketch file is renamed, + * because the sketch has to be reloaded from a different folder. + *
+ * Another exception is when an external editor is in use, + * in which case the load happens each time "run" is hit. + */ + protected abstract void load() throws IOException; + + /** + * Handler for the New Code menu option. + */ + public abstract void handleNewCode(); + + /** + * Handler for the Rename Code menu option. + */ + public abstract void handleRenameCode(); + + + /** + * This is called upon return from entering a new file name. + * (that is, from either newCode or renameCode after the prompt) + * This code is almost identical for both the newCode and renameCode + * cases, so they're kept merged except for right in the middle + * where they diverge. + */ + protected abstract void nameCode(String newName); + + + /** + * Remove a piece of code from the sketch and from the disk. + */ + public abstract void handleDeleteCode(); + + + /** + * Move to the previous tab. + */ + public void handlePrevCode() { + int prev = currentIndex - 1; + if (prev < 0) prev = data.getCodeCount()-1; + setCurrentCode(prev); + } + + + /** + * Move to the next tab. + */ + public void handleNextCode() { + setCurrentCode((currentIndex + 1) % data.getCodeCount()); + } + + + /** + * Sets the modified value for the code in the frontmost tab. + */ + public abstract void setModified(boolean state); + + + protected abstract void calcModified(); + + + public boolean isModified() { + return modified; + } + + + /** + * Save all code in the current sketch. + */ + public abstract boolean save() throws IOException; + + + protected boolean renameCodeToInoExtension(File pdeFile) { + for (SketchCode c : data.getCodes()) { + if (!c.getFile().equals(pdeFile)) + continue; + + String pdeName = pdeFile.getPath(); + pdeName = pdeName.substring(0, pdeName.length() - 4) + ".ino"; + return c.renameTo(new File(pdeName)); + } + return false; + } + + + /** + * Handles 'Save As' for a sketch. + *
+ * This basically just duplicates the current sketch folder to + * a new location, and then calls 'Save'. (needs to take the current + * state of the open files and save them to the new folder.. + * but not save over the old versions for the old sketch..) + *
+ * Also removes the previously-generated .class and .jar files, + * because they can cause trouble. + */ + protected abstract boolean saveAs() throws IOException; + + + /** + * Prompt the user for a new file to the sketch, then call the + * other addFile() function to actually add it. + */ + public abstract void handleAddFile(); + + + /** + * Add a file to the sketch. + *
+ * .pde or .java files will be added to the sketch folder.+ * There are three main parts to this process: + *
+ * (0. if not java, then use another 'engine'.. i.e. python) + * + * 1. do the p5 language preprocessing + * this creates a working .java file in a specific location + * better yet, just takes a chunk of java code and returns a + * new/better string editor can take care of saving this to a + * file location + * + * 2. compile the code from that location + * catching errors along the way + * placing it in a ready classpath, or .. ? + * + * 3. run the code + * needs to communicate location for window + * and maybe setup presentation space as well + * run externally if a code folder exists, + * or if more than one file is in the project + * + * X. afterwards, some of these steps need a cleanup function + *+ */ + //protected String compile() throws RunnerException { + + /** + * When running from the editor, take care of preparations before running + * the build. + */ + public abstract void prepare() throws IOException; + + + + /** + * Map an error from a set of processed .java files back to its location + * in the actual sketch. + * @param message The error message. + * @param filename The .java file where the exception was found. + * @param line Line number of the .java file for the exception (1-indexed) + * @return A RunnerException to be sent to the editor, or null if it wasn't + * possible to place the exception to the sketch code. + */ +// public RunnerException placeExceptionAlt(String message, +// String filename, int line) { +// String appletJavaFile = appletClassName + ".java"; +// SketchCode errorCode = null; +// if (filename.equals(appletJavaFile)) { +// for (SketchCode code : getCode()) { +// if (code.isExtension("ino")) { +// if (line >= code.getPreprocOffset()) { +// errorCode = code; +// } +// } +// } +// } else { +// for (SketchCode code : getCode()) { +// if (code.isExtension("java")) { +// if (filename.equals(code.getFileName())) { +// errorCode = code; +// } +// } +// } +// } +// int codeIndex = getCodeIndex(errorCode); +// +// if (codeIndex != -1) { +// //System.out.println("got line num " + lineNumber); +// // in case this was a tab that got embedded into the main .java +// line -= getCode(codeIndex).getPreprocOffset(); +// +// // lineNumber is 1-indexed, but editor wants zero-indexed +// line--; +// +// // getMessage() will be what's shown in the editor +// RunnerException exception = +// new RunnerException(message, codeIndex, line, -1); +// exception.hideStackTrace(); +// return exception; +// } +// return null; +// } + + + /** + * Run the build inside the temporary build folder. + * @return null if compilation failed, main class name if not + * @throws RunnerException + */ + public abstract String build(boolean verbose) throws RunnerException, PreferencesMapException; + + /** + * Preprocess and compile all the code for this sketch. + * + * In an advanced program, the returned class name could be different, + * which is why the className is set based on the return value. + * A compilation error will burp up a RunnerException. + * + * @return null if compilation failed, main class name if not + */ + public abstract String build(String buildPath, boolean verbose) throws RunnerException, PreferencesMapException; + + protected abstract boolean exportApplet(boolean usingProgrammer) throws Exception; + + + /** + * Handle export to applet. + */ + public abstract boolean exportApplet(String appletPath, boolean usingProgrammer) + throws Exception; + + + protected abstract boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws Exception; + + + public boolean exportApplicationPrompt() throws IOException, RunnerException { + return false; + } + + + /** + * Export to application via GUI. + */ + protected boolean exportApplication() throws IOException, RunnerException { + return false; + } + + + /** + * Export to application without GUI. + */ + public boolean exportApplication(String destPath, + int exportPlatform) throws IOException, RunnerException { + return false; + } + + + /** + * Make sure the sketch hasn't been moved or deleted by some + * nefarious user. If they did, try to re-create it and save. + * Only checks to see if the main folder is still around, + * but not its contents. + */ + protected void ensureExistence() { + if (data.getFolder().exists()) return; + + BaseNoGui.showWarning(_("Sketch Disappeared"), + _("The sketch folder has disappeared.\n " + + "Will attempt to re-save in the same location,\n" + + "but anything besides the code will be lost."), null); + try { + data.getFolder().mkdirs(); + modified = true; + + for (SketchCode code : data.getCodes()) { + code.save(); // this will force a save + } + calcModified(); + + } catch (Exception e) { + BaseNoGui.showWarning(_("Could not re-save sketch"), + _("Could not properly re-save the sketch. " + + "You may be in trouble at this point,\n" + + "and it might be time to copy and paste " + + "your code to another text editor."), e); + } + } + + + /** + * Returns true if this is a read-only sketch. Used for the + * examples directory, or when sketches are loaded from read-only + * volumes or folders without appropriate permissions. + */ + public boolean isReadOnly() { + String apath = data.getFolder().getAbsolutePath(); + for (File folder : BaseNoGui.getLibrariesPath()) { + if (apath.startsWith(folder.getAbsolutePath())) + return true; + } + if (apath.startsWith(BaseNoGui.getExamplesPath()) || + apath.startsWith(BaseNoGui.getSketchbookLibrariesFolder().getAbsolutePath())) { + return true; + } + + // canWrite() doesn't work on directories + // } else if (!folder.canWrite()) { + + // check to see if each modified code file can be written to + for (SketchCode code : data.getCodes()) { + if (code.isModified() && code.fileReadOnly() && code.fileExists()) { + // System.err.println("found a read-only file " + code[i].file); + return true; + } + } + return false; + } + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + // Breaking out extension types in order to clean up the code, and make it + // easier for other environments (like Arduino) to incorporate changes. + + /** + * True if the specified code has the default file extension. + */ + public boolean hasDefaultExtension(SketchCode code) { + return code.isExtension(getDefaultExtension()); + } + + + /** + * True if the specified extension is the default file extension. + */ + public boolean isDefaultExtension(String what) { + return what.equals(getDefaultExtension()); + } + + + /** + * Check this extension (no dots, please) against the list of valid + * extensions. + */ + public boolean validExtension(String what) { + return data.getExtensions().contains(what); + } + + + /** + * Returns the default extension for this editor setup. + */ + public String getDefaultExtension() { + return data.getDefaultExtension(); + } + + static private List