diff --git a/.project b/.project index 0b76a40ba80..666006c4305 100644 --- a/.project +++ b/.project @@ -1,17 +1,17 @@ - - - processing-head - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - + + + processing-head + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/app/.classpath b/app/.classpath index 8d33d06788f..0f1066dfec9 100644 --- a/app/.classpath +++ b/app/.classpath @@ -31,5 +31,8 @@ + + + diff --git a/app/.project b/app/.project index 69a82c3d004..78e91ccbbfa 100644 --- a/app/.project +++ b/app/.project @@ -1,17 +1,17 @@ - - - processing - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - + + + processing + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/app/.settings/org.eclipse.jdt.core.prefs b/app/.settings/org.eclipse.jdt.core.prefs index 4b64040da73..462c9daed55 100644 --- a/app/.settings/org.eclipse.jdt.core.prefs +++ b/app/.settings/org.eclipse.jdt.core.prefs @@ -1,20 +1,11 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.autoboxing=ignore org.eclipse.jdt.core.compiler.problem.deprecation=warning org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled org.eclipse.jdt.core.compiler.problem.discouragedReference=warning org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled org.eclipse.jdt.core.compiler.problem.fieldHiding=warning @@ -62,7 +53,6 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=di org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.6 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 diff --git a/app/build.xml b/app/build.xml index 4c20976b60d..1119d468738 100644 --- a/app/build.xml +++ b/app/build.xml @@ -7,6 +7,7 @@ + diff --git a/app/lib/cplus-libparser-0.0.1.jar b/app/lib/cplus-libparser-0.0.1.jar new file mode 100755 index 00000000000..8d9122aeb7e Binary files /dev/null and b/app/lib/cplus-libparser-0.0.1.jar differ diff --git a/app/lib/rsyntax-autocomplete-2.6.0-SNAPSHOT.jar b/app/lib/rsyntax-autocomplete-2.6.0-SNAPSHOT.jar new file mode 100755 index 00000000000..12beccfef93 Binary files /dev/null and b/app/lib/rsyntax-autocomplete-2.6.0-SNAPSHOT.jar differ diff --git a/app/src/ArduinoIDE.java b/app/src/ArduinoIDE.java new file mode 100755 index 00000000000..ad7adcabca8 --- /dev/null +++ b/app/src/ArduinoIDE.java @@ -0,0 +1,46 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +import processing.app.Base; + +/** + * Arduino IDE Launcher class + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + * @date 23/01/2015 + */ +public class ArduinoIDE { + + public static void main(String[] args) throws Exception { + Base.main(args); + } + +} diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 6f31a2b7281..e2cefd4e0d2 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -36,11 +36,14 @@ import cc.arduino.utils.Progress; import cc.arduino.view.*; import cc.arduino.view.Event; + import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; + import org.apache.commons.compress.utils.IOUtils; import org.apache.commons.lang3.StringUtils; + import processing.app.debug.TargetBoard; import processing.app.debug.TargetPackage; import processing.app.debug.TargetPlatform; @@ -64,10 +67,6 @@ import java.io.*; import java.util.*; import java.util.List; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.Logger; - import static processing.app.I18n._; @@ -146,8 +145,6 @@ static public void guardedMain(String args[]) throws Exception { BaseNoGui.initLogger(); - initLogger(); - BaseNoGui.initPlatform(); BaseNoGui.getPlatform().init(); @@ -226,35 +223,6 @@ static public void guardedMain(String args[]) throws Exception { INSTANCE = new Base(args); } - - static public void initLogger() { - Handler consoleHandler = new ConsoleLogger(); - consoleHandler.setLevel(Level.ALL); - consoleHandler.setFormatter(new LogFormatter("%1$tl:%1$tM:%1$tS [%4$7s] %2$s: %5$s%n")); - - Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); - globalLogger.setLevel(consoleHandler.getLevel()); - - // Remove default - Handler[] handlers = globalLogger.getHandlers(); - for(Handler handler : handlers) { - globalLogger.removeHandler(handler); - } - Logger root = Logger.getLogger(""); - handlers = root.getHandlers(); - for(Handler handler : handlers) { - root.removeHandler(handler); - } - - globalLogger.addHandler(consoleHandler); - - Logger.getLogger("cc.arduino.packages.autocomplete").setParent(globalLogger); - Logger.getLogger("br.com.criativasoft.cpluslibparser").setParent(globalLogger); - Logger.getLogger(Base.class.getPackage().getName()).setParent(globalLogger); - - } - - static protected void setCommandLine() { commandLine = true; } diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index e9e987c2f67..cd6c6c08bf3 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -22,14 +22,20 @@ package processing.app; +import br.com.criativasoft.cpluslibparser.LibraryIndex; +import br.com.criativasoft.cpluslibparser.metadata.TElementLocation; +import br.com.criativasoft.cpluslibparser.metadata.TError; +import br.com.criativasoft.cpluslibparser.metadata.TLibrary; import cc.arduino.packages.MonitorFactory; - import cc.arduino.view.StubMenuListener; import cc.arduino.view.findreplace.FindReplace; + import com.google.common.base.Predicate; import com.jcraft.jsch.JSchException; + import jssc.SerialPortException; import processing.app.debug.*; +import processing.app.debug.Compiler; import processing.app.forms.PasswordAuthorizationDialog; import processing.app.helpers.OSUtils; import processing.app.helpers.PreferencesMapException; @@ -62,6 +68,7 @@ import cc.arduino.packages.BoardPort; import cc.arduino.packages.Uploader; +import cc.arduino.packages.autocomplete.SketchCompletionProvider; import cc.arduino.packages.uploaders.SerialUploader; /** @@ -148,6 +155,7 @@ public boolean apply(Sketch sketch) { Sketch sketch; private EditorLineStatus lineStatus; + SyntaxErrorMarker errorMarker; //JEditorPane editorPane; @@ -204,6 +212,11 @@ public void windowClosing(WindowEvent e) { addWindowListener(new WindowAdapter() { public void windowActivated(WindowEvent e) { base.handleActivated(Editor.this); + + if(sketch != null){ + LibraryIndex.setContextCache(sketch.getSketchData().getLibraryCacheContext()); + } + } // added for 1.0.5 @@ -995,6 +1008,7 @@ private String findClassInZipFile(String base, File file) { private SketchTextArea createTextArea() throws IOException { final SketchTextArea textArea = new SketchTextArea(base.getPdeKeywords()); + textArea.addParser(new TokenErrorMarker(textArea)); textArea.setFocusTraversalKeysEnabled(false); textArea.requestFocusInWindow(); textArea.setMarkOccurrences(PreferencesData.getBoolean("editor.advanced")); @@ -1756,7 +1770,7 @@ protected void setCode(final SketchCodeDocument codeDoc) { if(codeDoc.getUndo() == null){ codeDoc.setUndo(new LastUndoableEditAwareUndoManager(textarea, this)); document.addUndoableEditListener(codeDoc.getUndo()); - } + } // Update the document object that's in use textarea.switchDocument(document, codeDoc.getUndo()); @@ -1767,6 +1781,8 @@ protected void setCode(final SketchCodeDocument codeDoc) { textarea.select(codeDoc.getSelectionStart(), codeDoc.getSelectionStop()); textarea.requestFocus(); // get the caret blinking + + if(errorMarker != null) errorMarker.setCurrentCode(codeDoc.getCode()); final int position = codeDoc.getScrollPosition(); @@ -1951,6 +1967,7 @@ public BuildHandler(boolean verbose, boolean saveHex) { public void run() { try { textarea.removeAllLineHighlights(); + errorMarker.removeAll(); sketch.prepare(); sketch.build(verbose, saveHex); statusNotice(_("Done compiling.")); @@ -2184,6 +2201,18 @@ protected boolean handleOpenInternal(File sketchFile) { try { sketch = new Sketch(this, file); + + LibraryIndex.setContextCache(sketch.getSketchData().getLibraryCacheContext()); + + // This needs to be after the ' LibraryIndex.setContextCache' for listeners work properly (on SketchCompletionProvider) + textarea.setupAutoComplete(new SketchCompletionProvider(sketch.getSketchData())); + + // This needs to be after the ' LibraryIndex.setContextCache' for listeners work properly + if(errorMarker == null){ + errorMarker = new SyntaxErrorMarker(textarea); + textarea.addParser(errorMarker); + } + } catch (IOException e) { Base.showWarning(_("Error"), _("Could not create the sketch."), e); return false; @@ -2659,39 +2688,57 @@ public void statusError(String what) { */ public void statusError(Exception e) { e.printStackTrace(); -// if (e == null) { -// System.err.println("Editor.statusError() was passed a null exception."); -// return; -// } if (e instanceof RunnerException) { RunnerException re = (RunnerException) e; - if (re.hasCodeIndex()) { - sketch.setCurrentCode(re.getCodeIndex()); - } - if (re.hasCodeLine()) { - int line = re.getCodeLine(); - // subtract one from the end so that the \n ain't included - if (line >= textarea.getLineCount()) { - // The error is at the end of this current chunk of code, - // so the last line needs to be selected. - line = textarea.getLineCount() - 1; - if (getLineText(line).length() == 0) { - // The last line may be zero length, meaning nothing to select. - // If so, back up one more line. - line--; + + if (re.getErrors() != null && ! re.getErrors().isEmpty()) { + + List errors = re.getErrors(); + + for (CompilerError compilerError : errors) { + + sketch.setCurrentCode(compilerError.getFileName()); + + int line = compilerError.getLine(); + // subtract one from the end so that the \n ain't included + if (line >= textarea.getLineCount()) { + // The error is at the end of this current chunk of code, + // so the last line needs to be selected. + line = textarea.getLineCount() - 1; + if (getLineText(line).length() == 0) { + // The last line may be zero length, meaning nothing to select. + // If so, back up one more line. + line--; + } } - } - if (line < 0 || line >= textarea.getLineCount()) { - System.err.println(I18n.format(_("Bad error line: {0}"), line)); - } else { - try { - textarea.addLineHighlight(line, new Color(1, 0, 0, 0.2f)); - textarea.setCaretPosition(textarea.getLineStartOffset(line)); - } catch (BadLocationException e1) { - e1.printStackTrace(); + if (line < 0 || line >= textarea.getLineCount()) { + System.err.println(I18n.format(_("Bad error line: {0}"), line)); + } else { + try { + // textarea.addLineHighlight(line, new Color(1, 0, 0, 0.2f)); + textarea.setCaretPosition(textarea.getLineStartOffset(line)); + + TLibrary metadata = sketch.getSketchData().getSketchMetadata(); + int startOffset = textarea.getLineStartOffset(line); + int endOffset = textarea.getLineEndOffset(line); + String path = sketch.getCurrentCode().getFile().getPath(); + + TError error = new TError(compilerError.getMessage(), TError.COMPILER_ERROR); + error.setLocation(new TElementLocation(path, startOffset, endOffset - startOffset)); + errorMarker.addError(error); + textarea.forceReparsing(errorMarker); + + if(metadata != null){ + metadata.getErrors().add(error); + } + } catch (BadLocationException e1) { + e1.printStackTrace(); + } } + } + } } diff --git a/app/src/processing/app/EditorListener.java b/app/src/processing/app/EditorListener.java index cbd082cfcad..5e6246461ca 100644 --- a/app/src/processing/app/EditorListener.java +++ b/app/src/processing/app/EditorListener.java @@ -5,7 +5,13 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; +import javax.swing.text.BadLocationException; + +import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; +import org.fife.ui.rsyntaxtextarea.Token; + import processing.app.syntax.SketchTextArea; +import cc.arduino.packages.autocomplete.SketchCompletionProvider; public class EditorListener implements KeyListener { @@ -67,7 +73,26 @@ public void keyPressed(KeyEvent event) { // int line = textarea.getCaretLineNumber(); // textarea.setActiveLineRange(line, line + 3); // } - + + // Generate New Variable + if (event.isAltDown() && code == KeyEvent.VK_ENTER) { + + int line = textarea.getCaretLineNumber(); + + Token tokenListForLine = textarea.getTokenListForLine(line); + int start = RSyntaxUtilities.getNextImportantToken(tokenListForLine, textarea, line).getOffset(); + int end = textarea.getLineEndOffsetOfCurrentLine(); + + try { + String expression = textarea.getText(start, end - start); + SketchCompletionProvider provider = textarea.getCompletionProvider(); + provider.generateNewVariableFor(expression, start); + + + + } catch (BadLocationException e) {} + + } } @Override diff --git a/app/src/processing/app/LastUndoableEditAwareUndoManager.java b/app/src/processing/app/LastUndoableEditAwareUndoManager.java old mode 100644 new mode 100755 diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 9cae9d25e04..feec97f0b33 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -997,6 +997,7 @@ public void setCurrentCode(int which, boolean forceUpdate) { current = (SketchCodeDocument) data.getCode(which).getMetadata(); currentIndex = which; + data.setCurrentCode(current.getCode()); editor.setCode(current); editor.header.rebuild(); @@ -1375,6 +1376,9 @@ public boolean isUntitled() { return editor.untitled; } + public SketchData getSketchData() { + return data; + } // ................................................................. diff --git a/app/src/processing/app/SketchCodeDocument.java b/app/src/processing/app/SketchCodeDocument.java index 681f0af9151..f8bf711b656 100644 --- a/app/src/processing/app/SketchCodeDocument.java +++ b/app/src/processing/app/SketchCodeDocument.java @@ -7,7 +7,7 @@ import javax.swing.text.Document; import javax.swing.undo.UndoManager; -public class SketchCodeDocument implements DocumentListener{ +public class SketchCodeDocument implements DocumentListener, SketchDocumentProvider{ private SketchCode code; private Sketch sketch; diff --git a/app/src/processing/app/syntax/SketchTextArea.java b/app/src/processing/app/syntax/SketchTextArea.java index f31a45ab39a..5060510e1ca 100644 --- a/app/src/processing/app/syntax/SketchTextArea.java +++ b/app/src/processing/app/syntax/SketchTextArea.java @@ -30,25 +30,12 @@ package processing.app.syntax; -import org.apache.commons.compress.utils.IOUtils; -import org.fife.ui.rsyntaxtextarea.*; -import org.fife.ui.rsyntaxtextarea.Theme; -import org.fife.ui.rsyntaxtextarea.Token; -import org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip; -import org.fife.ui.rtextarea.RTextArea; -import org.fife.ui.rtextarea.RTextAreaUI; -import org.fife.ui.rtextarea.RUndoManager; -import processing.app.*; - -import javax.swing.*; -import javax.swing.event.EventListenerList; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; -import javax.swing.text.Segment; -import javax.swing.undo.UndoManager; -import java.awt.*; +import java.awt.AWTKeyStroke; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Font; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.io.File; @@ -57,10 +44,54 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; +import javax.swing.event.EventListenerList; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Segment; +import javax.swing.undo.UndoManager; + +import org.apache.commons.compress.utils.IOUtils; +import org.fife.ui.autocomplete.AutoCompletion; +import org.fife.ui.autocomplete.AutoCompletionEvent; +import org.fife.ui.autocomplete.AutoCompletionListener; +import org.fife.ui.autocomplete.ParameterizedCompletion; +import org.fife.ui.autocomplete.ParameterizedCompletionEvent; +import org.fife.ui.rsyntaxtextarea.LinkGenerator; +import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.Style; +import org.fife.ui.rsyntaxtextarea.Theme; +import org.fife.ui.rsyntaxtextarea.Token; +import org.fife.ui.rsyntaxtextarea.TokenImpl; +import org.fife.ui.rsyntaxtextarea.TokenTypes; +import org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip; +import org.fife.ui.rtextarea.RTextArea; +import org.fife.ui.rtextarea.RTextAreaUI; +import org.fife.ui.rtextarea.RUndoManager; + +import processing.app.Base; +import processing.app.BaseNoGui; +import processing.app.EditorListener; +import processing.app.PreferencesData; +import processing.app.packages.UserLibrary; +import br.com.criativasoft.cpluslibparser.metadata.TAttribute; +import br.com.criativasoft.cpluslibparser.metadata.TFunction; +import cc.arduino.packages.autocomplete.CompletionsRenderer; +import cc.arduino.packages.autocomplete.RealtimeCompletionsListener; +import cc.arduino.packages.autocomplete.SketchCompletionProvider; +import cc.arduino.packages.autocomplete.TDynamicLocation; +import cc.arduino.packages.autocomplete.template.GenerateVarTemplate; +import cc.arduino.packages.autocomplete.template.IncludeTemplate; + /** * Arduino Sketch code editor based on RSyntaxTextArea (http://fifesoft.com/rsyntaxtextarea) * @@ -81,6 +112,8 @@ public class SketchTextArea extends RSyntaxTextArea { private final PdeKeywords pdeKeywords; + private SketchCompletionProvider completionProvider; + public SketchTextArea(PdeKeywords pdeKeywords) throws IOException { this.pdeKeywords = pdeKeywords; installFeatures(); @@ -139,6 +172,73 @@ private void setSyntaxTheme(int tokenType, String id) { getSyntaxScheme().setStyle(tokenType, style); } + + public void setupAutoComplete(SketchCompletionProvider provider) { + + if(this.completionProvider != null){ + completionProvider.uninstall(); + } + + this.completionProvider = provider; + AutoCompletion ac = new AutoCompletion(provider); + + + ac.setAutoActivationEnabled(true); + ac.setShowDescWindow(false); + ac.setListCellRenderer(new CompletionsRenderer()); + ac.setParamChoicesRenderer(new CompletionsRenderer()); + ac.setAutoCompleteSingleChoices(true); + ac.setParameterAssistanceEnabled(true); + + ac.install(this); + provider.setAutoCompletion(ac); + + ac.addAutoCompletionListener(new AutoCompletionListener() { + @Override + public void autoCompleteUpdate(AutoCompletionEvent e) { + + if(e instanceof ParameterizedCompletionEvent){ + ParameterizedCompletionEvent event = (ParameterizedCompletionEvent) e; + + ParameterizedCompletion completion = event.getCompletion(); + + if(e.getEventType() == AutoCompletionEvent.Type.PARAMETER_COMPLETION_FINISH){ + List parameterValues = event.getContext().getParameterValues(); + + // Force parser/load new Lib for autocomplete. + if(completion instanceof IncludeTemplate && !parameterValues.isEmpty()){ + UserLibrary library = Base.getLibraries().getByName(parameterValues.get(0).replaceAll("(<|>|\\.h)", "")); + getCompletionProvider().getSketchData().addLibrary(library); + } + + if(completion instanceof GenerateVarTemplate && !parameterValues.isEmpty()){ + GenerateVarTemplate varTemplate = (GenerateVarTemplate) completion; + TAttribute var = new TAttribute(varTemplate.getType(), parameterValues.iterator().next()); + + // Insert new var in current function scope + TFunction functionScope = getCompletionProvider().getCurrentFunctionScope(SketchTextArea.this); + if(functionScope != null){ + TDynamicLocation location = new TDynamicLocation(SketchTextArea.this.getDocument(), functionScope.getLocation()); + var.setLocation(location); + functionScope.addLocalVariable(var); + } + + } + + } + + if(e.getEventType() == AutoCompletionEvent.Type.PARAMETER_COMPLETION_SELECT){ + + } + } + } + }); + + } + + public SketchCompletionProvider getCompletionProvider() { + return completionProvider; + } // Removing the default focus traversal keys // This is because the DefaultKeyboardFocusManager handles the keypress and consumes the event diff --git a/app/src/processing/app/syntax/SyntaxErrorMarker.java b/app/src/processing/app/syntax/SyntaxErrorMarker.java new file mode 100755 index 00000000000..a874bf100e9 --- /dev/null +++ b/app/src/processing/app/syntax/SyntaxErrorMarker.java @@ -0,0 +1,187 @@ +package processing.app.syntax; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Element; + +import org.fife.ui.rsyntaxtextarea.RSyntaxDocument; +import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; +import org.fife.ui.rsyntaxtextarea.parser.*; +import org.fife.ui.rtextarea.Gutter; +import org.fife.ui.rtextarea.GutterIconInfo; + +import processing.app.Sketch; +import processing.app.SketchCode; +import br.com.criativasoft.cpluslibparser.LibraryIndex; +import br.com.criativasoft.cpluslibparser.LibraryIndexListener; +import br.com.criativasoft.cpluslibparser.metadata.TError; +import br.com.criativasoft.cpluslibparser.metadata.TLibrary; +import cc.arduino.packages.autocomplete.ArduinoLibraryScanner; +import cc.arduino.packages.autocomplete.CompletionType; +import cc.arduino.packages.autocomplete.CompletionsRenderer; +import cc.arduino.packages.autocomplete.SketchCodeScanner; +import cc.arduino.packages.autocomplete.SketchCompletionProvider; + + +/** + * Shows the result of the errors found after running the parser ({@link LibraryIndex}, {@link SketchCodeScanner}).
+ * 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; + private SketchCode currentCode; + + // TODO: this can be removed on fix: https://github.com/bobbylight/RSyntaxTextArea/issues/87 + private Gutter gutter; + private List errorIcons = new ArrayList(); + + public SyntaxErrorMarker(SketchTextArea textarea) { + this.textarea = textarea; + this.gutter = RSyntaxUtilities.getGutter(textarea); + LibraryIndex.addListener(this); + result = new DefaultParseResult(this); + } + + @Override + public ParseResult parse(RSyntaxDocument doc, String style) { + + Element root = doc.getDefaultRootElement(); + int lineCount = root.getElementCount(); + + if(sketchLibrary != null){ + result.setParsedLines(0, lineCount-1); + } + + return result; + } + + + @Override + public void onLoadLibrary(TLibrary library) { + if(library.name().startsWith(ArduinoLibraryScanner.SKETCH_LIB_PREFIX)){ // Sketch indexing finish + sketchLibrary = library; + collectErrors(); + } + } + + + @Override + public void onUnloadLibrary(TLibrary library) { + if(library.name().startsWith(ArduinoLibraryScanner.SKETCH_LIB_PREFIX)){ // Sketch indexing finish + removeAll(); + } + } + + @Override + public void onReloadLibrary(TLibrary library) { + if(library.name().startsWith(ArduinoLibraryScanner.SKETCH_LIB_PREFIX)){ // Sketch indexing finish + sketchLibrary = library; + collectErrors(); + } + } + + private void collectErrors(){ + + if(sketchLibrary != null){ + + Set errors = sketchLibrary.getErrors(); + + result.clearNotices(); + + for (GutterIconInfo gutterIconInfo : errorIcons) { + gutter.removeTrackingIcon(gutterIconInfo); + } + + if(!errors.isEmpty()){ + for (TError error : errors) { + addError(error); + } + } + textarea.forceReparsing(this); + } + + } + + public void addError(TError error){ + ErrorParserNotice notice = new ErrorParserNotice(this, error); + result.addNotice(notice); + // TODO: This(gutter) can be removed on fix: RSyntaxTextArea/issues/87 + if(gutter != null){ + try { + GutterIconInfo errorIcon = gutter.addOffsetTrackingIcon(error.getStartOffset(), CompletionsRenderer.getIcon(CompletionType.ERROR), error.name()); + errorIcons.add(errorIcon); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + } + + public static class ErrorParserNotice extends DefaultParserNotice{ + + private TError error; + private SyntaxErrorMarker parser; + + public ErrorParserNotice(SyntaxErrorMarker parser, TError error) { + super(parser, error.getName(), -1, error.getStartOffset() , error.getLength()); + this.error = error; + this.parser = parser; + setColor(Color.RED); + setShowInEditor(true); + } + + public TError getError() { + return error; + } + + @Override + public String getToolTipText() { + return error.getName(); + } + + @Override + public boolean getShowInEditor() { + + if(parser.getCurrentCode() != null){ + + String path = parser.getCurrentCode().getFile().getPath(); + + if(error.getPath() != null){ + return error.getPath().equals(path); + }else{ + return super.getShowInEditor(); + } + + }else{ + return super.getShowInEditor(); + } + + } + + } + + public void removeAll() { + result.clearNotices(); + textarea.forceReparsing(this); + for (GutterIconInfo gutterIconInfo : errorIcons) { + gutter.removeTrackingIcon(gutterIconInfo); + } + } + + public void setCurrentCode(SketchCode currentCode) { + this.currentCode = currentCode; + textarea.forceReparsing(this); + } + + public SketchCode getCurrentCode() { + return currentCode; + } + +} 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; line 0 && end == -1) end = t.getOffset(); + } + t = t.getNextToken(); + } + + if (start>-1) { + DefaultParserNotice pn = new DefaultParserNotice(this, "syntax error", line, start, (end-start)); + pn.setLevel(ParserNotice.Level.ERROR); + pn.setColor(Color.RED); + result.addNotice(pn); + found = true; + } + + return found; + } + + private boolean isError(Token token){ + + switch (token.getType()) { + case Token.ERROR_CHAR: + case Token.ERROR_IDENTIFIER: + case Token.ERROR_NUMBER_FORMAT: + case Token.ERROR_STRING_DOUBLE: + return true; + } + + return false; + } + +} diff --git a/arduino-autocomplete/.classpath b/arduino-autocomplete/.classpath new file mode 100755 index 00000000000..b8f3695e6f6 --- /dev/null +++ b/arduino-autocomplete/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/arduino-autocomplete/.gitignore b/arduino-autocomplete/.gitignore new file mode 100755 index 00000000000..583ba9546e9 --- /dev/null +++ b/arduino-autocomplete/.gitignore @@ -0,0 +1,2 @@ +/bin/ +arduino-autocomplete.jar \ No newline at end of file diff --git a/arduino-autocomplete/.project b/arduino-autocomplete/.project new file mode 100755 index 00000000000..16edc16e828 --- /dev/null +++ b/arduino-autocomplete/.project @@ -0,0 +1,17 @@ + + + arduino-autocomplete + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/arduino-autocomplete/build.xml b/arduino-autocomplete/build.xml new file mode 100755 index 00000000000..700d73254f4 --- /dev/null +++ b/arduino-autocomplete/build.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/ArduinoLibraryScanner.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/ArduinoLibraryScanner.java new file mode 100755 index 00000000000..76d24041da4 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/ArduinoLibraryScanner.java @@ -0,0 +1,89 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.packages.autocomplete; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import processing.app.helpers.filefilters.OnlyFilesWithExtension; +import processing.app.packages.UserLibrary; +import br.com.criativasoft.cpluslibparser.LibraryScanner; +import br.com.criativasoft.cpluslibparser.SourceParser; + +/** + * Scanner for Arduino libraries. + * This class is only a bridge between the libraries and the {@link SourceParser}, making the settings and adjustments + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + * @date 20/11/2014 + */ +public class ArduinoLibraryScanner extends LibraryScanner { + + public static final String SKETCH_LIB_PREFIX = "private:sketch:"; // for autocomplete metadata + + private UserLibrary library; + + private static final List ignoredFiles = new ArrayList(); + + static{ + ignoredFiles.add("USBCore.h"); + ignoredFiles.add("USBDesc.h"); + } + + public ArduinoLibraryScanner(UserLibrary library) { + this.library = library; + } + + @Override + protected File[] getFilesToParse(File folder) { + + // check /src directory + File src = new File(folder, "src"); + if(src.exists()){ + folder = src; + } + + return folder.listFiles(new OnlyFilesWithExtension(ignoredFiles, ".h")); + } + + @Override + protected void configParser(SourceParser parser, File currentFile) { + parser.addMacro("UBRR0H", "1"); // Enable Serial ! + } + + @Override + protected String getLibraryName() { + return library.getName(); + } + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionProviderWithContext.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionProviderWithContext.java new file mode 100755 index 00000000000..dbf314dd082 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionProviderWithContext.java @@ -0,0 +1,376 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +import javax.swing.text.JTextComponent; + +import org.fife.ui.autocomplete.Completion; +import org.fife.ui.autocomplete.DefaultCompletionProvider; +import org.fife.ui.autocomplete.FunctionCompletion; +import org.fife.ui.autocomplete.Util; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; + +import processing.app.helpers.Predicate; +import br.com.criativasoft.cpluslibparser.LibraryIndex; +import br.com.criativasoft.cpluslibparser.metadata.TAttribute; +import br.com.criativasoft.cpluslibparser.metadata.TClass; +import br.com.criativasoft.cpluslibparser.metadata.TClass.TClassType; +import br.com.criativasoft.cpluslibparser.metadata.TElement; +import br.com.criativasoft.cpluslibparser.metadata.TElementLocation; +import br.com.criativasoft.cpluslibparser.metadata.TFunction; +import br.com.criativasoft.cpluslibparser.metadata.TLibrary; + +/** + * Autocomplete logic implementation for instance functions, static functions and local variables. + * It determines the options that will be presented in accordance with the current context. + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + */ +public class CompletionProviderWithContext extends DefaultCompletionProvider{ + + private final static Logger LOG = Logger.getLogger(CompletionProviderWithContext.class.getName()); + + private static final String DOT = "."; + private static final String POINTER = "->"; + private static final String STATIC = "::"; + private TLibrary sketchLibrary; // classes, variables, functions of sketch + + private List sketchCompletions = new ArrayList(); // variables and functions of sketch + + public CompletionProviderWithContext() { + super(); + } + + public void setSketchLibrary(TLibrary sketchLibrary) { + this.sketchLibrary = sketchLibrary; + } + + @Override + public List getCompletionsImpl(JTextComponent comp) { + + RSyntaxTextArea textarea = (RSyntaxTextArea) comp; + + String entredText = getAlreadyEnteredText(comp); + + List contextCompletions = null; + + LOG.finest("entredText = "+ entredText); + + // Functions/Attrs of Classes + if (entredText != null && entredText.length() > 0) { + + String separator = null; + + if (entredText.contains(DOT)) separator = DOT; + if (entredText.contains(POINTER))separator = POINTER; + if (entredText.contains(STATIC)) separator = STATIC; + + if (separator != null) { + String var = entredText.substring(0, entredText.lastIndexOf(separator)); + String startMethod = entredText.substring(entredText.lastIndexOf(separator) + separator.length()); + contextCompletions = getCompletionsForClass(var, separator, startMethod, textarea); + } + + } + + // Only show functions/attrs of class. + if (contextCompletions != null) return contextCompletions; + + List list = new LinkedList(); + + TFunction functionScope = getCurrentFunctionScope(textarea); + + if (functionScope != null && sketchCompletions != null && !sketchCompletions.isEmpty()) { + + // Variables and functions + list.addAll(sketchCompletions); + + // Local variables of functions. + list.addAll(getVariablesInCurrentScope(textarea)); + + // Need to order before searching + if(list.size() != sketchCompletions.size()){ + Collections.sort(list, comparator); + } + + List filterCompletions = filterCompletions(entredText, list); + + if (filterCompletions != null) list = filterCompletions; + + } + + List completions = super.getCompletionsImpl(comp); + + // Outside of function (only show classes) + if (functionScope == null) { + for (Completion completion : completions) { + if (!(completion instanceof FunctionCompletion)) { + list.add(completion); + } + } + } else { + list.addAll(completions); + } + + return list; + + } + + public List getVariablesInCurrentScope(RSyntaxTextArea textarea){ + + int caretPos = textarea.getCaretPosition(); + TFunction functionScope = getCurrentFunctionScope(textarea); + List completions = new ArrayList(); + + if(functionScope != null){ + + Set localVariables = functionScope.getLocalVariables(); + + if(localVariables != null){ + for (TAttribute var : localVariables) { + if(var.getLocation().getStartOffset() <= caretPos){ // try to filter variables not declared at cursor position + // TODO: this may not work if many rows were changed after the last parser + completions.add(new TElementCompletion(this, var)); + } + } + } + + } + + + return completions; + + } + + public List getCompletionsForClass(String context, String token, String startMethod, RSyntaxTextArea textarea){ + + List list = new LinkedList(); + + boolean isInstance = (token == POINTER || Character.isLowerCase(context.charAt(0))); + boolean isStatic = (token == STATIC && Character.isUpperCase(context.charAt(0))); + + TClass tClass = null; + + if(!isStatic){ + // Find the correct type based on global/local variables + Set variables = new HashSet(); + variables.addAll(sketchLibrary.getGlobalVariables()); + + TFunction functionScope = getCurrentFunctionScope(textarea); + + if(functionScope != null){ + variables.addAll(functionScope.getLocalVariables()); + } + + for (TAttribute attribute : variables) { + if(attribute.name().equals(context)){ + tClass = LibraryIndex.getClass(attribute.getType()); + isInstance = true; + break; + } + } + } + + if(tClass == null){ + tClass = LibraryIndex.getClass(context); // if isInstance, ignore case !! + } + + if(tClass == null){ + + TLibrary library = LibraryIndex.getLibrary(context); + if(library != null){ + TElement variable = library.findMember(context); + if(variable instanceof TAttribute){ + tClass = LibraryIndex.getClass(((TAttribute) variable).getType()); + if(tClass != null) isInstance = true; + } + + } + + } + + + if(tClass != null){ + + Collection functions = tClass.getFunctions(true); + Collection attributes = tClass.getAttributes(); + + // if the user had entered part of the function/attr name + if(startMethod != null && startMethod.length() > 0){ + int matchMode = (startMethod.length() > 2 ? TElementFilter.MATCH_CONTAINS : TElementFilter.MATCH_START); + functions = Predicate.filter(functions, new TFunctionFilter(startMethod, matchMode)); + attributes = Predicate.filter(attributes, new TAttributeFilter(startMethod, matchMode)); + } + + String startTemplate = context + token; + + for (TFunction tFunction : functions) { + + if(!tFunction.isPublic() || tFunction.isConstructor()) continue; + + boolean add = false; + + // Instance + if(isInstance && !tFunction.isStatic()){ + add = true; + } + + // Static + if(!isInstance && tFunction.isStatic()){ + add = true; + } + + // Extern (show static and instance) + if(tClass.getType() == TClassType.EXTERN){ + add = true; + } + + if(add){ + list.add(new TFunctionCompletion(this, tFunction, startTemplate)); + } + + } + + for (TAttribute attr : attributes) { + + // Instance + if(isInstance && !attr.isStatic()){ + list.add(new TElementCompletion(this, attr , startTemplate)); + } + + // Static + if(!isInstance && attr.isStatic() || tClass.getType() == TClassType.EXTERN){ + list.add(new TElementCompletion(this, attr , startTemplate)); + } + + } + + } + + return list; + } + + public void setSketchCompletions(List sketchCompletions) { + this.sketchCompletions = sketchCompletions; + Collections.sort(sketchCompletions, comparator); + } + + public List getSketchCompletions() { + return sketchCompletions; + } + + + /** + * Find function at the caret position + * @param textarea + * @return + */ + public TFunction getCurrentFunctionScope(RSyntaxTextArea textarea){ + + int caretPos = textarea.getCaretPosition(); + + Set globalFunctions = sketchLibrary.getGlobalFunctions(); + + for (TFunction tFunction : globalFunctions) { + TElementLocation location = tFunction.getLocation(); + if(location != null && location.containsOffset(caretPos)){ + + LOG.finest("function = " + tFunction + ", loc: " + location.toString()); + + return tFunction; + } + } + + return null; + } + + /** + * Filter through the options that can be applied to the text that the user entered + * @param alreadyEnteredText + * @param completions - Must be ordered before searching + * @return + */ + protected List filterCompletions(String alreadyEnteredText, List completions) { + + if(alreadyEnteredText == null || alreadyEnteredText.isEmpty()) return new ArrayList(completions); + List retVal = new ArrayList(); + + if (alreadyEnteredText!=null) { + + int index = Collections.binarySearch(completions, alreadyEnteredText, comparator); + if (index<0) { // No exact match + index = -index - 1; + } + else { + // If there are several overloads for the function being + // completed, Collections.binarySearch() will return the index + // of one of those overloads, but we must return all of them, + // so search backward until we find the first one. + int pos = index - 1; + while (pos>0 && + comparator.compare(completions.get(pos), alreadyEnteredText)==0) { + retVal.add(completions.get(pos)); + pos--; + } + } + + while (index' == ch || '-' == ch || '<' == ch || '#' == ch || ':' == ch /**|| getParameterListStart() == ch */; + } + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionType.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionType.java new file mode 100755 index 00000000000..58ee48653df --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionType.java @@ -0,0 +1,46 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +public enum CompletionType { + LIBRARY, + CLASS, + ENUM, + STRUCT, + LOCAL_VAR, + STATIC_VAR, + VARIABLE, + FUNCTION, + TEMPLATE, + ERROR + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionsRenderer.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionsRenderer.java new file mode 100755 index 00000000000..a6853ca02ec --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/CompletionsRenderer.java @@ -0,0 +1,166 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JList; + +import org.fife.ui.autocomplete.BasicCompletion; +import org.fife.ui.autocomplete.FunctionCompletion; +import org.fife.ui.autocomplete.ShorthandCompletion; +import org.fife.ui.autocomplete.TemplateCompletion; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; + +import br.com.criativasoft.cpluslibparser.metadata.TElement; +import br.com.criativasoft.cpluslibparser.metadata.TFunction; + +/** + * Class responsible for formatting the elements of the autocomplete list + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + * @date 11/12/2014 + */ +public class CompletionsRenderer extends DefaultListCellRenderer { + + private static final long serialVersionUID = 1L; + + private static final Color HIGHLIGHT_COLOR = new Color(74, 144, 217); + + private static final String GRAY = "#A0A0A0"; + private static final String LIGHT_BLUE = "#008080"; + + /** Keeps the HTML descriptions from "wrapping" in the list, which cuts off words. */ + private static final String PREFIX = ""; + + private static Map iconsTypes = new HashMap(); + + static{ + iconsTypes.put(CompletionType.CLASS, getIcon("class.gif")); + iconsTypes.put(CompletionType.ENUM, getIcon("enum.gif")); + iconsTypes.put(CompletionType.VARIABLE, getIcon("variable.gif")); + iconsTypes.put(CompletionType.LOCAL_VAR, getIcon("variable_local.gif")); + iconsTypes.put(CompletionType.STATIC_VAR, getIcon("variable_static.gif")); + iconsTypes.put(CompletionType.FUNCTION, getIcon("function.gif")); + iconsTypes.put(CompletionType.ERROR, getIcon("error.gif")); + iconsTypes.put(CompletionType.TEMPLATE, getIcon("template_obj.gif")); + } + + + private static Icon getIcon(String image){ + return new ImageIcon(CompletionsRenderer.class.getResource("icons/"+image)); + } + + public static Icon getIcon(CompletionType tokenType){ + return iconsTypes.get(tokenType); + } + + public CompletionsRenderer() { + setOpaque(true); + // Font f = Theme.getDefaultFont(); + Font f = RSyntaxTextArea.getDefaultFont(); + setFont(f.deriveFont(f.getStyle() & ~Font.BOLD)); // remove bold. + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, + boolean cellHasFocus) { + + String text = null; + CompletionType tokenType = null; + + if(value instanceof TElementCompletion){ + + TElementCompletion completion = (TElementCompletion) value; + TElement element = completion.getElement(); + tokenType = completion.getType(); + text = element.getHtmlRepresentation(); + + }else if(value instanceof TFunctionCompletion){ + + TFunctionCompletion completion = (TFunctionCompletion) value; + TFunction function = completion.getFunction(); + text = function.getHtmlRepresentation(); + tokenType = CompletionType.FUNCTION; + + }else if(value instanceof ShorthandCompletion){ + text = ((ShorthandCompletion) value).getShortDescription(); + tokenType = CompletionType.TEMPLATE; + }else if(value instanceof FunctionCompletion){ + text = ((FunctionCompletion) value).getShortDescription(); + tokenType = CompletionType.FUNCTION; + }else if(value instanceof BasicCompletion){ + text = ((BasicCompletion) value).getInputText(); + if( ((BasicCompletion) value).getShortDescription() != null){ + text = ((BasicCompletion) value).getShortDescription(); + } + }else if(value instanceof TemplateCompletion){ + TemplateCompletion template = (TemplateCompletion) value; + text = font(template.getInputText(), LIGHT_BLUE) + font(" - " + template.getDefinitionString(), GRAY) ; + } + + if(text == null){ + text = value.toString(); + } + + // Find Icon + if(tokenType != null){ + setIcon(iconsTypes.get(tokenType)); + }else{ + setIcon(iconsTypes.get(CompletionType.TEMPLATE)); + } + + if (isSelected) { + setText(text.replaceAll("\\<[^>]*>","")); + setBackground(HIGHLIGHT_COLOR); + setForeground(Color.white); + } else { + setText(PREFIX + text); + setBackground(Color.white); + setForeground(Color.black); + } + + return this; + } + + private String font(String text, String color){ + return ""+text+""; + } + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/ParameterChoicesProvider.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/ParameterChoicesProvider.java new file mode 100755 index 00000000000..b839286f6d2 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/ParameterChoicesProvider.java @@ -0,0 +1,163 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import java.util.LinkedList; +import java.util.List; + +import javax.swing.text.JTextComponent; + +import org.fife.ui.autocomplete.BasicCompletion; +import org.fife.ui.autocomplete.Completion; +import org.fife.ui.autocomplete.CompletionProvider; +import org.fife.ui.autocomplete.CompletionProviderBase; +import org.fife.ui.autocomplete.ParameterizedCompletion; +import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter; + +import cc.arduino.packages.autocomplete.TFunctionCompletion.TFunctionParam; +import br.com.criativasoft.cpluslibparser.metadata.TFunction; +import br.com.criativasoft.cpluslibparser.metadata.TParam; + +/** + * This is used when a user code-completes a parameterized completion, such as a function or method.
+ * 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 getParameterChoices(JTextComponent tc, ParameterizedCompletion pc, Parameter param) { + + if (param instanceof TFunctionParam) { + + TFunctionParam functionParam = (TFunctionParam) param; + TFunction function = functionParam.getFunction(); + TParam tParam = functionParam.getAttributeParam(); + + // FIXME: REMOVE AFTER IMPLEMENT PARSER FROM SOURCE + if (function.name().equals("begin") && tParam.name().equals("baud")) { + // @param baud (Values: 300, 600, 1200 ...) + tParam.setAllowedValues("300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200"); + } + + if (function.name().equals("pinMode") && tParam.name().equals("mode")) { + tParam.setAllowedValues("OUTPUT, INPUT, INPUT_PULLUP"); + } + + if (function.name().equals("digitalWrite") && tParam.name().equals("value")) { + tParam.setAllowedValues("HIGH, LOW"); + } + + // end: remove -------------- + + if (tParam.getAllowedValues() != null) { + return createFromAllowedValues(tParam); + } + + } + + if(pc instanceof TemplateChoicesCompletion){ + TemplateChoicesCompletion choicesCompletion = (TemplateChoicesCompletion) pc; + return choicesCompletion.getChoices(param); + } + + return null; + } + + private List createFromAllowedValues(TParam param) { + + List completions = new LinkedList(); + + String allowedValues = param.getAllowedValues(); + + String[] strings = allowedValues.split(","); + + for (String key : strings) { + completions.add(new ParamCompletion(provider, key.trim(), param.getType())); + } + + return completions; + } + + + // it is only necessary to properly sort integer values. + private static class ParamCompletion extends BasicCompletion { + + private Long value; + + public ParamCompletion(CompletionProvider provider, String replacementText, + String type) { + super(provider, replacementText); + + if (isNumber(type)) { + try { + value = Long.parseLong(replacementText); + } catch (Exception e) {} + } + + } + + private boolean isNumber(String type) { + if (type.contains("int") || type.contains("long")) { + return true; + } + + return false; + } + + public Long getValue() { + return value; + } + + @Override + public int compareTo(Completion c2) { + + if(value != null){ + return value.compareTo(((ParamCompletion)c2).getValue()); + }else{ + return super.compareTo(c2); + } + + } + + } + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/RealtimeCompletionsListener.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/RealtimeCompletionsListener.java new file mode 100755 index 00000000000..efe7f5344d1 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/RealtimeCompletionsListener.java @@ -0,0 +1,205 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.util.Set; +import java.util.logging.Logger; + +import javax.swing.Timer; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.Segment; + +import processing.app.SketchCode; +import processing.app.SketchData; +import br.com.criativasoft.cpluslibparser.LibraryIndex; +import br.com.criativasoft.cpluslibparser.metadata.TElement; +import br.com.criativasoft.cpluslibparser.metadata.TError; +import br.com.criativasoft.cpluslibparser.metadata.TFunction; +import br.com.criativasoft.cpluslibparser.metadata.TLibrary; + +/** + * This is the class responsible for monitoring the events and changes in the code and decide when it should + * be done a parser to extract the metadata to make the autocomplete
+ * 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 SketchData sketchData; + private Segment segment = new Segment(); + private Timer debounce; + private int startOffs; + private int endOffs; + private int startLine; + private int endLine; + + public RealtimeCompletionsListener(SketchData sketchData) { + this.sketchData = sketchData; + 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 = sketchData.getCurrentCode(); + TLibrary library = sketchData.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(sketchCode.getFile().getPath()); + } + + try { + Document document = SketchCompletionProvider.getDocument(sketchCode); + String code = document.getText(0, document.getLength()); + LibraryIndex.scanSource(code, new SketchCodeScanner(sketchData, sketchData.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(sketchData != null && sketchData.getSketchMetadata() != null){ + TLibrary metadata = sketchData.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 functions = metadata.getGlobalFunctions(); + + for (TFunction function : functions) { + if(!"setup".equals(function.name())){ + if(TElement.contains(startOffs, function.getLocalVariables())){ + LOG.fine("Changing a local variable, firing parser"); + fireParser(); + return; + } + } + } + + } + + } + + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/SketchCodeScanner.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/SketchCodeScanner.java new file mode 100755 index 00000000000..7064288c6f5 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/SketchCodeScanner.java @@ -0,0 +1,85 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import java.io.File; + +import processing.app.SketchCode; +import processing.app.SketchData; +import processing.app.helpers.filefilters.OnlyFilesWithExtension; +import br.com.criativasoft.cpluslibparser.LibraryScanner; +import br.com.criativasoft.cpluslibparser.SourceParser; + +public class SketchCodeScanner extends LibraryScanner { + + private SketchCode code; + private SketchData sketch; + + public SketchCodeScanner(SketchData sketchData, SketchCode code) { + this(sketchData); + this.code = code; + } + + public SketchCodeScanner(SketchData sketch) { + super(); + this.sketch = sketch; + setSerialize(false); // not cache + setDeserialize(false); // not cache + } + + @Override + protected File[] getFilesToParse(File folder) { + + if(code != null){ // single file{ + + return new File[]{code.getFile()}; + + }else{ + + return folder.listFiles(new OnlyFilesWithExtension("ino", "pde", "c", "cpp", "h")); + + } + + } + + @Override + protected void configParser(SourceParser parser, File currentFile) { + parser.setParseInternalAttrs(true); + if(currentFile == null) parser.setDefaultFileName(code.getFileName()); + } + + @Override + protected String getLibraryName() { + return SketchCompletionProvider.SKETCH_LIB_PREFIX + sketch.getName(); + } + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/SketchCompletionProvider.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/SketchCompletionProvider.java new file mode 100755 index 00000000000..9b922d0266a --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/SketchCompletionProvider.java @@ -0,0 +1,563 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.text.Document; + +import org.fife.ui.autocomplete.AutoCompletion; +import org.fife.ui.autocomplete.Completion; +import org.fife.ui.autocomplete.LanguageAwareCompletionProvider; +import org.fife.ui.autocomplete.TemplateCompletion; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; + +import processing.app.BaseNoGui; +import processing.app.PreferencesData; +import processing.app.SketchCode; +import processing.app.SketchData; +import processing.app.SketchDocumentProvider; +import processing.app.debug.TargetPlatform; +import processing.app.helpers.StringUtils; +import processing.app.packages.LibraryList; +import processing.app.packages.LibraryListener; +import processing.app.packages.SketchListener; +import processing.app.packages.UserLibrary; +import br.com.criativasoft.cpluslibparser.LibraryIndex; +import br.com.criativasoft.cpluslibparser.LibraryIndexListener; +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.TElementLocation; +import br.com.criativasoft.cpluslibparser.metadata.TFunction; +import br.com.criativasoft.cpluslibparser.metadata.TLibrary; +import cc.arduino.packages.autocomplete.template.GenerateVarTemplate; +import cc.arduino.packages.autocomplete.template.IncludeTemplate; + +/** + * CompletionProvider for Arduino/CPP Language.
+ * 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 = ArduinoLibraryScanner.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 SketchData sketchData; + private LibraryList importedLibraries; // same instance in Sketch + + private RealtimeCompletionsListener realtimeCompletionsListener; + + private CompletionProviderWithContext provider = new CompletionProviderWithContext(); // Loaded static auto-completes. + + private AutoCompletion autoCompletion; + + public SketchCompletionProvider(SketchData sketchData) { + super(); + this.sketchData = sketchData; + + provider.setParameterChoicesProvider(new ParameterChoicesProvider(this)); + setDefaultCompletionProvider(provider); + provider.setParameterizedCompletionParams('(', ", ", ')'); + + LibraryIndex.addListener(this); + sketchData.addListener(this); + realtimeCompletionsListener = new RealtimeCompletionsListener(sketchData); + + // Import existing... + + // Arduino Core + //======================= + TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform(); + File folder = targetPlatform.getFolder(); + File coreFolder = new File(folder,"cores"+File.separator+"arduino"); + if(coreFolder.exists()){ + UserLibrary coreLib; + try { + coreLib = UserLibrary.create(coreFolder); + LibraryIndex.scanFolder(coreFolder, new ArduinoLibraryScanner(coreLib)); // fire #onLoadLibrary on finish + } catch (IOException e) { + e.printStackTrace(); + } + } + + LibraryIndex.scanFolder(sketchData.getFolder(), new SketchCodeScanner(sketchData)); // fire #onLoadLibrary on finish + + + onSketchLoad(sketchData); + for (SketchCode sketchCode : sketchData.getCodes()) { + onSketchInserted(sketchData, sketchCode); + } + + loadDefaultAutocompletes(); + } + + + /** + * Remove all listeners + */ + public void uninstall() { + LibraryIndex.removeListener(this); + LibraryIndex.removeLibrary(sketchLibrary); + sketchData.removeListener(this); + importedLibraries.removeListener(this); + + autoCompletion.getTextComponent().removeKeyListener(realtimeCompletionsListener); + + for (SketchCode code : sketchData.getCodes()) { + Document document = getDocument(code); + if(document != null) + document.removeDocumentListener(realtimeCompletionsListener); + } + } + + + // ========================================== + // Sketch Library (importedLibraries) Listener + // ========================================== + + @Override + public void onInsertLibrary(UserLibrary library) { + + if(isExternalMode()) return; + + LOG.fine("Arduino Lib: " + library); + LibraryIndex.scanFolder(library.getSrcFolder(), new ArduinoLibraryScanner(library)); // scan lib and fire #onLoadLibrary + } + + @Override + public void onRemoveLibrary(UserLibrary library) { + + if(isExternalMode()) return; + + LOG.fine("Arduino Lib: " + library); + } + + @Override + public void onClearLibraryList() { + + if(isExternalMode()) return; + + } + + + // ========================================== + // SketchCode Listener + // ========================================== + + @Override + public void onSketchLoad(SketchData sketch) { + + if(isExternalMode()) return; + + LOG.fine(sketch.getName()); + + importedLibraries = sketch.getImportedLibraries(); + importedLibraries.addListener(this); + for (UserLibrary library : importedLibraries) { + onInsertLibrary(library); + } + } + + + @Override + public void onSketchInserted(SketchData sketch, SketchCode code) { + + if(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(SketchData sketch, SketchCode code) { + + if(isExternalMode()) return; + + LOG.fine(code.getFileName()); + + if(sketchLibrary != null){ + sketchLibrary.clear(code.getFile().getPath()); // Clear to get the new variables and remove those that no longer exist + } + + LibraryIndex.scanFolder(sketch.getFolder(), new SketchCodeScanner(sketch, code)); // fire #onLoadLibrary on finish + } + + + // ========================================== + // LibraryIndex Listener (Parser) + // ========================================== + + @Override + public void onLoadLibrary(TLibrary library) { + + if(isExternalMode()) return; + + if(library.name().equals(SKETCH_LIB_PREFIX+sketchData.getName())){ // Sketch indexing finish + sketchLibrary = library; + sketchLibrary.setReloadable(true); + provider.setSketchLibrary(sketchLibrary); + sketchData.setSketchMetadata(sketchLibrary); + } + + createCompletions(library); + } + + @Override + public void onUnloadLibrary(TLibrary library) { + LOG.fine(library.name()); + + } + + @Override + public void onReloadLibrary(TLibrary library) { + + if(isExternalMode()) return; + + createCompletions(library); + } + + private boolean isExternalMode(){ + return PreferencesData.getBoolean("editor.external"); + } + + protected void loadDefaultAutocompletes(){ + + List completions = new ArrayList(); + + completions.add(new IncludeTemplate(provider)); + completions.add(new TemplateCompletion(provider, "for", "interate over array", "for (int ${i} = 0; ${i} < ${array}.length; ${i}++) {\n\t${cursor}\n}")); + completions.add(new TemplateCompletion(provider, "while", "while block", "while (${condition}) {\n\t${cursor}\n}")); + completions.add(new TemplateCompletion(provider, "if", "if block", "if (${condition}) {\n\t${cursor}\n}")); + completions.add(new TemplateCompletion(provider, "elseif", "elseif block", "else if (${condition}) {\n\t${cursor}\n}")); + completions.add(new TemplateCompletion(provider, "else", "else block", "else{\n\t${cursor}\n}")); + + completions.add(new TemplateCompletion(provider, "println", "Serial.println()", "Serial.println(\"${cursor}\");")); + + completions.add(new TemplateCompletion(provider, "dw", "digitalWrite", "digitalWrite(${cursor});")); + completions.add(new TemplateCompletion(provider, "dr", "digitalRead", "digitalRead(${cursor});")); + completions.add(new TemplateCompletion(provider, "aw", "analogWrite", "analogWrite(${cursor});")); + completions.add(new TemplateCompletion(provider, "ar", "analogRead", "analogRead(${cursor});")); + + + //Add as ENUNM + // TODO: only show if in method params + String[] names = {"HIGH", "LOW", "OUTPUT", "INPUT", "INPUT_PULLUP", "CHANGE", "FALLING", "RISING", "RISING", "DEC", "HEX", "OCT", "BIN", "LED_BUILTIN"}; + for (String name : names) { + TAttribute attribute = new TAttribute("int", name); + attribute.setEnum(true); + completions.add(new TElementCompletion(provider, attribute)); + } + + provider.addCompletions(completions); + } + + + /** + * Add Completions from parsed lib + */ + protected void createCompletions( TLibrary library ) { + + LOG.fine("build auto-complete for: " + library.name()); + + Set allMembers = library.getAllMembers(); + + // Sketch indexing finish + // sketchCompletions are dynamic. + if (sketchLibrary != null && library.name().equals(sketchLibrary.name())) { + + List sketchCompletions = new ArrayList(); + + for (TElement element : allMembers) { + + // Set sketck attrs as not static + if (element instanceof TAttribute) { + ((TAttribute) element).setStatic(false); + } + + // track positions of methods and variables even after document changes + TElementLocation location = element.getLocation(); + if (location != null) { + Document document = findSketchDocument(element); + // If if document already loaded + if (document != null) { + TDynamicLocation dynamicLocation = new TDynamicLocation(document, location); + element.setLocation(dynamicLocation); + } + } + + if (element instanceof TFunction) { + if (element.name().equals("setup") || element.name().equals("loop")) continue; + TFunctionCompletion completion = new TFunctionCompletion(provider, (TFunction) element); + completion.setRelevance(3); + sketchCompletions.add(completion); + } else { + sketchCompletions.add(new TElementCompletion(provider, element)); + } + } + + provider.setSketchCompletions(sketchCompletions); + + } else { + + List staticCompletions = new ArrayList(); + + Set classes = library.getClasses(); + for (TClass tClass : classes) { + // XXX autocomplete: PdeTokenMaker.addKeyword(tClass.name(), Token.DATA_TYPE); + } + + for (TElement element : allMembers) { + if (element instanceof TFunction) { // global func. + if (element.name().equals("setup") || element.name().equals("loop")) continue; + TFunctionCompletion completion = new TFunctionCompletion(provider, (TFunction) element); + staticCompletions.add(completion); + } else { + staticCompletions.add(new TElementCompletion(provider, element)); + } + } + + provider.addCompletions(staticCompletions); + + } + + } + + protected Document findSketchDocument(TElement element){ + + TElementLocation location = element.getLocation(); + + String name = location.getFileName(); + + SketchCode[] codes = sketchData.getCodes(); + + if(codes.length == 1) return getDocument(codes[0]); + + for (SketchCode sketchCode : codes) { + if(sketchCode.getFileName().equals(name)){ + return getDocument(sketchCode); + } + } + + return null; + } + + static Document getDocument(SketchCode code){ + Object metadata = code.getMetadata(); + if(metadata instanceof SketchDocumentProvider){ + return ((SketchDocumentProvider) metadata).getDocument(); + } + return null; + } + + public SketchData getSketchData() { + return sketchData; + } + + public TFunction getCurrentFunctionScope(RSyntaxTextArea textarea){ + return provider.getCurrentFunctionScope(textarea); + } + + + public void generateNewVariableFor(String expression, int startOffSet) { + + Matcher instanceCall = INSTANCE_CALL_REGEX.matcher(expression); + + String returnType = null; + String function = null; + String varname = null; + + RSyntaxTextArea textArea = (RSyntaxTextArea) autoCompletion.getTextComponent(); + + // find retun type of function like (obj.myMethod(params)) + if (instanceCall.find()) { + String instance = instanceCall.group(1); + function = instanceCall.group(2); + + Set variables = new HashSet(); + + variables.addAll(sketchLibrary.getGlobalVariables()); + + TFunction functionScope = provider.getCurrentFunctionScope(textArea); + if(functionScope != null){ + variables.addAll(functionScope.getLocalVariables()); + } + + TClass varClass = null; + + for (TAttribute var : variables) { + + LOG.fine("generateVariableName , var : " + var); + + // find class of instance. + if(var.name().equals(instance)){ + LOG.fine("generateVariableName , found : " + var); + + String type = var.getType(); + varClass = LibraryIndex.getClass(type); + if(varClass != null) break; + } + + } + + // Find like: Serial / Ethernet. + if(varClass == null){ + varClass = LibraryIndex.getClass(instance); + } + + // Find like: EEPROM (static struct) + if(varClass == null){ + + TLibrary library = LibraryIndex.getLibrary(instance); + if(library != null){ + TElement variable = library.findMember(instance); + if(variable instanceof TAttribute){ + varClass = LibraryIndex.getClass(((TAttribute) variable).getType()); + } + + } + + } + + if(varClass != null){ + + LOG.fine("Class : " +varClass + ""); + TFunction tFunction = varClass.getFunction(function, true); + + LOG.fine("Function = " +tFunction + " (for:" + function + ")"); + + if(tFunction != null){ + returnType = tFunction.getReturnType(); + } + + } + + + }else{ + + Matcher functionCall = FUNCTION_CALL_REGEX.matcher(expression); + if (functionCall.find()) { + function = functionCall.group(1); + String param = functionCall.group(2); + + if(function.equals("digitalRead") || function.equals("analoadRead")){ + returnType = "int"; + varname = param +"Val"; + }else{ + Set functions = LibraryIndex.getGlobalFunctions(function); + + if(!functions.isEmpty()){ + returnType = functions.iterator().next().getReturnType(); + } + } + + } + + } + + + if(returnType != null){ + + if(varname == null){ + if(TElement.isPrimitive(returnType)){ + varname = function; + }else{ + String lastWord = StringUtils.findLastWord(returnType); + if(lastWord == null) lastWord = returnType; + varname = StringUtils.uncapitalize(lastWord); + } + } + + if(varname != null){ + + GenerateVarTemplate completion = new GenerateVarTemplate(provider, returnType, varname); + + textArea.setCaretPosition(startOffSet); + + AutoCompletion autoCompletion = getAutoCompletion(); + autoCompletion.startParameterizedCompletionAssistance(completion, false); + + } + } + + } + + + public void setAutoCompletion(AutoCompletion autoCompletion) { + this.autoCompletion = autoCompletion; + autoCompletion.getTextComponent().addKeyListener(realtimeCompletionsListener); + } + + public AutoCompletion getAutoCompletion() { + return autoCompletion; + } + + + + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TAttributeFilter.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TAttributeFilter.java new file mode 100755 index 00000000000..e0110b522e3 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TAttributeFilter.java @@ -0,0 +1,46 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import br.com.criativasoft.cpluslibparser.metadata.TAttribute; + +/** + * Simple collections filter + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + */ +public class TAttributeFilter extends TElementFilter { + + public TAttributeFilter(String text, int mathType) { + super(text, mathType); + } + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TDynamicLocation.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TDynamicLocation.java new file mode 100755 index 00000000000..732560779a9 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TDynamicLocation.java @@ -0,0 +1,151 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.Position; + +import br.com.criativasoft.cpluslibparser.metadata.TElement; +import br.com.criativasoft.cpluslibparser.metadata.TElementLocation; + +/** + * Element to track positions of methods and variables even after document changes.
+ * 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..90af82d77a2 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TElementCompletion.java @@ -0,0 +1,139 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import org.fife.ui.autocomplete.AbstractCompletion; +import org.fife.ui.autocomplete.CompletionProvider; + +import br.com.criativasoft.cpluslibparser.metadata.*; + +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..94737c71bbe --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TElementFilter.java @@ -0,0 +1,77 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +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 implements IPredicate { + + public static final int MATCH_START = 1; + public static final int MATCH_CONTAINS = 2; + public static final int MATCH_END = 3; + + private String text; + + private int mathType = MATCH_START; + + + public TElementFilter(String text, int mathType) { + super(); + this.text = text; + this.mathType = mathType; + } + + + @Override + public boolean apply(TElement node) { + String name = node.name().toLowerCase(); + + if(mathType == MATCH_START){ + return name.startsWith(text); + } + if(mathType == MATCH_CONTAINS){ + return name.contains(text); + } + if(mathType == MATCH_END){ + return name.endsWith(text); + } + + return false; + } + + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TFunctionCompletion.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TFunctionCompletion.java new file mode 100755 index 00000000000..c26727725ee --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TFunctionCompletion.java @@ -0,0 +1,122 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.fife.ui.autocomplete.CompletionProvider; +import org.fife.ui.autocomplete.FunctionCompletion; + +import br.com.criativasoft.cpluslibparser.metadata.TFunction; +import br.com.criativasoft.cpluslibparser.metadata.TParam; + +public class TFunctionCompletion extends FunctionCompletion { + + private TFunction function; + private String alreadyEntered; + + public TFunctionCompletion(CompletionProvider provider, TFunction function) { + this(provider, function, null); + } + + public TFunctionCompletion(CompletionProvider provider, TFunction function, String alreadyEntered) { + super(provider, function.name(), function.getReturnType()); + this.function = function; + this.alreadyEntered = alreadyEntered; + + Set params = function.getParams(); + List list = new LinkedList(); + + for (TParam param : params) { + list.add(new TFunctionParam(param, function)); + } + + setParams(list); + } + + public TFunction getFunction() { + return function; + } + + @Override + public String getShortDescription() { + return function.toDeclarationString(); + } + + @Override + public String getInputText() { + return function.name(); + } + + + @Override + public String getReplacementText() { + + if(alreadyEntered == null || alreadyEntered.length() == 0) return super.getReplacementText(); + + return alreadyEntered + super.getReplacementText(); + } + + @Override + public int getRelevance() { + return 3; + } + + @Override + public String toString() { + return function.name(); + } + + public static class TFunctionParam extends Parameter{ + + private TParam param; + private TFunction function; + + public TFunctionParam(TParam attribute, TFunction function) { + super(attribute.getType(), attribute.name()); + this.param = attribute; + this.function = function; + } + + public TFunction getFunction() { + return function; + } + + public TParam getAttributeParam() { + return param; + } + + } + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TFunctionFilter.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TFunctionFilter.java new file mode 100755 index 00000000000..c1a0a54167b --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TFunctionFilter.java @@ -0,0 +1,46 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import br.com.criativasoft.cpluslibparser.metadata.TFunction; + +/** + * Simple collections filter + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + */ +public class TFunctionFilter extends TElementFilter{ + + public TFunctionFilter(String text, int mathType) { + super(text, mathType); + } + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TemplateChoicesCompletion.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TemplateChoicesCompletion.java new file mode 100755 index 00000000000..f2b6eb7217a --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/TemplateChoicesCompletion.java @@ -0,0 +1,67 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete; + +import java.util.List; + +import org.fife.ui.autocomplete.Completion; +import org.fife.ui.autocomplete.CompletionProvider; +import org.fife.ui.autocomplete.ParameterizedCompletion; +import org.fife.ui.autocomplete.TemplateCompletion; + +/** + * Base class for templates that provide assistance to autocomplete parameters + * @see ParameterizedCompletion + * @see ParameterChoicesProvider + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + * @date 09/12/2014 + */ +public abstract class TemplateChoicesCompletion extends TemplateCompletion { + + public TemplateChoicesCompletion(CompletionProvider provider, + String inputText, String definitionString, + String template) { + super(provider, inputText, definitionString, template); + } + + public TemplateChoicesCompletion(CompletionProvider provider, + String inputText, String definitionString, + String template, String shortDescription, + String summary) { + super(provider, inputText, definitionString, template, shortDescription,summary); + } + + + public abstract List getChoices(Parameter param); + + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/class.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/class.gif new file mode 100755 index 00000000000..e4c2a836f83 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/class.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/enum.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/enum.gif new file mode 100755 index 00000000000..15535f52f52 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/enum.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/error.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/error.gif new file mode 100755 index 00000000000..0bc60689c6d Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/error.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/field_default_obj.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/field_default_obj.gif new file mode 100755 index 00000000000..6929d3d13f2 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/field_default_obj.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/field_public_obj.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/field_public_obj.gif new file mode 100755 index 00000000000..d4cb4254d92 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/field_public_obj.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/function.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/function.gif new file mode 100755 index 00000000000..7d24707ee82 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/function.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/function_static.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/function_static.gif new file mode 100755 index 00000000000..e02dc63568c Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/function_static.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/int_obj.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/int_obj.gif new file mode 100755 index 00000000000..2ebc46e1d3b Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/int_obj.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/jdoc_tag_obj.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/jdoc_tag_obj.gif new file mode 100755 index 00000000000..c43c5d51c51 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/jdoc_tag_obj.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/static_co.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/static_co.gif new file mode 100755 index 00000000000..6119fb446f4 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/static_co.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/template_obj.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/template_obj.gif new file mode 100755 index 00000000000..fdde5fbb95e Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/template_obj.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable.gif new file mode 100755 index 00000000000..f4a1ea15070 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable_local.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable_local.gif new file mode 100755 index 00000000000..8adce9541f1 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable_local.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable_static.gif b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable_static.gif new file mode 100755 index 00000000000..c63eb8506b0 Binary files /dev/null and b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/icons/variable_static.gif differ diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/template/GenerateVarTemplate.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/template/GenerateVarTemplate.java new file mode 100755 index 00000000000..5462bf29349 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/template/GenerateVarTemplate.java @@ -0,0 +1,63 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete.template; + +import org.fife.ui.autocomplete.CompletionProvider; +import org.fife.ui.autocomplete.TemplateCompletion; + +import cc.arduino.packages.autocomplete.SketchCompletionProvider; + +/** + * Used in {@link SketchCompletionProvider#generateNewVariableFor(String, int)} + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + * @date 11/12/2014 + */ +public class GenerateVarTemplate extends TemplateCompletion { + + private String type, name; + + public GenerateVarTemplate(CompletionProvider provider,String type, String name) { + super(provider, name, name, type + " ${" + name + "} = "); + this.type = type; + this.name = name; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + +} diff --git a/arduino-autocomplete/src/cc/arduino/packages/autocomplete/template/IncludeTemplate.java b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/template/IncludeTemplate.java new file mode 100755 index 00000000000..cfaf9dc4529 --- /dev/null +++ b/arduino-autocomplete/src/cc/arduino/packages/autocomplete/template/IncludeTemplate.java @@ -0,0 +1,110 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.packages.autocomplete.template; + +import java.io.File; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import org.fife.ui.autocomplete.BasicCompletion; +import org.fife.ui.autocomplete.Completion; +import org.fife.ui.autocomplete.CompletionProvider; + +import br.com.criativasoft.cpluslibparser.LibraryIndex; +import br.com.criativasoft.cpluslibparser.metadata.TLibrary; +import processing.app.BaseNoGui; +import processing.app.helpers.filefilters.OnlyFilesWithExtension; +import processing.app.packages.LibraryList; +import processing.app.packages.UserLibrary; +import cc.arduino.packages.autocomplete.SketchCompletionProvider; +import cc.arduino.packages.autocomplete.TemplateChoicesCompletion; + +public class IncludeTemplate extends TemplateChoicesCompletion { + + public IncludeTemplate(CompletionProvider provider) { + super(provider, "#include", "#include <>", "#include ${<}"); + } + + @Override + public List getChoices(Parameter param) { + List completions = new LinkedList(); + + LibraryList libraries = BaseNoGui.getLibraries(); + for (UserLibrary library : libraries) { + completions.add(new IncludeCompletion(getProvider(), library)); + } + + // Get files from Sketch folder. + Collection libs = LibraryIndex.getLibraries().values(); + for (TLibrary tLibrary : libs) { + if(tLibrary.getName().startsWith(SketchCompletionProvider.SKETCH_LIB_PREFIX)){ + File folder = new File(tLibrary.getLocation().getPath()); + File[] listOfFiles = folder.listFiles(new OnlyFilesWithExtension(".h")); + if (listOfFiles != null) { + for (int i = 0; i < listOfFiles.length; i++) { + completions.add(new BasicCompletion(getProvider(), "\""+listOfFiles[i].getName()+"\"")); + } + } + } + } + + return completions; + } + + private static class IncludeCompletion extends BasicCompletion{ + + private UserLibrary library; + + public IncludeCompletion(CompletionProvider provider, UserLibrary library) { + super(provider, library.getInstalledFolder().getName()); + this.library = library; + } + + @Override + public String getSummary() { + return library.getSentence(); + } + + @Override + public String getShortDescription() { + return library.getName(); + } + + @Override + public String getReplacementText() { + return "<"+library.getInstalledFolder().getName()+".h>"; + } + + } + +} diff --git a/arduino-core/.classpath b/arduino-core/.classpath index b0e162044ae..e0cb4e783bc 100644 --- a/arduino-core/.classpath +++ b/arduino-core/.classpath @@ -18,6 +18,8 @@ + + @@ -29,5 +31,6 @@ + diff --git a/arduino-core/build.xml b/arduino-core/build.xml index 6245ed6b5c0..baf01440442 100644 --- a/arduino-core/build.xml +++ b/arduino-core/build.xml @@ -5,6 +5,9 @@ + + +
diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index 640f2d757c6..0a88692dea2 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -7,10 +7,13 @@ import cc.arduino.files.DeleteFilesOnShutdown; import cc.arduino.packages.DiscoveryManager; import cc.arduino.packages.Uploader; + import com.fasterxml.jackson.core.JsonProcessingException; + import org.apache.commons.compress.utils.IOUtils; import org.apache.commons.logging.impl.LogFactoryImpl; import org.apache.commons.logging.impl.NoOpLog; + import processing.app.debug.Compiler; import processing.app.debug.*; import processing.app.helpers.*; @@ -23,6 +26,7 @@ import java.io.*; import java.net.URISyntaxException; import java.util.*; +import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; @@ -65,15 +69,14 @@ public class BaseNoGui { // maps #included files to their library folder public static Map importToLibraryTable; - // maps library name to their library folder - static private LibraryList libraries; - // XXX: Remove this field static private List librariesFolders; static UserNotifier notifier = new BasicUserNotifier(); static public Map packages; + + static List enabledLoggers = new ArrayList(); static Platform platform; @@ -243,7 +246,7 @@ static public String getHardwarePath() { } static public LibraryList getLibraries() { - return libraries; + return librariesIndexer.getInstalledLibraries(); } static public List getLibrariesPath() { @@ -599,6 +602,43 @@ protected static void dumpPrefs(CommandlineParser parser) { static public void initLogger() { System.setProperty(LogFactoryImpl.LOG_PROPERTY, NoOpLog.class.getCanonicalName()); Logger.getLogger("javax.jmdns").setLevel(Level.OFF); + + Handler consoleHandler = new ConsoleLogger(); + consoleHandler.setLevel(Level.ALL); + consoleHandler.setFormatter(new LogFormatter("%1$tl:%1$tM:%1$tS [%4$7s] %2$s: %5$s%n")); + + Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + globalLogger.setLevel(consoleHandler.getLevel()); + + // Remove default + Handler[] handlers = globalLogger.getHandlers(); + for(Handler handler : handlers) { + globalLogger.removeHandler(handler); + } + Logger root = Logger.getLogger(""); + handlers = root.getHandlers(); + for(Handler handler : handlers) { + root.removeHandler(handler); + } + + globalLogger.addHandler(consoleHandler); + //root.addHandler(consoleHandler); + + enableLogger("cc.arduino.packages.autocomplete"); + enableLogger("br.com.criativasoft.cpluslibparser"); + enableLogger(BaseNoGui.class.getPackage().getName()); + + } + + static public void enableLogger(String name){ + + Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + + Logger logger = Logger.getLogger(name); + + enabledLoggers.add(logger); + + logger.setParent(globalLogger); } static public void initPackages() throws Exception { diff --git a/arduino-core/src/processing/app/SketchData.java b/arduino-core/src/processing/app/SketchData.java index cef17433e57..671bfad7eeb 100644 --- a/arduino-core/src/processing/app/SketchData.java +++ b/arduino-core/src/processing/app/SketchData.java @@ -1,5 +1,8 @@ package processing.app; +import br.com.criativasoft.cpluslibparser.LibraryCache; +import br.com.criativasoft.cpluslibparser.metadata.TLibrary; + import com.google.common.collect.FluentIterable; import static processing.app.I18n._; @@ -8,6 +11,11 @@ import java.io.IOException; import java.util.*; +import processing.app.packages.LibraryList; +import processing.app.packages.SketchListener; +import processing.app.packages.UserLibrary; +import processing.app.preproc.PdePreprocessor; + public class SketchData { public static final List SKETCH_EXTENSIONS = Arrays.asList("ino", "pde"); @@ -33,6 +41,21 @@ public class SketchData { private String name; private List codes = new ArrayList(); + + private Set listeners = new LinkedHashSet(); + + /** + * List of library folders. + */ + private LibraryList importedLibraries = new LibraryList(); + + /** Sketch source metadata(classes, variables, functions), this is set in {@link SketchCompletionProvider#onLoadLibrary(TLibrary)} */ + private transient TLibrary sketchMetadata; + + /** Sketch and 'Libraries currently used' Metadata Cache - This is used by autocomplete */ + private transient LibraryCache libraryCacheContext; + + private transient SketchCode currentCode; private static final Comparator CODE_DOCS_COMPARATOR = new Comparator() { @Override @@ -49,6 +72,9 @@ public int compare(SketchCode x, SketchCode y) { String mainFilename = primaryFile.getName(); int suffixLength = getDefaultExtension().length() + 1; name = mainFilename.substring(0, mainFilename.length() - suffixLength); + + libraryCacheContext = new LibraryCache(); + libraryCacheContext.setName(name); folder = new File(file.getParent()); //System.out.println("sketch dir is " + folder); @@ -146,6 +172,21 @@ protected void load() throws IOException { break; } } + + // Find used libraries + for (SketchCode code : getCodes()) { + List includes = PdePreprocessor.findIncludes(code.getProgram()); + if(includes != null){ + for (String include : includes) { + LibraryList libs = BaseNoGui.importToLibraryTable.get(include); + if(libs == null) continue; + UserLibrary lib = libs.get(0); + if (lib != null && !importedLibraries.contains(lib)) { + importedLibraries.add(lib); + } + } + } + } // sort the entries at the top sortCode(); @@ -153,8 +194,10 @@ protected void load() throws IOException { public void save() throws IOException { for (SketchCode code : getCodes()) { - if (code.isModified()) + if (code.isModified()){ code.save(); + notifyListeners(SketchListener.Event.SAVED, code); + } } } @@ -190,6 +233,7 @@ public String getMainFilePath() { public void addCode(SketchCode sketchCode) { codes.add(sketchCode); + notifyListeners(SketchListener.Event.INSERTED, sketchCode); } public void moveCodeToFront(SketchCode codeDoc) { @@ -201,6 +245,7 @@ protected void replaceCode(SketchCode newCode) { for (SketchCode code : codes) { if (code.getFileName().equals(newCode.getFileName())) { codes.set(codes.indexOf(code), newCode); + notifyListeners(SketchListener.Event.SAVED, newCode); return; } } @@ -235,6 +280,32 @@ public int indexOfCode(SketchCode who) { } return -1; } + + public boolean addListener(SketchListener listener){ + return listeners.add(listener); + } + + public boolean removeListener(SketchListener listener){ + return listeners.add(listener); + } + + public void notifyListeners(SketchListener.Event event, SketchCode code){ + + for (SketchListener listener : listeners) { + + if(event == SketchListener.Event.LOAD){ + listener.onSketchLoad(this); + } + if(event == SketchListener.Event.INSERTED){ + listener.onSketchInserted(this, code); + } + if(event == SketchListener.Event.SAVED){ + listener.onSketchSaved(this, code); + } + + } + + } public String getName() { return name; @@ -259,4 +330,33 @@ public File getDataFolder() { public File getCodeFolder() { return codeFolder; } + + public void setSketchMetadata(TLibrary sketchMetadata) { + this.sketchMetadata = sketchMetadata; + } + + public TLibrary getSketchMetadata() { + return sketchMetadata; + } + + public LibraryCache getLibraryCacheContext() { + return libraryCacheContext; + } + + public LibraryList getImportedLibraries() { + return importedLibraries; + } + + public void addLibrary(UserLibrary lib) { + if(lib != null){ + importedLibraries.add(lib); + } + } + public void setCurrentCode(SketchCode currentCode) { + this.currentCode = currentCode; + } + + public SketchCode getCurrentCode() { + return currentCode; + } } diff --git a/arduino-core/src/processing/app/SketchDocumentProvider.java b/arduino-core/src/processing/app/SketchDocumentProvider.java new file mode 100755 index 00000000000..b5eecf4a22a --- /dev/null +++ b/arduino-core/src/processing/app/SketchDocumentProvider.java @@ -0,0 +1,9 @@ +package processing.app; + +import javax.swing.text.Document; + +public interface SketchDocumentProvider { + + Document getDocument(); + +} diff --git a/arduino-core/src/processing/app/debug/Compiler.java b/arduino-core/src/processing/app/debug/Compiler.java index 3de715384c1..398e80f422c 100644 --- a/arduino-core/src/processing/app/debug/Compiler.java +++ b/arduino-core/src/processing/app/debug/Compiler.java @@ -72,6 +72,7 @@ public class Compiler implements MessageConsumer { private boolean saveHex; private List objectFiles; + private List errors = new LinkedList(); private boolean sketchIsCompiled; @@ -125,6 +126,7 @@ static public String build(SketchData data, String buildPath, File tempBuildFold } catch (RunnerException e) { // when the compile fails, take this opportunity to show // any helpful info possible before throwing the exception + e.setErrors(compiler.getErrors()); compiler.adviseDuplicateLibraries(); throw e; } @@ -259,6 +261,8 @@ protected void cleanup(boolean force, File tempBuildFolder) { // if the java runtime is holding onto any files in the build dir, we // won't be able to delete them, so we need to force a gc here System.gc(); + + errors.clear(); if (force) { // delete the entire directory and all contents @@ -869,28 +873,33 @@ public void message(String s) { //msg = _("\nThe 'Keyboard' class is only supported on the Arduino Leonardo.\n\n"); } - RunnerException e = null; + CompilerError e = null; if (!sketchIsCompiled) { // Place errors when compiling the sketch, but never while compiling libraries // or the core. The user's sketch might contain the same filename! - e = placeException(error, pieces[1], PApplet.parseInt(pieces[2]) - 1); + //e = placeException(error, pieces[1], PApplet.parseInt(pieces[2]) - 1); + + e = new CompilerError(error, PApplet.parseInt(pieces[2]) - 1, pieces[1]); + errors.add(e); + } // replace full file path with the name of the sketch tab (unless we're // in verbose mode, in which case don't modify the compiler output) if (e != null && !verbose) { - SketchCode code = sketch.getCode(e.getCodeIndex()); + + SketchCode code = null; + for (SketchCode curr : sketch.getCodes()) { + if (e.getFileName().equals(curr.getFileName())) { + code = curr; + } + } + String fileName = (code.isExtension("ino") || code.isExtension("pde")) ? code.getPrettyName() : code.getFileName(); - int lineNum = e.getCodeLine() + 1; + int lineNum = e.getLine() + 1; s = fileName + ":" + lineNum + ": error: " + error + msg; } - if (e != null) { - if (exception == null || exception.getMessage().equals(e.getMessage())) { - exception = e; - exception.hideStackTrace(); - } - } } if (s.contains("undefined reference to `SPIClass::begin()'") && @@ -1209,6 +1218,10 @@ public PreferencesMap getBuildPreferences() { return prefs; } + public List getErrors() { + return errors; + } + /** * Build all the code for this sketch. * @@ -1335,27 +1348,6 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru private List importedDuplicateHeaders; private List importedDuplicateLibraries; - /** - * Map an error from a set of processed .java files back to its location - * in the actual sketch. - * @param message The error message. - * @param dotJavaFilename The .java file where the exception was found. - * @param dotJavaLine Line number of the .java file for the exception (0-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 placeException(String message, - String dotJavaFilename, - int dotJavaLine) { - // Placing errors is simple, because we inserted #line directives - // into the preprocessed source. The compiler gives us correct - // the file name and line number. :-) - for (SketchCode code : sketch.getCodes()) { - if (dotJavaFilename.equals(code.getFileName())) { - return new RunnerException(message, sketch.indexOfCode(code), dotJavaLine); - } - } - return null; - } + } diff --git a/arduino-core/src/processing/app/debug/CompilerError.java b/arduino-core/src/processing/app/debug/CompilerError.java new file mode 100755 index 00000000000..455f2c77e11 --- /dev/null +++ b/arduino-core/src/processing/app/debug/CompilerError.java @@ -0,0 +1,54 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2004-08 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package processing.app.debug; + +/** + * An error with a line number attached that occurs during either compile time. + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + */ +public class CompilerError { + + public CompilerError(String message, int line, String fileName) { + super(); + this.message = message; + this.line = line; + this.fileName = fileName; + } + + private int line; + private String message; + private String fileName; + + public int getLine() { + return line; + } + + public String getMessage() { + return message; + } + + public String getFileName() { + return fileName; + } + +} \ No newline at end of file diff --git a/arduino-core/src/processing/app/debug/RunnerException.java b/arduino-core/src/processing/app/debug/RunnerException.java index 0a67d1e80ef..dce2a32ac6c 100644 --- a/arduino-core/src/processing/app/debug/RunnerException.java +++ b/arduino-core/src/processing/app/debug/RunnerException.java @@ -23,6 +23,8 @@ package processing.app.debug; +import java.util.List; + /** * An exception with a line number attached that occurs @@ -31,9 +33,9 @@ @SuppressWarnings("serial") public class RunnerException extends Exception { protected String message; - protected int codeIndex; - protected int codeLine; - protected int codeColumn; + + protected List errors; + protected boolean showStackTrace; @@ -42,27 +44,10 @@ public RunnerException(String message) { } public RunnerException(String message, boolean showStackTrace) { - this(message, -1, -1, -1, showStackTrace); - } - - public RunnerException(String message, int file, int line) { - this(message, file, line, -1, true); - } - - - public RunnerException(String message, int file, int line, int column) { - this(message, file, line, column, true); - } - - - public RunnerException(String message, int file, int line, int column, - boolean showStackTrace) { this.message = message; - this.codeIndex = file; - this.codeLine = line; - this.codeColumn = column; this.showStackTrace = showStackTrace; } + public RunnerException(Exception e) { @@ -83,47 +68,6 @@ public void setMessage(String message) { this.message = message; } - - public int getCodeIndex() { - return codeIndex; - } - - - public void setCodeIndex(int index) { - codeIndex = index; - } - - - public boolean hasCodeIndex() { - return codeIndex != -1; - } - - - public int getCodeLine() { - return codeLine; - } - - - public void setCodeLine(int line) { - this.codeLine = line; - } - - - public boolean hasCodeLine() { - return codeLine != -1; - } - - - public void setCodeColumn(int column) { - this.codeColumn = column; - } - - - public int getCodeColumn() { - return codeColumn; - } - - public void showStackTrace() { showStackTrace = true; } @@ -152,6 +96,13 @@ static public final String massage(String msg) { } */ + public void setErrors( List errors ) { + this.errors = errors; + } + + public List getErrors() { + return errors; + } public void printStackTrace() { if (showStackTrace) { diff --git a/app/src/processing/app/helpers/ConsoleLogger.java b/arduino-core/src/processing/app/helpers/ConsoleLogger.java old mode 100644 new mode 100755 similarity index 100% rename from app/src/processing/app/helpers/ConsoleLogger.java rename to arduino-core/src/processing/app/helpers/ConsoleLogger.java diff --git a/arduino-core/src/processing/app/helpers/IPredicate.java b/arduino-core/src/processing/app/helpers/IPredicate.java new file mode 100755 index 00000000000..3af53471d6e --- /dev/null +++ b/arduino-core/src/processing/app/helpers/IPredicate.java @@ -0,0 +1,7 @@ +package processing.app.helpers; + +/** + * Interface to perform the filtering elements + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + */ +public interface IPredicate { boolean apply(T element); } \ No newline at end of file diff --git a/app/src/processing/app/helpers/LogFormatter.java b/arduino-core/src/processing/app/helpers/LogFormatter.java old mode 100644 new mode 100755 similarity index 100% rename from app/src/processing/app/helpers/LogFormatter.java rename to arduino-core/src/processing/app/helpers/LogFormatter.java diff --git a/arduino-core/src/processing/app/helpers/Predicate.java b/arduino-core/src/processing/app/helpers/Predicate.java new file mode 100755 index 00000000000..b12c58d9ad8 --- /dev/null +++ b/arduino-core/src/processing/app/helpers/Predicate.java @@ -0,0 +1,47 @@ +package processing.app.helpers; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Utility to filter elements based on predicates + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + */ +public class Predicate { + + public static Collection filter(Collection list, IPredicate predicate) { + Collection result = new ArrayList(); + return filter(list, predicate, result); + } + + public static Collection filter(Collection list, IPredicate predicate, Collection target) { + for (T element : list) { + if (predicate.apply(element)) { + target.add(element); + } + } + return target; +} + + public static T select(Collection target, IPredicate predicate) { + T result = null; + for (T element : target) { + if (!predicate.apply(element)) + continue; + result = element; + break; + } + return result; + } + + public static T select(Collection target, IPredicate predicate, T defaultValue) { + T result = defaultValue; + for (T element : target) { + if (!predicate.apply(element)) + continue; + result = element; + break; + } + return result; + } +} diff --git a/arduino-core/src/processing/app/helpers/StringUtils.java b/arduino-core/src/processing/app/helpers/StringUtils.java index fb60df33020..a14f46f8804 100644 --- a/arduino-core/src/processing/app/helpers/StringUtils.java +++ b/arduino-core/src/processing/app/helpers/StringUtils.java @@ -40,4 +40,30 @@ public static String rtrim(String s) { } return s.substring(0, i + 1); } + + public static String findLastWord(String input){ + + int pos = -1; + for (int i = 0; i < input.length(); i++) { + if(Character.isUpperCase(input.charAt(i))){ + pos = i; + } + } + + if(pos > -1){ + return input.substring(pos); + }else{ + return null; + } + + } + + /** + * Make the first character of a String lower case + */ + public static String uncapitalize(String input){ + String firstLetter = input.substring(0,1).toLowerCase(); + String restLetters = input.substring(1); + return firstLetter + restLetters; + } } diff --git a/arduino-core/src/processing/app/helpers/filefilters/OnlyFilesWithExtension.java b/arduino-core/src/processing/app/helpers/filefilters/OnlyFilesWithExtension.java index c13adcbcfe8..eca40171306 100644 --- a/arduino-core/src/processing/app/helpers/filefilters/OnlyFilesWithExtension.java +++ b/arduino-core/src/processing/app/helpers/filefilters/OnlyFilesWithExtension.java @@ -23,16 +23,33 @@ import java.io.File; import java.io.FilenameFilter; +import java.util.Collection; public class OnlyFilesWithExtension implements FilenameFilter { String extensions[]; + Collection ignoredFiles; public OnlyFilesWithExtension(String... ext) { this.extensions = ext; } + + + public OnlyFilesWithExtension(Collection ignoredFiles, String... ext) { + super(); + this.extensions = ext; + this.ignoredFiles = ignoredFiles; + } + public boolean accept(File dir, String name) { + + if(ignoredFiles != null){ + if(ignoredFiles.contains(name)){ + return false; + } + } + for (String ext : extensions) { if (name.endsWith(ext)) { return true; diff --git a/arduino-core/src/processing/app/packages/LibraryList.java b/arduino-core/src/processing/app/packages/LibraryList.java index d4d504cea79..b9414dda3a1 100644 --- a/arduino-core/src/processing/app/packages/LibraryList.java +++ b/arduino-core/src/processing/app/packages/LibraryList.java @@ -30,13 +30,17 @@ import java.io.File; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; import processing.app.helpers.FileUtils; @SuppressWarnings("serial") public class LibraryList extends LinkedList { + + private Set listeners = new LinkedHashSet(); public LibraryList(LibraryList libs) { super(libs); @@ -87,5 +91,41 @@ public boolean hasLibrary(UserLibrary lib) { if (l == lib) return true; return false; } -} + + @Override + public boolean add(UserLibrary l) { + + if(l == null || l.getName() == null || l.getName().length() == 0) return false; + + boolean add = super.add(l); + if(add){ // notify.. + if(listeners != null) for (LibraryListener listener : listeners) { listener.onInsertLibrary(l);} + } + + return add; + } + + @Override + public boolean remove(Object l) { + boolean remove = super.remove(l); + if(remove){ // notify.. + if(listeners != null) for (LibraryListener listener : listeners) { listener.onRemoveLibrary((UserLibrary)l);} + } + return remove; + } + + @Override + public void clear() { + if(listeners != null) for (LibraryListener listener : listeners) { listener.onClearLibraryList();} + super.clear(); + } + public boolean addListener(LibraryListener e) { + return listeners.add(e); + } + + public boolean removeListener(LibraryListener e) { + return listeners.remove(e); + } + +} diff --git a/arduino-core/src/processing/app/packages/LibraryListener.java b/arduino-core/src/processing/app/packages/LibraryListener.java new file mode 100755 index 00000000000..9ec6df526cf --- /dev/null +++ b/arduino-core/src/processing/app/packages/LibraryListener.java @@ -0,0 +1,15 @@ +package processing.app.packages; + +/** + * Interface to monitor sketck library changes + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + */ +public interface LibraryListener { + + void onInsertLibrary(UserLibrary library); + + void onRemoveLibrary(UserLibrary library); + + void onClearLibraryList(); + +} diff --git a/arduino-core/src/processing/app/packages/SketchListener.java b/arduino-core/src/processing/app/packages/SketchListener.java new file mode 100755 index 00000000000..5520167a722 --- /dev/null +++ b/arduino-core/src/processing/app/packages/SketchListener.java @@ -0,0 +1,18 @@ +package processing.app.packages; + +import processing.app.SketchCode; +import processing.app.SketchData; + +public interface SketchListener { + + public enum Event{ + LOAD, INSERTED, SAVED + } + + void onSketchLoad(SketchData sketch); + + void onSketchInserted(SketchData sketch, SketchCode code); + + void onSketchSaved(SketchData sketch, SketchCode code); + +} diff --git a/build/build.xml b/build/build.xml index f94e7975ca0..bcc97b601fd 100644 --- a/build/build.xml +++ b/build/build.xml @@ -74,6 +74,7 @@ + @@ -112,11 +113,13 @@ + + diff --git a/build/linux/dist/arduino b/build/linux/dist/arduino index 4e58bce3af1..04a7351beb2 100755 --- a/build/linux/dist/arduino +++ b/build/linux/dist/arduino @@ -33,4 +33,4 @@ if [ -x ./java/bin/java ]; then JAVA=./java/bin/java fi -$JAVA -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel $SPLASH processing.app.Base --curdir "$CURDIR" "$@" +$JAVA -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel $SPLASH ArduinoIDE --curdir "$CURDIR" "$@" diff --git a/build/macosx/template.app/Contents/Info.plist b/build/macosx/template.app/Contents/Info.plist index 5fa1337eb7a..a6d338d6009 100755 --- a/build/macosx/template.app/Contents/Info.plist +++ b/build/macosx/template.app/Contents/Info.plist @@ -97,7 +97,7 @@ - $JAVAROOT/antlr.jar:$JAVAROOT/apple.jar:$JAVAROOT/arduino-core.jar:$JAVAROOT/bcpg-jdk15on-152.jar:$JAVAROOT/bcprov-jdk15on-152.jar:$JAVAROOT/commons-codec-1.7.jar:$JAVAROOT/commons-compress-1.8.jar:$JAVAROOT/commons-exec-1.1.jar:$JAVAROOT/commons-httpclient-3.1.jar:$JAVAROOT/commons-lang3-3.3.2.jar:$JAVAROOT/commons-logging-1.0.4.jar:$JAVAROOT/ecj.jar:$JAVAROOT/guava-18.0.jar:$JAVAROOT/jackson-annotations-2.2.3.jar:$JAVAROOT/jackson-core-2.2.3.jar:$JAVAROOT/jackson-databind-2.2.3.jar:$JAVAROOT/jackson-module-mrbean-2.2.3.jar:$JAVAROOT/java-semver-0.8.0.jar:$JAVAROOT/jmdns-3.4.1.jar:$JAVAROOT/jsch-0.1.50.jar:$JAVAROOT/jssc-2.8.0.jar:$JAVAROOT/pde.jar:$JAVAROOT/quaqua.jar:$JAVAROOT/rsyntaxtextarea-2.5.6.1+arduino.jar + $JAVAROOT/antlr.jar:$JAVAROOT/apple.jar:$JAVAROOT/arduino-core.jar:$JAVAROOT/bcpg-jdk15on-152.jar:$JAVAROOT/bcprov-jdk15on-152.jar:$JAVAROOT/commons-codec-1.7.jar:$JAVAROOT/commons-compress-1.8.jar:$JAVAROOT/commons-exec-1.1.jar:$JAVAROOT/commons-httpclient-3.1.jar:$JAVAROOT/commons-lang3-3.3.2.jar:$JAVAROOT/commons-logging-1.0.4.jar:$JAVAROOT/ecj.jar:$JAVAROOT/guava-18.0.jar:$JAVAROOT/jackson-annotations-2.2.3.jar:$JAVAROOT/jackson-core-2.2.3.jar:$JAVAROOT/jackson-databind-2.2.3.jar:$JAVAROOT/jackson-module-mrbean-2.2.3.jar:$JAVAROOT/java-semver-0.8.0.jar:$JAVAROOT/jmdns-3.4.1.jar:$JAVAROOT/jsch-0.1.50.jar:$JAVAROOT/jssc-2.8.0.jar:$JAVAROOT/pde.jar:$JAVAROOT/quaqua.jar:$JAVAROOT/rsyntaxtextarea-2.5.6.1+arduino.jar:$JAVAROOT/rsyntax-autocomplete-2.6.0-SNAPSHOT.jar:$JAVAROOT/cplus-libparser-0.0.1.jar:$JAVAROOT/arduino-autocomplete.jar JVMArchs diff --git a/build/shared/lib/theme/syntax/eclipse.xml b/build/shared/lib/theme/syntax/eclipse.xml new file mode 100644 index 00000000000..1196f801356 --- /dev/null +++ b/build/shared/lib/theme/syntax/eclipse.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +