Commit aa630358 authored by Alexander Weigl's avatar Alexander Weigl

Execution Marker

parent 30714eee
...@@ -178,6 +178,8 @@ IMP : '==>' ; ...@@ -178,6 +178,8 @@ IMP : '==>' ;
EQUIV : '<=>' ; EQUIV : '<=>' ;
NOT: 'not'; NOT: 'not';
EXE_MARKER: '\u2316' -> channel(HIDDEN);
DIGITS : DIGIT+ ; DIGITS : DIGIT+ ;
fragment DIGIT : [0-9] ; fragment DIGIT : [0-9] ;
ID : [a-zA-Z] ([_a-zA-Z0-9] | '.' | '\\' )* ; ID : [a-zA-Z] ([_a-zA-Z0-9] | '.' | '\\' )* ;
\ No newline at end of file
...@@ -48,6 +48,7 @@ import org.reactfx.value.Val; ...@@ -48,6 +48,7 @@ import org.reactfx.value.Val;
import java.io.File; import java.io.File;
import java.time.Duration; import java.time.Duration;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import java.util.function.IntFunction; import java.util.function.IntFunction;
/** /**
...@@ -56,11 +57,13 @@ import java.util.function.IntFunction; ...@@ -56,11 +57,13 @@ import java.util.function.IntFunction;
* It displays the script code and allows highlighting of lines and setting of breakpoints * It displays the script code and allows highlighting of lines and setting of breakpoints
*/ */
public class ScriptArea extends CodeArea { public class ScriptArea extends CodeArea {
private static final Logger LOGGER = LogManager.getLogger(ScriptArea.class); public static final Logger LOGGER = LogManager.getLogger(ScriptArea.class);
public static final String EXECUTION_MARKER = "\u2316";
/** /**
* Underlying filepath, should not be null * Underlying filepath, should not be null
*/ */
private final ObjectProperty<File> filePath = new SimpleObjectProperty<>(new File(Utils.getRandomName())); private final ObjectProperty<File> filePath = new SimpleObjectProperty<>(this, "filePath", new File(Utils.getRandomName()));
/** /**
* If true, the content was changed since last save. * If true, the content was changed since last save.
...@@ -71,6 +74,7 @@ public class ScriptArea extends CodeArea { ...@@ -71,6 +74,7 @@ public class ScriptArea extends CodeArea {
* CSS classes for regions, used for "manually" highlightning. e.g. debugging marker * CSS classes for regions, used for "manually" highlightning. e.g. debugging marker
*/ */
private final SetProperty<RegionStyle> markedRegions = new SimpleSetProperty<>(FXCollections.observableSet()); private final SetProperty<RegionStyle> markedRegions = new SimpleSetProperty<>(FXCollections.observableSet());
/** /**
* set by {@link ScriptController} * set by {@link ScriptController}
*/ */
...@@ -82,6 +86,9 @@ public class ScriptArea extends CodeArea { ...@@ -82,6 +86,9 @@ public class ScriptArea extends CodeArea {
private SimpleObjectProperty<CharacterHit> currentMouseOver = new SimpleObjectProperty<>(); private SimpleObjectProperty<CharacterHit> currentMouseOver = new SimpleObjectProperty<>();
private ScriptAreaContextMenu contextMenu = new ScriptAreaContextMenu(); private ScriptAreaContextMenu contextMenu = new ScriptAreaContextMenu();
private Consumer<Token> onPostMortem = token -> {
};
private int getTextWithoutMarker;
public ScriptArea() { public ScriptArea() {
init(); init();
...@@ -96,14 +103,17 @@ public class ScriptArea extends CodeArea { ...@@ -96,14 +103,17 @@ public class ScriptArea extends CodeArea {
getStyleClass().add("script-area"); getStyleClass().add("script-area");
installPopup(); installPopup();
setOnMouseClicked(this::showContextMenu); // setOnMouseClicked(this::showContextMenu);
setContextMenu(contextMenu);
textProperty().addListener((prop, oldValue, newValue) -> { textProperty().addListener((prop, oldValue, newValue) -> {
dirty.set(true); dirty.set(true);
updateMainScriptMarker(); updateMainScriptMarker();
updateHighlight(); updateHighlight();
highlightProblems(); highlightProblems();
highlightNonExecutionArea();
}); });
markedRegions.addListener((InvalidationListener) o -> updateHighlight()); markedRegions.addListener((InvalidationListener) o -> updateHighlight());
/* .successionEnds(Duration.ofMillis(100)) /* .successionEnds(Duration.ofMillis(100))
...@@ -118,7 +128,6 @@ public class ScriptArea extends CodeArea { ...@@ -118,7 +128,6 @@ public class ScriptArea extends CodeArea {
} }
}).subscribe(s -> setStyleSpans(0, s));*/ }).subscribe(s -> setStyleSpans(0, s));*/
this.addEventHandler(MouseEvent.MOUSE_PRESSED, (MouseEvent e) -> { this.addEventHandler(MouseEvent.MOUSE_PRESSED, (MouseEvent e) -> {
CharacterHit hit = this.hit(e.getX(), e.getY()); CharacterHit hit = this.hit(e.getX(), e.getY());
currentMouseOver.set(this.hit(e.getX(), e.getY())); currentMouseOver.set(this.hit(e.getX(), e.getY()));
...@@ -131,6 +140,16 @@ public class ScriptArea extends CodeArea { ...@@ -131,6 +140,16 @@ public class ScriptArea extends CodeArea {
mainScript.addListener((observable) -> updateMainScriptMarker()); mainScript.addListener((observable) -> updateMainScriptMarker());
} }
private void highlightNonExecutionArea() {
if (hasExecutionMarker()) {
setStyle(0, getExecutionMarkerPosition(), Collections.singleton("NON_EXE_AREA"));
}
}
private boolean hasExecutionMarker() {
return getText().contains(EXECUTION_MARKER);
}
public void showContextMenu(MouseEvent mouseEvent) { public void showContextMenu(MouseEvent mouseEvent) {
if (contextMenu.isShowing()) if (contextMenu.isShowing())
contextMenu.hide(); contextMenu.hide();
...@@ -160,7 +179,8 @@ public class ScriptArea extends CodeArea { ...@@ -160,7 +179,8 @@ public class ScriptArea extends CodeArea {
private void updateMainScriptMarker() { private void updateMainScriptMarker() {
try { try {
MainScriptIdentifier ms = mainScript.get(); MainScriptIdentifier ms = mainScript.get();
System.out.println("ScriptArea.updateMainScriptMarker"); LOGGER.debug("ScriptArea.updateMainScriptMarker");
if (ms != null && filePath.get().getAbsolutePath().equals(ms.getSourceName())) { if (ms != null && filePath.get().getAbsolutePath().equals(ms.getSourceName())) {
System.out.println(ms); System.out.println(ms);
CharStream stream = CharStreams.fromString(getText(), filePath.get().getAbsolutePath()); CharStream stream = CharStreams.fromString(getText(), filePath.get().getAbsolutePath());
...@@ -239,6 +259,7 @@ public class ScriptArea extends CodeArea { ...@@ -239,6 +259,7 @@ public class ScriptArea extends CodeArea {
} }
public void setText(String text) { public void setText(String text) {
clear();
insertText(0, text); insertText(0, text);
} }
...@@ -306,6 +327,57 @@ public class ScriptArea extends CodeArea { ...@@ -306,6 +327,57 @@ public class ScriptArea extends CodeArea {
d.show((Node) event.getTarget(), event.getScreenX(), event.getScreenY()); d.show((Node) event.getTarget(), event.getScreenX(), event.getScreenY());
} }
public Consumer<Token> getOnPostMortem() {
return onPostMortem;
}
public void setOnPostMortem(Consumer<Token> onPostMortem) {
this.onPostMortem = onPostMortem;
}
public ObservableSet<RegionStyle> getMarkedRegions() {
return markedRegions.get();
}
public void setMarkedRegions(ObservableSet<RegionStyle> markedRegions) {
this.markedRegions.set(markedRegions);
}
public SetProperty<RegionStyle> markedRegionsProperty() {
return markedRegions;
}
public boolean isDirty() {
return dirty.get();
}
public void setDirty(boolean dirty) {
this.dirty.set(dirty);
}
public BooleanProperty dirtyProperty() {
return dirty;
}
public void removeExecutionMarker() {
setText(getTextWithoutMarker());
}
private String getTextWithoutMarker() {
return getText().replace("" + EXECUTION_MARKER, "");
}
public void insertExecutionMarker(int pos) {
LOGGER.debug("ScriptArea.insertExecutionMarker");
String text = getText();
setText(text.substring(0, pos) + EXECUTION_MARKER + text.substring(pos));
}
public int getExecutionMarkerPosition() {
return getText().lastIndexOf(EXECUTION_MARKER);
}
private static class GutterView extends HBox { private static class GutterView extends HBox {
private final SimpleObjectProperty<GutterAnnotation> annotation = new SimpleObjectProperty<>(); private final SimpleObjectProperty<GutterAnnotation> annotation = new SimpleObjectProperty<>();
...@@ -463,6 +535,13 @@ public class ScriptArea extends CodeArea { ...@@ -463,6 +535,13 @@ public class ScriptArea extends CodeArea {
} }
} }
@RequiredArgsConstructor
@Data
public static class RegionStyle {
public final int start, stop;
public final String clazzName;
}
public class GutterFactory implements IntFunction<Node> { public class GutterFactory implements IntFunction<Node> {
private final Background defaultBackground = private final Background defaultBackground =
new Background(new BackgroundFill(Color.web("#ddd"), null, null)); new Background(new BackgroundFill(Color.web("#ddd"), null, null));
...@@ -553,7 +632,9 @@ public class ScriptArea extends CodeArea { ...@@ -553,7 +632,9 @@ public class ScriptArea extends CodeArea {
public void showPostMortem(ActionEvent event) { public void showPostMortem(ActionEvent event) {
LOGGER.debug("ScriptAreaContextMenu.showPostMortem " + event); LOGGER.debug("ScriptAreaContextMenu.showPostMortem " + event);
CharacterHit pos = currentMouseOver.get();
Token node = Utils.findToken(getText(), pos.getInsertionIndex());
onPostMortem.accept(node);
//TODO forward to ProofTreeController, it jumps to the node and this should be done via the callbacks. //TODO forward to ProofTreeController, it jumps to the node and this should be done via the callbacks.
...@@ -564,36 +645,12 @@ public class ScriptArea extends CodeArea { ...@@ -564,36 +645,12 @@ public class ScriptArea extends CodeArea {
area.highlightStmt(lineNumber, "line-highlight-postmortem"); area.highlightStmt(lineNumber, "line-highlight-postmortem");
}*/ }*/
} }
}
public ObservableSet<RegionStyle> getMarkedRegions() {
return markedRegions.get();
}
public SetProperty<RegionStyle> markedRegionsProperty() { public void setExecutionMarker(ActionEvent event) {
return markedRegions; LOGGER.debug("ScriptAreaContextMenu.setExecutionMarker");
} int pos = getCaretPosition();
removeExecutionMarker();
public void setMarkedRegions(ObservableSet<RegionStyle> markedRegions) { insertExecutionMarker(pos);
this.markedRegions.set(markedRegions); }
}
public boolean isDirty() {
return dirty.get();
}
public BooleanProperty dirtyProperty() {
return dirty;
}
public void setDirty(boolean dirty) {
this.dirty.set(dirty);
}
@RequiredArgsConstructor
@Data
public static class RegionStyle {
public final int start, stop;
public final String clazzName;
} }
} }
...@@ -3,6 +3,7 @@ package edu.kit.formal.gui.controls; ...@@ -3,6 +3,7 @@ package edu.kit.formal.gui.controls;
import de.uka.ilkd.key.logic.op.IProgramMethod; import de.uka.ilkd.key.logic.op.IProgramMethod;
import de.uka.ilkd.key.pp.ProgramPrinter; import de.uka.ilkd.key.pp.ProgramPrinter;
import de.uka.ilkd.key.speclang.Contract; import de.uka.ilkd.key.speclang.Contract;
import edu.kit.formal.proofscriptparser.ScriptLanguageLexer;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
...@@ -12,6 +13,8 @@ import javafx.scene.control.Label; ...@@ -12,6 +13,8 @@ import javafx.scene.control.Label;
import javafx.scene.control.TextArea; import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.Token;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
...@@ -192,4 +195,18 @@ public class Utils { ...@@ -192,4 +195,18 @@ public class Utils {
o.addListener((ChangeListener<Object>) (observable, oldValue, newValue) -> o.addListener((ChangeListener<Object>) (observable, oldValue, newValue) ->
logger.debug("Observable {} changed from {} to {}", id, oldValue, newValue)); logger.debug("Observable {} changed from {} to {}", id, oldValue, newValue));
} }
public static Token findToken(String text, int insertionIndex) {
ScriptLanguageLexer lexer = new ScriptLanguageLexer(CharStreams.fromString(text));
for (Token t : lexer.getAllTokens()) {
if (t.getType() == ScriptLanguageLexer.WS
|| t.getType() == ScriptLanguageLexer.MULTI_LINE_COMMENT
|| t.getType() == ScriptLanguageLexer.SINGLE_LINE_COMMENT)
continue;
if (t.getStopIndex() >= insertionIndex)
return t;
}
return null;
}
} }
...@@ -2,12 +2,15 @@ ...@@ -2,12 +2,15 @@
<?import edu.kit.formal.gui.controls.*?> <?import edu.kit.formal.gui.controls.*?>
<?import javafx.scene.control.MenuItem?> <?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SeparatorMenuItem?>
<fx:root type="edu.kit.formal.gui.controls.ScriptArea.ScriptAreaContextMenu" <fx:root type="edu.kit.formal.gui.controls.ScriptArea.ScriptAreaContextMenu"
xmlns="http://javafx.com/javafx" xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml" > xmlns:fx="http://javafx.com/fxml" >
<items> <items>
<MenuItem text="show post mortem" onAction="#showPostMortem"/> <MenuItem text="Show post mortem" onAction="#showPostMortem"/>
<MenuItem text="Set main script" onAction="#setMainScript"/> <SeparatorMenuItem/>
<MenuItem text="Set Main Script" onAction="#setMainScript"/>
<MenuItem text="Set Execution Marker" onAction="#setExecutionMarker" accelerator="Ctrl+m"/>
</items> </items>
</fx:root> </fx:root>
...@@ -35,6 +35,21 @@ ...@@ -35,6 +35,21 @@
} }
.EXE_MARKER {
-fx-fill: @violet;
-fx-border-color: red;
-fx-font-size: 120%;
-fx-font-weight: bold;
}
.NON_EXE_AREA {
-rtfx-background: @cyan;
-rtfx-underline-cap: butt;
-rtfx-underline-color: @cyan;
-rtfx-underline-width: 1px;
}
// Structures // Structures
.FOREACH, .CASES, .CASE, .DEFAULT .FOREACH, .CASES, .CASE, .DEFAULT
.THEONLY, .SCRIPT, .USING, .REPEAT { .THEONLY, .SCRIPT, .USING, .REPEAT {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment