Commit c73bf4f5 authored by Alexander Weigl's avatar Alexander Weigl

auto reload of clean files.

... useful for external editors.
... title = fielpath + dirty flag
parent cad71758
Pipeline #22022 passed with stages
in 5 minutes and 44 seconds
...@@ -42,15 +42,15 @@ public class GoalNode<T> { ...@@ -42,15 +42,15 @@ public class GoalNode<T> {
this(parent, parent.getAssignments(), data, isClosed); this(parent, parent.getAssignments(), data, isClosed);
} }
private GoalNode(GoalNode<T> parent, VariableAssignment assignments, T data, boolean isClosed) { private GoalNode(@Nonnull GoalNode<T> parent, VariableAssignment assignments, T data, boolean isClosed) {
this.assignments = assignments.push(); this.assignments = assignments.push();
this.parent = parent; this.parent = parent;
this.data = data; this.data = data;
this.isClosed = isClosed; this.isClosed = isClosed;
} }
private GoalNode(int id, GoalNode<T> tGoalNode, T data, boolean isClosed) { private GoalNode(int id, GoalNode<T> parent, T data, boolean isClosed) {
this(tGoalNode, data, isClosed); this(parent, data, isClosed);
this.id = id; this.id = id;
} }
...@@ -121,6 +121,12 @@ public class GoalNode<T> { ...@@ -121,6 +121,12 @@ public class GoalNode<T> {
return assignments; return assignments;
} }
/**
* @deprecated weigl: IMHO this method creates a lot of pain in analyses of goal nodes dependency.
* For example we can't guarant gn.getParent() == gn' for checking inheritance.
* Currently solved by id field.
* @return
*/
public GoalNode<T> deepCopy() { public GoalNode<T> deepCopy() {
if (parent != null) { if (parent != null) {
return new GoalNode<T>(id, parent.deepCopy(), data, isClosed); return new GoalNode<T>(id, parent.deepCopy(), data, isClosed);
......
package edu.kit.iti.formal.psdbg.gui.controls;
import javafx.application.Platform;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Alexander Weigl
* @version 1 (24.05.18)
*/
public class FileReloadingService extends TimerTask {
public static final Logger LOGGER = LogManager.getLogger(FileReloadingService.class);
public static final Logger CONSOLE_LOGGER = LogManager.getLogger(ScriptArea.class);
public Map<Path, FileChangedCallback> callbacks = new ConcurrentHashMap<Path, FileChangedCallback>();
public Map<Path, WatchKey> watchKeys = new ConcurrentHashMap<>();
public Map<WatchKey, Integer> watches = new ConcurrentHashMap<>();
private Timer timer;
@Nullable
private WatchService wService;
public FileReloadingService() {
try {
wService = FileSystems.getDefault().newWatchService();
timer = new Timer("filereloading", true);
timer.schedule(this, 500, 500);
} catch (IOException e) {
LOGGER.error(e);
CONSOLE_LOGGER.error("Auto-reloading is not available. See log file for more details");
}
}
public boolean addListener(File filePath, FileChangedCallback callback) {
if (wService == null && filePath != null) return false;
try {
Path toWatch = filePath.toPath().toAbsolutePath();
Path parent = toWatch.getParent();
if (!Files.exists(parent)) return false;
if (!watchKeys.containsKey(parent)) {
WatchKey watchKey = parent.register(wService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE);
watchKeys.put(parent, watchKey);
}
//increment used resource counter
watches.compute(watchKeys.get(parent), (k, v) -> (v == null) ? 1 : (v + 1));
//register listener
callbacks.put(toWatch, callback);
return true;
} catch (IOException e) {
CONSOLE_LOGGER.catching(e);
return false;
}
}
public void removeListener(File filePath) {
Path toWatch = filePath.toPath().toAbsolutePath();
Path parent = toWatch.getParent();
callbacks.remove(toWatch);
WatchKey wk = watchKeys.get(parent);
if (wk == null) return; // not registered before
watches.compute(wk, (k, v) -> v == 1 ? null : v - 1);
if (!watches.containsKey(wk)) {
wk.cancel();
watchKeys.remove(parent);
}
}
public void run() {
if (wService == null) return;
CONSOLE_LOGGER.info("Waiting for file changed events");
while (true) {
// wait for key to be signaled
WatchKey key;
try {
key = wService.take();
} catch (InterruptedException x) {
return;
}
Path dir = (Path) key.watchable();
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path filename = ev.context();
Path child = dir.resolve(filename).toAbsolutePath();
try {
String content = FileUtils.readFileToString(child.toFile(), Charset.defaultCharset());
CONSOLE_LOGGER.info("Auto-reload {}", child);
Platform.runLater(() -> callbacks.get(child).fileChanged(content));
} catch (IOException e) {
CONSOLE_LOGGER.catching(e);
}
}
boolean valid = key.reset();
//clean up dead keys
}
}
public interface FileChangedCallback {
void fileChanged(String newText);
}
}
...@@ -10,7 +10,6 @@ import edu.kit.iti.formal.psdbg.gui.actions.inline.InlineActionSupplier; ...@@ -10,7 +10,6 @@ import edu.kit.iti.formal.psdbg.gui.actions.inline.InlineActionSupplier;
import edu.kit.iti.formal.psdbg.gui.controller.Events; import edu.kit.iti.formal.psdbg.gui.controller.Events;
import edu.kit.iti.formal.psdbg.gui.model.MainScriptIdentifier; import edu.kit.iti.formal.psdbg.gui.model.MainScriptIdentifier;
import edu.kit.iti.formal.psdbg.interpreter.dbg.Breakpoint; import edu.kit.iti.formal.psdbg.interpreter.dbg.Breakpoint;
import edu.kit.iti.formal.psdbg.interpreter.dbg.DebuggerCommand;
import edu.kit.iti.formal.psdbg.lint.LintProblem; import edu.kit.iti.formal.psdbg.lint.LintProblem;
import edu.kit.iti.formal.psdbg.lint.LinterStrategy; import edu.kit.iti.formal.psdbg.lint.LinterStrategy;
import edu.kit.iti.formal.psdbg.parser.Facade; import edu.kit.iti.formal.psdbg.parser.Facade;
...@@ -66,8 +65,6 @@ import org.reactfx.collection.LiveList; ...@@ -66,8 +65,6 @@ import org.reactfx.collection.LiveList;
import org.reactfx.value.Val; import org.reactfx.value.Val;
import java.io.File; import java.io.File;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.time.Duration; import java.time.Duration;
import java.util.*; import java.util.*;
import java.util.function.IntFunction; import java.util.function.IntFunction;
...@@ -86,9 +83,12 @@ import static org.fxmisc.wellbehaved.event.InputMap.*; ...@@ -86,9 +83,12 @@ import static org.fxmisc.wellbehaved.event.InputMap.*;
*/ */
public class ScriptArea extends BorderPane { public class ScriptArea extends BorderPane {
public static final Logger LOGGER = LogManager.getLogger(ScriptArea.class); public static final Logger LOGGER = LogManager.getLogger(ScriptArea.class);
public static final Logger CONSOLE_LOGGER = LogManager.getLogger(ScriptArea.class);
public static final String EXECUTION_MARKER = "\u2316"; public static final String EXECUTION_MARKER = "\u2316";
public static final FileReloadingService FILE_RELOADING_SERVICE = new FileReloadingService();
/** /**
* Underlying filepath, should not be null * Underlying filepath, should not be null
*/ */
...@@ -100,7 +100,6 @@ public class ScriptArea extends BorderPane { ...@@ -100,7 +100,6 @@ public class ScriptArea extends BorderPane {
private final BooleanProperty dirty = new SimpleBooleanProperty(this, "dirty", false); private final BooleanProperty dirty = new SimpleBooleanProperty(this, "dirty", false);
/** /**
* CSS classes for regions, used for "manually" highlightning. e.g. debugging marker * CSS classes for regions, used for "manually" highlightning. e.g. debugging marker
*/ */
...@@ -243,6 +242,15 @@ public class ScriptArea extends BorderPane { ...@@ -243,6 +242,15 @@ public class ScriptArea extends BorderPane {
}); });
mainScript.addListener((observable) -> updateMainScriptMarker()); mainScript.addListener((observable) -> updateMainScriptMarker());
filePath.addListener((p, o, n) -> {
if (o != null)
FILE_RELOADING_SERVICE.removeListener(o);
if (n != null) {
FILE_RELOADING_SERVICE.addListener(n, s -> {
if (!isDirty()) setText(s);
});
}
});
} }
...@@ -421,6 +429,7 @@ public class ScriptArea extends BorderPane { ...@@ -421,6 +429,7 @@ public class ScriptArea extends BorderPane {
/** /**
* Set marker in gutter at the line of the Savepoint, which is loaded * Set marker in gutter at the line of the Savepoint, which is loaded
*
* @param lineNumber line in where the marker is to be set * @param lineNumber line in where the marker is to be set
*/ */
public void setSavepointMarker(int lineNumber) { public void setSavepointMarker(int lineNumber) {
...@@ -429,12 +438,11 @@ public class ScriptArea extends BorderPane { ...@@ -429,12 +438,11 @@ public class ScriptArea extends BorderPane {
} }
private void underline (int linenumber) { private void underline(int linenumber) {
} }
private boolean hasExecutionMarker() { private boolean hasExecutionMarker() {
return getText().contains(EXECUTION_MARKER); return getText().contains(EXECUTION_MARKER);
} }
...@@ -595,10 +603,11 @@ public class ScriptArea extends BorderPane { ...@@ -595,10 +603,11 @@ public class ScriptArea extends BorderPane {
public void setText(String text) { public void setText(String text) {
codeArea.clear(); codeArea.clear();
codeArea.insertText(0, text); codeArea.insertText(0, text);
setDirty(false);
} }
public void deleteText(int i, int length) { public void deleteText(int i, int length) {
codeArea.deleteText(i,length); codeArea.deleteText(i, length);
} }
private static class GutterView extends HBox { private static class GutterView extends HBox {
...@@ -752,13 +761,13 @@ public class ScriptArea extends BorderPane { ...@@ -752,13 +761,13 @@ public class ScriptArea extends BorderPane {
return savepoint.get(); return savepoint.get();
} }
public SimpleBooleanProperty savepointProperty() {
return savepoint;
}
public void setSavepoint(boolean savepoint) { public void setSavepoint(boolean savepoint) {
this.savepoint.set(savepoint); this.savepoint.set(savepoint);
} }
public SimpleBooleanProperty savepointProperty() {
return savepoint;
}
} }
public static class BreakpointDialog extends BorderPane { public static class BreakpointDialog extends BorderPane {
...@@ -829,7 +838,7 @@ public class ScriptArea extends BorderPane { ...@@ -829,7 +838,7 @@ public class ScriptArea extends BorderPane {
@Override @Override
public Node apply(int idx) { public Node apply(int idx) {
if(idx==-1) return new Label("idx is -1!"); //TODO weigl debug if (idx == -1) return new Label("idx is -1!"); //TODO weigl debug
Val<String> formatted = nParagraphs.map(n -> format(idx + 1, n)); Val<String> formatted = nParagraphs.map(n -> format(idx + 1, n));
GutterAnnotation model = getLineAnnotation(idx); GutterAnnotation model = getLineAnnotation(idx);
GutterView hbox = new GutterView(model); GutterView hbox = new GutterView(model);
...@@ -879,7 +888,7 @@ public class ScriptArea extends BorderPane { ...@@ -879,7 +888,7 @@ public class ScriptArea extends BorderPane {
LOGGER.debug("ScriptAreaContextMenu.setMainScript"); LOGGER.debug("ScriptAreaContextMenu.setMainScript");
// Check if script is saved // Check if script is saved
if(!filePath.getValue().isFile()) { if (!filePath.getValue().isFile()) {
Utils.showInfoDialog("Saving Script", "Save Script", "Script has to be saved first before it can be executed."); Utils.showInfoDialog("Saving Script", "Save Script", "Script has to be saved first before it can be executed.");
return; return;
} }
......
...@@ -10,10 +10,11 @@ import edu.kit.iti.formal.psdbg.gui.actions.inline.InlineActionSupplier; ...@@ -10,10 +10,11 @@ import edu.kit.iti.formal.psdbg.gui.actions.inline.InlineActionSupplier;
import edu.kit.iti.formal.psdbg.gui.controller.Events; import edu.kit.iti.formal.psdbg.gui.controller.Events;
import edu.kit.iti.formal.psdbg.gui.model.MainScriptIdentifier; import edu.kit.iti.formal.psdbg.gui.model.MainScriptIdentifier;
import edu.kit.iti.formal.psdbg.interpreter.data.SavePoint; import edu.kit.iti.formal.psdbg.interpreter.data.SavePoint;
import edu.kit.iti.formal.psdbg.interpreter.data.State;
import edu.kit.iti.formal.psdbg.interpreter.dbg.Breakpoint; import edu.kit.iti.formal.psdbg.interpreter.dbg.Breakpoint;
import edu.kit.iti.formal.psdbg.parser.Facade; import edu.kit.iti.formal.psdbg.parser.Facade;
import edu.kit.iti.formal.psdbg.parser.ast.*; import edu.kit.iti.formal.psdbg.parser.ast.ASTNode;
import edu.kit.iti.formal.psdbg.parser.ast.CallStatement;
import edu.kit.iti.formal.psdbg.parser.ast.ProofScript;
import javafx.beans.property.ListProperty; import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleListProperty;
...@@ -218,6 +219,9 @@ public class ScriptController { ...@@ -218,6 +219,9 @@ public class ScriptController {
} }
area.setText(code); area.setText(code);
} }
area.dirtyProperty().addListener(o -> updateTitle(dockNode, area));
area.filePathProperty().addListener(o -> updateTitle(dockNode, area));
return area; return area;
} else { } else {
logger.info("File already exists. Will not load it again"); logger.info("File already exists. Will not load it again");
...@@ -226,6 +230,13 @@ public class ScriptController { ...@@ -226,6 +230,13 @@ public class ScriptController {
} }
} }
private void updateTitle(DockNode dockNode, ScriptArea area) {
String title = area.getFilePath().getName();
if (area.isDirty())
title += "*";
dockNode.setTitle(title);
}
/* Create new DockNode for ScriptArea Tab /* Create new DockNode for ScriptArea Tab
* *
* @param area ScriptAreaTab * @param area ScriptAreaTab
...@@ -343,10 +354,6 @@ public class ScriptController { ...@@ -343,10 +354,6 @@ public class ScriptController {
return mainScript.get(); return mainScript.get();
} }
public void setMainScript(MainScriptIdentifier mainScript) {
this.mainScript.set(mainScript);
}
public void setMainScript(ProofScript proofScript) { public void setMainScript(ProofScript proofScript) {
MainScriptIdentifier msi = new MainScriptIdentifier(); MainScriptIdentifier msi = new MainScriptIdentifier();
msi.setLineNumber(proofScript.getStartPosition().getLineNumber()); msi.setLineNumber(proofScript.getStartPosition().getLineNumber());
...@@ -356,6 +363,10 @@ public class ScriptController { ...@@ -356,6 +363,10 @@ public class ScriptController {
setMainScript(msi); setMainScript(msi);
} }
public void setMainScript(MainScriptIdentifier mainScript) {
this.mainScript.set(mainScript);
}
public ObjectProperty<MainScriptIdentifier> mainScriptProperty() { public ObjectProperty<MainScriptIdentifier> mainScriptProperty() {
return mainScript; return mainScript;
} }
......
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