diff --git a/lib/autocomplete-2.5.4.jar b/lib/autocomplete-2.5.4.jar new file mode 100644 index 0000000..e6b2299 Binary files /dev/null and b/lib/autocomplete-2.5.4.jar differ diff --git a/nbproject/project.properties b/nbproject/project.properties index 450d76a..cef1491 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -31,6 +31,7 @@ dist.jar=${dist.dir}/SyMAT.jar dist.javadoc.dir=${dist.dir}/javadoc endorsed.classpath= excludes= +file.reference.autocomplete-2.5.4.jar=lib/autocomplete-2.5.4.jar file.reference.htmlcleaner-2.10.jar=lib/htmlcleaner-2.10.jar file.reference.iText-4.2.0-com.itextpdf.jar=lib/iText-4.2.0-com.itextpdf.jar file.reference.JavaPrettify-1.2.1.jar=lib/JavaPrettify-1.2.1.jar @@ -53,7 +54,8 @@ javac.classpath=\ ${file.reference.js-engine.jar}:\ ${file.reference.js.jar}:\ ${file.reference.jython-standalone-2.7-b3.jar}:\ - ${file.reference.rsyntaxtextarea-2.5.6.jar} + ${file.reference.rsyntaxtextarea-2.5.6.jar}:\ + ${file.reference.autocomplete-2.5.4.jar} # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false diff --git a/src/net/apocalypselabs/symat/CodeCompleter.java b/src/net/apocalypselabs/symat/CodeCompleter.java new file mode 100644 index 0000000..d27bed3 --- /dev/null +++ b/src/net/apocalypselabs/symat/CodeCompleter.java @@ -0,0 +1,97 @@ +/* + * Apocalypse Laboratories + * Open Source License + * + * Source code can be used for any purpose, as long as: + * - Compiled binaries are rebranded and trademarks are not + * visible by the end user at any time, except to give + * credit to Apocalypse Laboratories, such as by showing + * "Based on by Apocalypse Laboratories" or a + * similar notice; + * - You do not use the code for evil; + * - Rebranded compiled applications have significant + * differences in functionality; + * - and you provide your modified source code for download, + * under the terms of the GNU LGPL v3 or a comparable + * license. + * + * Compiled binaries cannot be redistributed or mirrored, + * unless: + * - You have written permission from Apocalypse Laboratories; + * - Downloads are not available from Apocalypse Laboratories, + * not even behind a paywall or other blocking mechanism; + * - or you have received a multi-computer license, in which + * case you should take measures to prevent unauthorized + * downloads, such as preventing download access from the + * Internet. + */ +package net.apocalypselabs.symat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import org.fife.ui.autocomplete.BasicCompletion; +import org.fife.ui.autocomplete.Completion; +import org.fife.ui.autocomplete.CompletionProvider; +import org.fife.ui.autocomplete.DefaultCompletionProvider; +import org.fife.ui.autocomplete.FunctionCompletion; +import org.fife.ui.autocomplete.MarkupTagCompletion; +import org.fife.ui.autocomplete.ShorthandCompletion; +import org.fife.ui.autocomplete.VariableCompletion; + +/** + * + * @author Skylar + */ +public class CodeCompleter { + + private final CompletionProvider provider; + private final String lang; + + /** + * + * @param language Either js or py. + */ + public CodeCompleter(String language) { + lang = language; + provider = makeCompletions(); + } + + public CompletionProvider getProvider() { + return provider; + } + + private CompletionProvider makeCompletions() { + DefaultCompletionProvider provider = new DefaultCompletionProvider(); + try { + String[] files = {"functions", "constants"}; + for (String fileid : files) { + BufferedReader reader = new BufferedReader( + new InputStreamReader( + CodeEditor.class.getResourceAsStream("resources/" + lang + fileid + ".txt"))); + String line; + while ((line = reader.readLine()) != null) { + switch (fileid) { + case "functions": + String[] args = line.split("\\|"); + if (args.length == 2) { + provider.addCompletion(new BasicCompletion(provider, args[0], args[1])); + } else if (args.length == 3) { + provider.addCompletion(new BasicCompletion(provider, args[0], args[1], args[2])); + } else { + provider.addCompletion(new BasicCompletion(provider, args[0])); + } + break; + case "constants": + provider.addCompletion(new VariableCompletion(provider, line, "double")); + break; + } + } + } + } catch (IOException ex) { + Debug.printerr(ex.getMessage()); + } + return provider; + } + +} diff --git a/src/net/apocalypselabs/symat/CodeEditor.form b/src/net/apocalypselabs/symat/CodeEditor.form index bc535a4..c70c93c 100644 --- a/src/net/apocalypselabs/symat/CodeEditor.form +++ b/src/net/apocalypselabs/symat/CodeEditor.form @@ -108,17 +108,31 @@ - + - + - + - + + + + + + + + + + + + + + + @@ -130,6 +144,17 @@ + + + + + + + + + + + diff --git a/src/net/apocalypselabs/symat/CodeEditor.java b/src/net/apocalypselabs/symat/CodeEditor.java index 7d03766..5257503 100644 --- a/src/net/apocalypselabs/symat/CodeEditor.java +++ b/src/net/apocalypselabs/symat/CodeEditor.java @@ -40,12 +40,13 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; -import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; +import org.fife.ui.autocomplete.AutoCompletion; +import org.fife.ui.autocomplete.CompletionProvider; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.Theme; @@ -62,6 +63,11 @@ public class CodeEditor extends javax.swing.JInternalFrame { private RSyntaxTextArea codeBox = new RSyntaxTextArea(); private RTextScrollPane sp; private String lastSaved = ""; + + private CompletionProvider jscomp = new CodeCompleter("js").getProvider(); + private CompletionProvider pycomp = new CodeCompleter("py").getProvider(); + private AutoCompletion jsac = new AutoCompletion(jscomp); + private AutoCompletion pyac = new AutoCompletion(pycomp); /** * Creates new form CodeEditor @@ -101,6 +107,8 @@ public class CodeEditor extends javax.swing.JInternalFrame { formMouseClicked(evt); } }); + + jsac.install(codeBox); sp.setVisible(true); codeBox.setVisible(true); codeBox.requestFocus(); @@ -161,8 +169,11 @@ public class CodeEditor extends javax.swing.JInternalFrame { saveAsMenu = new javax.swing.JMenuItem(); exportMenu = new javax.swing.JMenuItem(); editMenu = new javax.swing.JMenu(); - copyBtn = new javax.swing.JMenuItem(); + undoBtn = new javax.swing.JMenuItem(); + redoBtn = new javax.swing.JMenuItem(); + jSeparator1 = new javax.swing.JPopupMenu.Separator(); cutBtn = new javax.swing.JMenuItem(); + copyBtn = new javax.swing.JMenuItem(); pasteBtn = new javax.swing.JMenuItem(); runMenu = new javax.swing.JMenu(); runCodeBtn = new javax.swing.JMenuItem(); @@ -316,14 +327,25 @@ public class CodeEditor extends javax.swing.JInternalFrame { editMenu.setText("Edit"); - copyBtn.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_MASK)); - copyBtn.setText("Copy"); - copyBtn.addActionListener(new java.awt.event.ActionListener() { + undoBtn.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.event.InputEvent.CTRL_MASK)); + undoBtn.setText("Undo"); + undoBtn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - copyBtnActionPerformed(evt); + undoBtnActionPerformed(evt); } }); - editMenu.add(copyBtn); + editMenu.add(undoBtn); + + redoBtn.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Y, java.awt.event.InputEvent.CTRL_MASK)); + redoBtn.setText("Redo"); + redoBtn.setToolTipText(""); + redoBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + redoBtnActionPerformed(evt); + } + }); + editMenu.add(redoBtn); + editMenu.add(jSeparator1); cutBtn.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, java.awt.event.InputEvent.CTRL_MASK)); cutBtn.setText("Cut"); @@ -334,6 +356,15 @@ public class CodeEditor extends javax.swing.JInternalFrame { }); editMenu.add(cutBtn); + copyBtn.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_MASK)); + copyBtn.setText("Copy"); + copyBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + copyBtnActionPerformed(evt); + } + }); + editMenu.add(copyBtn); + pasteBtn.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_V, java.awt.event.InputEvent.CTRL_MASK)); pasteBtn.setText("Paste"); pasteBtn.addActionListener(new java.awt.event.ActionListener() { @@ -444,10 +475,12 @@ public class CodeEditor extends javax.swing.JInternalFrame { javascriptOption.setSelected(true); pythonOption.setSelected(false); codeBox.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); + jsac.install(codeBox); } else if (file.matches(".*\\.(sypy|py)")) { javascriptOption.setSelected(false); pythonOption.setSelected(true); codeBox.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON); + pyac.install(codeBox); } } @@ -595,6 +628,14 @@ public class CodeEditor extends javax.swing.JInternalFrame { outputBox.setText(""); }//GEN-LAST:event_clearBtnActionPerformed + private void undoBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_undoBtnActionPerformed + codeBox.undoLastAction(); + }//GEN-LAST:event_undoBtnActionPerformed + + private void redoBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redoBtnActionPerformed + codeBox.redoLastAction(); + }//GEN-LAST:event_redoBtnActionPerformed + /** * Open a sample code file with the given name.

