diff --git a/.gitignore b/.gitignore
index 1ff22582a..c3aae4577 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,13 +14,17 @@ hardware/arduino/bootloaders/caterina_LUFA/Caterina.elf
hardware/arduino/bootloaders/caterina_LUFA/Caterina.eep
hardware/arduino/bootloaders/caterina_LUFA/.dep/
build/windows/work/
+build/windows/jre.zip
+build/windows/libastylej*
build/windows/arduino-*.zip
build/windows/dist/gcc-*.tar.gz
build/macosx/arduino-*.zip
build/macosx/dist/gcc-*.tar.gz
+build/macosx/libastylej*
build/linux/work/
build/linux/dist/*.tar.gz
build/linux/*.tgz
+build/linux/libastylej*
test-bin
*.iml
.idea
diff --git a/app/src/cc/arduino/packages/formatter/AStyle.java b/app/src/cc/arduino/packages/formatter/AStyle.java
new file mode 100644
index 000000000..54d51dfde
--- /dev/null
+++ b/app/src/cc/arduino/packages/formatter/AStyle.java
@@ -0,0 +1,68 @@
+package cc.arduino.packages.formatter;
+
+import processing.app.Base;
+import processing.app.Editor;
+import processing.app.helpers.FileUtils;
+import processing.app.tools.Tool;
+
+import java.io.File;
+import java.io.IOException;
+
+import static processing.app.I18n._;
+
+public class AStyle implements Tool {
+
+ private static String FORMATTER_CONF = "formatter.conf";
+
+ private final AStyleInterface aStyleInterface;
+ private final String formatterConfiguration;
+ private Editor editor;
+
+ public AStyle() {
+ this.aStyleInterface = new AStyleInterface();
+ File customFormatterConf = Base.getSettingsFile(FORMATTER_CONF);
+ File defaultFormatterConf = new File(Base.getContentFile("lib"), FORMATTER_CONF);
+
+ File formatterConf;
+ if (customFormatterConf.exists()) {
+ formatterConf = customFormatterConf;
+ } else {
+ formatterConf = defaultFormatterConf;
+ }
+ String formatterConfiguration = "";
+
+ try {
+ formatterConfiguration = FileUtils.readFileToString(formatterConf);
+ } catch (IOException e) {
+ // noop
+ }
+ this.formatterConfiguration = formatterConfiguration;
+ }
+
+ @Override
+ public void init(Editor editor) {
+ this.editor = editor;
+ }
+
+ @Override
+ public void run() {
+ String originalText = editor.getText();
+ String formattedText = aStyleInterface.AStyleMain(originalText, formatterConfiguration);
+
+ if (formattedText.equals(originalText)) {
+ editor.statusNotice(_("No changes necessary for Auto Format."));
+ return;
+ }
+
+ editor.setText(formattedText);
+ editor.getSketch().setModified(true);
+ // mark as finished
+ editor.statusNotice(_("Auto Format finished."));
+ }
+
+ @Override
+ public String getMenuTitle() {
+ return _("Auto Format");
+ }
+
+}
diff --git a/app/src/cc/arduino/packages/formatter/AStyleInterface.java b/app/src/cc/arduino/packages/formatter/AStyleInterface.java
new file mode 100644
index 000000000..8c08c6446
--- /dev/null
+++ b/app/src/cc/arduino/packages/formatter/AStyleInterface.java
@@ -0,0 +1,54 @@
+package cc.arduino.packages.formatter;
+
+import processing.app.Base;
+
+import java.io.File;
+
+public class AStyleInterface {
+
+ static {
+ File astyleLib = new File(Base.getContentFile("lib"), System.mapLibraryName("astylej"));
+ String astylePath = astyleLib.getAbsolutePath();
+ try {
+ System.load(astylePath);
+ } catch (UnsatisfiedLinkError e) {
+ e.printStackTrace();
+ System.out.println(e.getMessage());
+ System.out.println("Cannot load native library " + astylePath);
+ System.out.println("The program has terminated!");
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Calls the AStyleMain function in Artistic Style.
+ *
+ * @param textIn A string containing the source code to be formatted.
+ * @param options A string of options to Artistic Style.
+ * @return A String containing the formatted source from Artistic Style.
+ */
+ public native String AStyleMain(String textIn, String options);
+
+ /**
+ * Calls the AStyleGetVersion function in Artistic Style.
+ *
+ * @return A String containing the version number of Artistic Style.
+ */
+ public native String AStyleGetVersion();
+
+ /**
+ * Error handler for messages from Artistic Style.
+ * This method is called only if there are errors when AStyleMain is called.
+ * This is for debugging and there should be no errors when the calling
+ * parameters are correct.
+ * Changing the method name requires changing Artistic Style.
+ * Signature: (ILjava/lang/String;)V.
+ *
+ * @param errorNumber The error number from Artistic Style.
+ * @param errorMessage The error message from Artistic Style.
+ */
+ private void ErrorHandler(int errorNumber, String errorMessage) {
+ System.out.println("AStyle error " + String.valueOf(errorNumber) + " - " + errorMessage);
+ }
+
+}
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index 284a39148..0929092f7 100644
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -907,7 +907,7 @@ public class Editor extends JFrame implements RunnerListener {
protected JMenu addInternalTools(JMenu menu) {
JMenuItem item;
- item = createToolMenuItem("processing.app.tools.AutoFormat");
+ item = createToolMenuItem("cc.arduino.packages.formatter.AStyle");
int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
item.setAccelerator(KeyStroke.getKeyStroke('T', modifiers));
menu.add(item);
diff --git a/app/src/processing/app/helpers/FileUtils.java b/app/src/processing/app/helpers/FileUtils.java
index f35a14918..bf562a80b 100644
--- a/app/src/processing/app/helpers/FileUtils.java
+++ b/app/src/processing/app/helpers/FileUtils.java
@@ -1,9 +1,6 @@
package processing.app.helpers;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
@@ -170,4 +167,25 @@ public class FileUtils {
public static boolean isSCCSOrHiddenFile(File file) {
return file.isHidden() || file.getName().charAt(0) == '.' || (file.isDirectory() && SOURCE_CONTROL_FOLDERS.contains(file.getName()));
}
+
+ public static String readFileToString(File file) throws IOException {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
+ StringBuilder sb = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ sb.append(line).append("\n");
+ }
+ return sb.toString();
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ // noop
+ }
+ }
+ }
+ }
}
diff --git a/build/build.xml b/build/build.xml
index 6eddc3de9..e9e023b2d 100644
--- a/build/build.xml
+++ b/build/build.xml
@@ -259,6 +259,11 @@
+
+
+
+
+
@@ -470,6 +475,11 @@
+
+
+
+
+
@@ -485,6 +495,7 @@
+
@@ -659,6 +670,10 @@
+
+
+
+
diff --git a/build/shared/lib/formatter.conf b/build/shared/lib/formatter.conf
new file mode 100644
index 000000000..255716d1d
--- /dev/null
+++ b/build/shared/lib/formatter.conf
@@ -0,0 +1,28 @@
+# This configuration file contains a selection of the available options provided by the formatting tool "Artistic Style"
+# http://astyle.sourceforge.net/astyle.html
+#
+# If you wish to change them, don't edit this file.
+# Instead, copy it in the same folder of file "preferences.txt" and modify the copy. This way, you won't lose your custom formatter settings when upgrading the IDE
+# If you don't know where file preferences.txt is stored, open the IDE, File -> Preferences and you'll find a link
+
+# 2 spaces indentation
+indent=spaces=2
+
+# also indent macros
+indent-preprocessor
+
+# indent classes, switches (and cases), comments starting at column 1
+indent-classes
+indent-switches
+indent-cases
+indent-col1-comments
+
+# put a space around operators
+pad-oper
+
+# put a space after if/for/while
+pad-header
+
+# if you like one-liners, keep them
+keep-one-line-statements
+