From 3133b513750b70544293df603c00e777c7cd47a7 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 21 Aug 2023 17:51:53 +0100 Subject: [PATCH] More GUI REPL syntax highlighting --- .../gui/manager/windows/peer/REPLPanel.java | 86 ++++++------ .../java/convex/gui/utils/CVXHighlighter.java | 123 +++++++++++++++++- 2 files changed, 162 insertions(+), 47 deletions(-) diff --git a/convex-gui/src/main/java/convex/gui/manager/windows/peer/REPLPanel.java b/convex-gui/src/main/java/convex/gui/manager/windows/peer/REPLPanel.java index 5384ad38e..dcb67f242 100644 --- a/convex-gui/src/main/java/convex/gui/manager/windows/peer/REPLPanel.java +++ b/convex-gui/src/main/java/convex/gui/manager/windows/peer/REPLPanel.java @@ -17,7 +17,6 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; -import javax.swing.JTextArea; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; @@ -29,11 +28,6 @@ import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.misc.Interval; -import org.antlr.v4.runtime.tree.ParseTree; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,21 +41,20 @@ import convex.core.data.AString; import convex.core.data.AVector; import convex.core.data.Address; +import convex.core.lang.RT; import convex.core.lang.Reader; import convex.core.lang.Symbols; -import convex.core.lang.reader.ConvexErrorListener; -import convex.core.lang.reader.antlr.ConvexLexer; -import convex.core.lang.reader.antlr.ConvexParser; import convex.core.transactions.ATransaction; import convex.core.transactions.Invoke; import convex.gui.components.AccountChooserPanel; import convex.gui.components.ActionPanel; import convex.gui.components.RightCopyMenu; +import convex.gui.utils.CVXHighlighter; @SuppressWarnings("serial") public class REPLPanel extends JPanel { - JTextArea inputArea; + JTextPane inputArea; JTextPane outputArea; private JButton btnClear; private JButton btnInfo; @@ -97,13 +90,18 @@ protected void handleResult(Result r) { if (r.isError()) { handleError(r.getErrorCode(),r.getValue(),r.getTrace()); } else { - handleResult((Object)r.getValue()); + handleResult((ACell)r.getValue()); } } - protected void handleResult(Object m) { - addOutput(outputArea," => " + m + "\n"); - outputArea.setCaretPosition(outputArea.getDocument().getLength()); + protected void handleResult(ACell m) { + String resultString=RT.print(m).toString(); + int start=outputArea.getDocument().getLength(); + addOutput(outputArea," => " + resultString + "\n"); + int end=outputArea.getDocument().getLength(); + updateHighlight(outputArea,start,end-start); + + outputArea.setCaretPosition(end); } protected void handleError(Object code, Object msg, AVector trace) { @@ -151,7 +149,6 @@ public REPLPanel(Convex convex) { add(splitPane, BorderLayout.CENTER); outputArea = new JTextPane(); - outputArea.setText("foo"); //outputArea.setRows(15); outputArea.setEditable(false); //outputArea.setLineWrap(true); @@ -162,8 +159,7 @@ public REPLPanel(Convex convex) { //caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); splitPane.setLeftComponent(new JScrollPane(outputArea)); - inputArea = new JTextArea(); - inputArea.setRows(5); + inputArea = new JTextPane(); inputArea.setFont(INPUT_FONT); inputArea.getDocument().addDocumentListener(inputListener); inputArea.addKeyListener(inputListener); @@ -272,30 +268,23 @@ private void sendMessage(String s) { }); } - @SuppressWarnings("unused") - public void updateHighlight() { - String input=inputArea.getText(); - try { - CharStream cs=CharStreams.fromString(input); - ConvexLexer lexer=new ConvexLexer(cs); - lexer.removeErrorListeners(); - lexer.addErrorListener(new ConvexErrorListener() ); - CommonTokenStream tokens = new CommonTokenStream(lexer); - ConvexParser parser = new ConvexParser(tokens); - parser.removeErrorListeners(); - ParseTree pt = parser.forms(); - - Interval iv=pt.getSourceInterval(); - int tcount=tokens.size(); - int start=iv.a; - int end=iv.b+1; - int len=iv.length(); - System.out.println(tokens.getTokens()); - } catch (Exception t) { - System.err.println(t); + + boolean highlighting=false; + protected void updateHighlight() { + int len=inputArea.getDocument().getLength(); + if (!highlighting) { + highlighting=true; + updateHighlight(inputArea,0,len); } } + protected void updateHighlight(JTextPane pane,int start, int len) { + SwingUtilities.invokeLater(()->{ + CVXHighlighter.highlight(pane,start,start+len); + highlighting=false; + }); + } + /** * Listener to detect returns at the end of the input box => send message */ @@ -303,13 +292,20 @@ private class InputListener implements DocumentListener, KeyListener { @Override public void insertUpdate(DocumentEvent e) { - int len = e.getLength(); - int off = e.getOffset(); - String s = inputArea.getText(); - - // Detect Enter at end of form - if ((len == 1) && (len + off == s.length()) && (s.charAt(off) == '\n')) { - sendMessage(s.trim()); + try { + int off = e.getOffset(); + int len = e.getLength(); + int end=off+len; + int docLen=e.getDocument().getLength(); + + // Detect Enter at end of form + if ((end==docLen) && ("\n".equals(e.getDocument().getText(end-1,1)))) { + String s=e.getDocument().getText(0, docLen); + sendMessage(s.trim()); + } + } catch (BadLocationException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); } updateHighlight(); } diff --git a/convex-gui/src/main/java/convex/gui/utils/CVXHighlighter.java b/convex-gui/src/main/java/convex/gui/utils/CVXHighlighter.java index f24071e15..30635ad10 100644 --- a/convex-gui/src/main/java/convex/gui/utils/CVXHighlighter.java +++ b/convex-gui/src/main/java/convex/gui/utils/CVXHighlighter.java @@ -1,7 +1,126 @@ package convex.gui.utils; +import java.awt.Color; + +import javax.swing.JTextPane; +import javax.swing.text.AttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import javax.swing.text.StyledDocument; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.Token; + +import convex.core.lang.reader.antlr.ConvexLexer; + public class CVXHighlighter { - public static void highlight() { - + static StyleContext sc = StyleContext.getDefaultStyleContext(); + static AttributeSet BASE = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Italic, false); + static AttributeSet ITALIC = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Italic, true); + + static AttributeSet NORMAL = sc.addAttribute(BASE, StyleConstants.Foreground, Color.LIGHT_GRAY); + static AttributeSet STRING = sc.addAttribute(ITALIC, StyleConstants.Foreground, Color.CYAN); + static AttributeSet KEYWORD = sc.addAttribute(BASE, StyleConstants.Foreground, Color.PINK); + static AttributeSet SYMBOL = NORMAL; + static AttributeSet NUMBER = sc.addAttribute(BASE, StyleConstants.Foreground, Color.ORANGE); + + private static final AttributeSet[] PARENS = new AttributeSet[10]; + + static { + for (int i=0; i0) { + char c=input.charAt(tstart-start); + + AttributeSet aset=NORMAL; + switch (c) { + case '"': { + aset=STRING; break; + } + case ':': { + aset=KEYWORD; break; + } + case '(':{ + aset=getParen(nest++); break; + } + case ')': { + aset=getParen(--nest); break; + } + case '[':{ + nest+=3; + aset=getParen(nest++); break; + } + case ']': { + aset=getParen(--nest); + nest-=3; break; + } + case '{':{ + nest+=6; + aset=getParen(nest++); break; + } + case '}': { + aset=getParen(--nest); + nest-=6; break; + } + // Whitespace uses paren colour, this colours commas! + case ' ': case '\t': case ',': { + aset=getParen(nest); + break; + } + + default: { + if (Character.isDigit(c)) { + aset=NUMBER; break; + } + } + } + + d.setCharacterAttributes(tstart, tlen, aset, false); + } + } + } catch (Exception t) { + t.printStackTrace(); + } + } + + private static AttributeSet getParen(int i) { + if (i<0) i=0; + return PARENS[i%PARENS.length]; + } + }