* Uses the current language. @@ -678,6 +719,7 @@ public class CodeEditor extends javax.swing.JInternalFrame { private javax.swing.JMenuItem jMenuItem4; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JPopupMenu.Separator jSeparator1; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JRadioButtonMenuItem javascriptOption; private javax.swing.ButtonGroup langBtnGroup; @@ -687,11 +729,13 @@ public class CodeEditor extends javax.swing.JInternalFrame { private javax.swing.JPanel outputPanel; private javax.swing.JMenuItem pasteBtn; private javax.swing.JRadioButtonMenuItem pythonOption; + private javax.swing.JMenuItem redoBtn; private javax.swing.JMenuItem runCodeBtn; private javax.swing.JMenu runMenu; private javax.swing.JMenuItem sampleGraph; private javax.swing.JMenuItem sampleHelloWorld; private javax.swing.JMenuItem saveAsMenu; private javax.swing.JMenuItem saveMenu; + private javax.swing.JMenuItem undoBtn; // End of variables declaration//GEN-END:variables } diff --git a/src/net/apocalypselabs/symat/MainGUI.form b/src/net/apocalypselabs/symat/MainGUI.form index 863534a..88e66ed 100644 --- a/src/net/apocalypselabs/symat/MainGUI.form +++ b/src/net/apocalypselabs/symat/MainGUI.form @@ -94,18 +94,12 @@ - - - - - - - - - + + + - + @@ -224,8 +218,8 @@ - - + + diff --git a/src/net/apocalypselabs/symat/MainGUI.java b/src/net/apocalypselabs/symat/MainGUI.java index 52f404c..ae9b605 100644 --- a/src/net/apocalypselabs/symat/MainGUI.java +++ b/src/net/apocalypselabs/symat/MainGUI.java @@ -272,15 +272,11 @@ public class MainGUI extends javax.swing.JFrame { .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(shellBtn) .addComponent(editorBtn) - .addComponent(graphBtn)) + .addComponent(graphBtn) + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(helpBtn, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(jPanel4Layout.createSequentialGroup() - .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() - .addComponent(helpBtn) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) ); tabs.addTab("Apps", jPanel4); @@ -341,8 +337,8 @@ public class MainGUI extends javax.swing.JFrame { .addComponent(arrangeWindowsBtn) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(closeAllBtn) - .addGap(94, 94, 94) - .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 490, Short.MAX_VALUE)) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) diff --git a/src/net/apocalypselabs/symat/resources/jsconstants.txt b/src/net/apocalypselabs/symat/resources/jsconstants.txt new file mode 100644 index 0000000..5fe6f09 --- /dev/null +++ b/src/net/apocalypselabs/symat/resources/jsconstants.txt @@ -0,0 +1,8 @@ +E +PI +LN2 +LN10 +LOG2E +LOG10E +SQRT1_2 +SQRT2 \ No newline at end of file diff --git a/src/net/apocalypselabs/symat/resources/jsfunctions.txt b/src/net/apocalypselabs/symat/resources/jsfunctions.txt new file mode 100644 index 0000000..2af5356 --- /dev/null +++ b/src/net/apocalypselabs/symat/resources/jsfunctions.txt @@ -0,0 +1,30 @@ +notify|return nothing|Display a message in a box. +ask|return String|Ask a question in a box. Supply question text. +D|return String|Find the derivative of the function passed with respect to the second argument. +rad|return double|Convert a given number in degrees to radians. +deg|return double|Convert a given number in radians to degrees. +subs|return double|Solve an equation for the second argument. +plot|return nothing|Graph the given function. +graph|alias of plot|Graph the given function. +plotname|return nothing or String|Gets or sets the title of the graph window. +plotclr|return nothing|Clear the graph and its history. +clearplot|alias of plotclr|Clear the graph and its history. +plotscale|return nothing|Scale the plot to the given factor. +drawdot|return nothing|Places a red dot at the given coordinates. +abs|return double| +asin|return double| +acos|return double| +atan|return double| +ceil|return double| +exp|return double| +floor|return double| +log|return double| +max|return double|Returns the highest number given. +min|return double|Returns the lowest number given. +pow|return double| +random|return double|Gives a random number between 0.0 and 1.0. +round|return double| +sin|return double| +cos|return double| +tan|return double| +print|return nothing|Prints the supplied text to the output. \ No newline at end of file diff --git a/src/net/apocalypselabs/symat/resources/pyconstants.txt b/src/net/apocalypselabs/symat/resources/pyconstants.txt new file mode 100644 index 0000000..92b21ad --- /dev/null +++ b/src/net/apocalypselabs/symat/resources/pyconstants.txt @@ -0,0 +1,2 @@ +e +pi \ No newline at end of file diff --git a/src/net/apocalypselabs/symat/resources/pyfunctions.txt b/src/net/apocalypselabs/symat/resources/pyfunctions.txt new file mode 100644 index 0000000..cb6328c --- /dev/null +++ b/src/net/apocalypselabs/symat/resources/pyfunctions.txt @@ -0,0 +1,29 @@ +_.notify|return nothing|Display a message in a box. +_.ask|return String|Ask a question in a box. Supply question text. +_.D|return String|Find the derivative of the function passed with respect to the second argument. +radians|return double|Convert a given number in degrees to radians. +degrees|return double|Convert a given number in radians to degrees. +_.subs|return double|Solve an equation for the second argument. +_.plot|return nothing|Graph the given function. +_.graph|alias of plot|Graph the given function. +_.plotname|return nothing or String|Gets or sets the title of the graph window. +_.plotclr|return nothing|Clear the graph and its history. +_.clearplot|alias of plotclr|Clear the graph and its history. +_.plotscale|return nothing|Scale the plot to the given factor. +_.drawdot|return nothing|Places a red dot at the given coordinates. +fabs|return double| +asin|return double| +acos|return double| +atan|return double| +ceil|return double| +exp|return double| +floor|return double| +log|return double| +max|return double|Returns the highest number given. +min|return double|Returns the lowest number given. +pow|return double| +round|return double| +sin|return double| +cos|return double| +tan|return double| +print|return nothing|Prints the supplied text to the output. \ No newline at end of file