Skip to content
This repository has been archived by the owner on Oct 19, 2023. It is now read-only.

Commit

Permalink
Implemented parser based syntax highlighting
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffreyguenther committed Sep 30, 2014
1 parent cce70a3 commit ac66a42
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public class ShiroPlayground extends Application {
private CodeArea codeArea;
private ExecutorService executor;


@Override
public void start(Stage primaryStage) throws Exception {
executor = Executors.newSingleThreadExecutor();
Expand Down
129 changes: 129 additions & 0 deletions src/main/java/org/shirolang/playground/ShiroPlaygroundParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright (c) 2012-2014 Jeffrey Guenther
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package org.shirolang.playground;

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.fxmisc.richtext.*;
import org.reactfx.EventStream;
import org.shirolang.interpreter.ShiroLexer;
import org.shirolang.interpreter.ShiroParser;

import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
*
*/
public class ShiroPlaygroundParser extends Application {
private CodeArea codeArea;
private ExecutorService executor;


@Override
public void start(Stage primaryStage) throws Exception {
executor = Executors.newSingleThreadExecutor();
codeArea = new CodeArea();
codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea));

EventStream<PlainTextChange> textChanges = codeArea.plainTextChanges();

textChanges.successionEnds(Duration.ofMillis(500))
.supplyTask(this::computeHighlightingAsync)
.awaitLatest(textChanges)
.subscribe(this::applyHighlighting);

codeArea.replaceText("port a Double(343)\n" +
"port b String(\"dfd\")\n" +
"node D begin\n" +
"port a Double(12)\n" +
"end");

Scene scene = new Scene(new StackPane(codeArea), 600, 400);
scene.getStylesheets().add(getClass().getResource("syntax.css").toExternalForm());
primaryStage.setTitle("Shiro Playground");
primaryStage.setScene(scene);
primaryStage.show();
}

@Override
public void stop() throws Exception {
// stop the thread service
executor.shutdown();
}

private Task<StyleSpans<Collection<String>>> computeHighlightingAsync(){
String code = codeArea.getText();

Task<StyleSpans<Collection<String>>> task = new Task<StyleSpans<Collection<String>>>() {
@Override
protected StyleSpans<Collection<String>> call() throws Exception {
return computeHighlighting(code);
}
};
executor.execute(task);
return task;
}

private static StyleSpans<Collection<String>> computeHighlighting(String text){
if(text.length() > 0){
ShiroLexer lex = new ShiroLexer(new ANTLRInputStream(text));
lex.getErrorListeners().clear();
// parse
ShiroParser parser = new ShiroParser(new CommonTokenStream(lex));
parser.getErrorListeners().clear();
parser.setBuildParseTree(true);
ShiroParser.ShiroContext shiro = parser.shiro();

ParseTreeWalker walker = new ParseTreeWalker();
SyntaxHighlighter h = new SyntaxHighlighter(text.length());
walker.walk(h, shiro);
return h.getStyles();
}else{
StyleSpansBuilder<Collection<String>> objectStyleSpansBuilder = new StyleSpansBuilder<>();
objectStyleSpansBuilder.add(Collections.emptyList(), 0);
return objectStyleSpansBuilder.create();
}
}

private void applyHighlighting(StyleSpans<Collection<String>> highlighting) {
if(highlighting.getSpanCount() > 0) {
codeArea.setStyleSpans(0, highlighting);
}
}

public static void main(String[] args) {
launch(args);
}
}
50 changes: 35 additions & 15 deletions src/main/java/org/shirolang/playground/SyntaxHighlighter.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@

import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.fxmisc.richtext.StyleSpans;
import org.fxmisc.richtext.StyleSpansBuilder;
import org.shirolang.interpreter.ShiroBaseListener;
import org.shirolang.interpreter.ShiroParser;

import javax.xml.bind.SchemaOutputResolver;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
Expand All @@ -45,43 +47,61 @@ public class SyntaxHighlighter extends ShiroBaseListener{

public SyntaxHighlighter(int l) {
textlength = l;
}
}

@Override
public void enterShiro(@NotNull ShiroParser.ShiroContext ctx) {
lastEnd = 0;
}

@Override
public void enterPortDecl(@NotNull ShiroParser.PortDeclContext ctx) {
add(ctx.MFNAME().getSymbol(), "mf");
public void exitPortDecl(@NotNull ShiroParser.PortDeclContext ctx) {
add(ctx.MFNAME(), "mf");
}

@Override
public void enterPortName(@NotNull ShiroParser.PortNameContext ctx) {
add(ctx.IDENT().getSymbol(), "ident");
add(ctx.IDENT(), "ident");
}

@Override
public void enterMfName(@NotNull ShiroParser.MfNameContext ctx) {
add(ctx.MFNAME().getSymbol(), "mf");
add(ctx.MFNAME(), "mf");
}

@Override
public void enterNodestmt(@NotNull ShiroParser.NodestmtContext ctx) {
add(ctx.BEGIN().getSymbol(), "begin-end");
add(ctx.MFNAME().getSymbol(), "ident");
add(ctx.MFNAME().getSymbol(), "node-type");
add(ctx.END().getSymbol(), "begin-end");
add(ctx.MFNAME(), "node-type");
add(ctx.BEGIN(), "begin-end");


}

@Override
public void exitNodestmt(@NotNull ShiroParser.NodestmtContext ctx) {
add(ctx.END(), "begin-end");
}

/**
* @return the styles
*/
public StyleSpans<Collection<String>> getStyles() {
spansBuilder.add(Collections.emptyList(), textlength - lastEnd);
spansBuilder.add(Collections.emptyList(), textlength - lastEnd );
return spansBuilder.create();
}

private void add(Token ident, String style) {
System.out.println("start: " + ident.getStartIndex() + " end: " + ident.getStopIndex());
spansBuilder.add(Collections.emptyList(), ident.getStartIndex() - lastEnd);
spansBuilder.add(Collections.singleton(style), (ident.getStopIndex() + 1 - ident.getStartIndex()));
lastEnd = ident.getStopIndex() + 1;
private void add(TerminalNode ident, String style) {
if(ident != null) {
Token t = ident.getSymbol();

int spacer = t.getStartIndex() - lastEnd;
if(spacer > 0) {
spansBuilder.add(Collections.emptyList(), spacer);

int gap = t.getText().length();
spansBuilder.add(Collections.singleton(style), gap);
lastEnd = t.getStopIndex() + 1;
}
}
}
}
1 change: 1 addition & 0 deletions src/main/resources/org/shirolang/playground/syntax.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

.node-type{
-fx-fill: rgb(55, 26, 148);
-fx-font-weight: bold;
}

.mf{
Expand Down

0 comments on commit ac66a42

Please sign in to comment.