Skip to content

Commit

Permalink
More GUI REPL syntax highlighting
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Aug 21, 2023
1 parent 1fe6109 commit 3133b51
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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<AString> trace) {
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -272,44 +268,44 @@ 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
*/
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();
}
Expand Down
123 changes: 121 additions & 2 deletions convex-gui/src/main/java/convex/gui/utils/CVXHighlighter.java
Original file line number Diff line number Diff line change
@@ -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; i<PARENS.length; i++) {
Color c=Color.getHSBColor((0.1f*i), 1, 1);
c=c.brighter();
AttributeSet aset = sc.addAttribute(BASE, StyleConstants.Foreground, c);
PARENS[i]=aset;
}
}

public static void highlight(JTextPane inputArea, int start, int end) {
try {
// Get range of text to format
StyledDocument d=inputArea.getStyledDocument();
int dlen=d.getLength();
end=Math.min(end, dlen); // ensure in bounds

String input=d.getText(start, end-start);

CharStream cs=CharStreams.fromString(input);
ConvexLexer lexer=new ConvexLexer(cs);
lexer.removeErrorListeners();
CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.fill();
//ConvexParser parser = new ConvexParser(tokens);
//parser.removeErrorListeners();
//ParseTree pt = parser.forms();

int tcount=tokens.size();
int nest=0;
for (int i=0; i<tcount; i++) {
Token tok=tokens.get(i);
int tstart=start+tok.getStartIndex();
int tend=start+tok.getStopIndex()+1;
int tlen=tend-tstart;

if (tlen>0) {
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];
}

}

0 comments on commit 3133b51

Please sign in to comment.