diff --git a/app/src/cc/arduino/view/git/GitCommit.form b/app/src/cc/arduino/view/git/GitCommit.form
new file mode 100644
index 00000000000..592679bbaf9
--- /dev/null
+++ b/app/src/cc/arduino/view/git/GitCommit.form
@@ -0,0 +1,103 @@
+
+
+
diff --git a/app/src/cc/arduino/view/git/GitCommit.java b/app/src/cc/arduino/view/git/GitCommit.java
new file mode 100644
index 00000000000..f2e4b219e0d
--- /dev/null
+++ b/app/src/cc/arduino/view/git/GitCommit.java
@@ -0,0 +1,224 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * 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.view.git;
+
+import processing.app.Base;
+import processing.app.Editor;
+import processing.app.Sketch;
+import processing.app.helpers.OSUtils;
+import processing.app.syntax.SketchTextArea;
+
+import java.awt.event.WindowEvent;
+import java.io.*;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static processing.app.I18n.tr;
+
+public class GitCommit extends javax.swing.JFrame {
+ private final static Logger LOG = Logger.getLogger(SketchTextArea.class.getName());
+ private final Editor editor;
+
+
+ public GitCommit(Editor editor, Map state) {
+ this.editor = editor;
+
+ initComponents();
+
+ Base.setIcon(this);
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ javax.swing.JLabel commitMessageLabel = new javax.swing.JLabel();
+ commitMessageField = new javax.swing.JTextField();
+ buttonsContainer = new javax.swing.JPanel();
+ cancelButton = new javax.swing.JButton();
+ okButton = new javax.swing.JButton();
+
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setTitle(tr("Commit"));
+ setResizable(false);
+
+ commitMessageLabel.setText(tr("Message:"));
+
+ commitMessageField.setColumns(20);
+
+ cancelButton.setText(tr("Cancel"));
+ cancelButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cancelButtonActionPerformed(evt);
+ }
+ });
+ buttonsContainer.add(cancelButton);
+
+ okButton.setText(tr("Ok"));
+ okButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ okButtonActionPerformed(evt);
+ }
+ });
+ buttonsContainer.add(okButton);
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+ getContentPane().setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(commitMessageLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(commitMessageField, javax.swing.GroupLayout.DEFAULT_SIZE, 513, Short.MAX_VALUE))
+ .addComponent(buttonsContainer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap())
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(commitMessageLabel)
+ .addComponent(commitMessageField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(0, 0, 0)
+ .addComponent(buttonsContainer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+
+ pack();
+ }// //GEN-END:initComponents
+
+ private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
+ dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
+ }//GEN-LAST:event_cancelButtonActionPerformed
+
+ private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
+ commit();
+ dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
+ }//GEN-LAST:event_okButtonActionPerformed
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JPanel buttonsContainer;
+ private javax.swing.JButton cancelButton;
+ private javax.swing.JTextField commitMessageField;
+ private javax.swing.JButton okButton;
+ // End of variables declaration//GEN-END:variables
+
+ private String[] getArgsForProcess(String command) {
+ String[] args = new String[3];
+ if (OSUtils.isWindows()) {
+ args[0] = "cmd.exe";
+ args[1] = "/c";
+ } else { //For Mac and Linux
+ args[0] = "/bin/bash";
+ args[1] = "-cl";
+ }
+
+ args[2] = command;
+
+ return args;
+ }
+
+ private void setSystemEnvironment(Map environment) {
+ environment.put("HOME", System.getProperty("user.home"));
+ environment.put("LANG", "en_US.UTF-8");
+ environment.put("GDM_LANG", "en_US.UTF-8");
+ environment.put("LANGUAGE", "us");
+ }
+
+ private void runCommand(String command, File dir) {
+ ProcessBuilder processBuilder = new ProcessBuilder(getArgsForProcess(command));
+ processBuilder.redirectErrorStream(true);
+
+ setSystemEnvironment(processBuilder.environment());
+
+ processBuilder.directory(dir);
+
+ try {
+ Process process = processBuilder.start();
+ try (BufferedReader errStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ BufferedReader cin = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+ process.waitFor();
+
+ String line;
+ while ((line = errStream.readLine()) != null) {
+ System.out.println(line);
+ LOG.log(Level.WARNING, line);
+ }
+
+ while ((line = cin.readLine()) != null) {
+ System.out.println(line);
+ LOG.log(Level.WARNING, line);
+ }
+
+ if (process.exitValue() == 0) {
+ System.out.println("Git command successful!");
+ LOG.log(Level.FINE, "Git command successful!");
+ }
+
+ } catch (InterruptedException e) {
+ System.out.println(e.getMessage());
+ LOG.log(Level.WARNING, e.getMessage());
+ }
+
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ LOG.log(Level.WARNING, e.getMessage());
+ }
+ }
+
+ private void commit() {
+ String filePath = editor.getSketch().getMainFilePath();
+ StringBuilder command = new StringBuilder(String.format("git add %s && git commit %s ", filePath, filePath));
+
+ String message = commitMessageField.getText();
+ if (!message.isEmpty()) {
+ command.append(" -m \"")
+ .append(message)
+ .append('\"');
+ } else {
+ System.out.println("Commit Failed! Git message wasn't set!");
+ LOG.log(Level.WARNING, "Commit Failed! Git message wasn't set!");
+ return;
+ }
+
+ runCommand(command.toString(), editor.getSketch().getFolder());
+ }
+}
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index 566cabf1c3f..5938e4dff67 100644
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -29,6 +29,7 @@
import cc.arduino.view.GoToLineNumber;
import cc.arduino.view.StubMenuListener;
import cc.arduino.view.findreplace.FindReplace;
+import cc.arduino.view.git.GitCommit;
import com.jcraft.jsch.JSchException;
import jssc.SerialPortException;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
@@ -189,6 +190,7 @@ public boolean test(Sketch sketch) {
protected RedoAction redoAction;
private FindReplace find;
+ private GitCommit gitCommit;
Runnable runHandler;
Runnable presentHandler;
@@ -1502,6 +1504,14 @@ public void actionPerformed(ActionEvent e) {
});
menu.add(findPreviousItem);
+ JMenuItem commitItem = newJMenuItem(tr("Commit..."), 'C');
+ commitItem.addActionListener(e -> {
+ gitCommit = new GitCommit(Editor.this, Collections.emptyMap());
+ gitCommit.setLocationRelativeTo(Editor.this);
+ gitCommit.setVisible(true);
+ });
+ menu.add(commitItem);
+
if (OSUtils.isMacOS()) {
JMenuItem useSelectionForFindItem = newJMenuItem(tr("Use Selection For Find"), 'E');
useSelectionForFindItem.addActionListener(new ActionListener() {