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> {
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.parent = parent;
this.data = data;
this.isClosed = isClosed;
}
private GoalNode(int id, GoalNode<T> tGoalNode, T data, boolean isClosed) {
this(tGoalNode, data, isClosed);
private GoalNode(int id, GoalNode<T> parent, T data, boolean isClosed) {
this(parent, data, isClosed);
this.id = id;
}
......@@ -121,6 +121,12 @@ public class GoalNode<T> {
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() {
if (parent != null) {
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;
import edu.kit.iti.formal.psdbg.gui.controller.Events;
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.DebuggerCommand;
import edu.kit.iti.formal.psdbg.lint.LintProblem;
import edu.kit.iti.formal.psdbg.lint.LinterStrategy;
import edu.kit.iti.formal.psdbg.parser.Facade;
......@@ -66,8 +65,6 @@ import org.reactfx.collection.LiveList;
import org.reactfx.value.Val;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.time.Duration;
import java.util.*;
import java.util.function.IntFunction;
......@@ -86,9 +83,12 @@ import static org.fxmisc.wellbehaved.event.InputMap.*;
*/
public class ScriptArea extends BorderPane {
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 FileReloadingService FILE_RELOADING_SERVICE = new FileReloadingService();
/**
* Underlying filepath, should not be null
*/
......@@ -100,7 +100,6 @@ public class ScriptArea extends BorderPane {
private final BooleanProperty dirty = new SimpleBooleanProperty(this, "dirty", false);
/**
* CSS classes for regions, used for "manually" highlightning. e.g. debugging marker
*/
......@@ -243,6 +242,15 @@ public class ScriptArea extends BorderPane {
});
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 {
/**
* Set marker in gutter at the line of the Savepoint, which is loaded
*
* @param lineNumber line in where the marker is to be set
*/
public void setSavepointMarker(int lineNumber) {
......@@ -429,12 +438,11 @@ public class ScriptArea extends BorderPane {
}
private void underline (int linenumber) {
private void underline(int linenumber) {
}
private boolean hasExecutionMarker() {
return getText().contains(EXECUTION_MARKER);
}
......@@ -595,10 +603,11 @@ public class ScriptArea extends BorderPane {
public void setText(String text) {
codeArea.clear();
codeArea.insertText(0, text);
setDirty(false);
}
public void deleteText(int i, int length) {
codeArea.deleteText(i,length);
codeArea.deleteText(i, length);
}
private static class GutterView extends HBox {
......@@ -752,13 +761,13 @@ public class ScriptArea extends BorderPane {
return savepoint.get();
}
public SimpleBooleanProperty savepointProperty() {
return savepoint;
}
public void setSavepoint(boolean savepoint) {
this.savepoint.set(savepoint);
}
public SimpleBooleanProperty savepointProperty() {
return savepoint;
}
}
public static class BreakpointDialog extends BorderPane {
......@@ -829,7 +838,7 @@ public class ScriptArea extends BorderPane {
@Override
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));
GutterAnnotation model = getLineAnnotation(idx);
GutterView hbox = new GutterView(model);
......@@ -879,7 +888,7 @@ public class ScriptArea extends BorderPane {
LOGGER.debug("ScriptAreaContextMenu.setMainScript");
// 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.");
return;
}
......
......@@ -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.model.MainScriptIdentifier;
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.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.ObjectProperty;
import javafx.beans.property.SimpleListProperty;
......@@ -218,6 +219,9 @@ public class ScriptController {
}
area.setText(code);
}
area.dirtyProperty().addListener(o -> updateTitle(dockNode, area));
area.filePathProperty().addListener(o -> updateTitle(dockNode, area));
return area;
} else {
logger.info("File already exists. Will not load it again");
......@@ -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
*
* @param area ScriptAreaTab
......@@ -343,10 +354,6 @@ public class ScriptController {
return mainScript.get();
}
public void setMainScript(MainScriptIdentifier mainScript) {
this.mainScript.set(mainScript);
}
public void setMainScript(ProofScript proofScript) {
MainScriptIdentifier msi = new MainScriptIdentifier();
msi.setLineNumber(proofScript.getStartPosition().getLineNumber());
......@@ -356,6 +363,10 @@ public class ScriptController {
setMainScript(msi);
}
public void setMainScript(MainScriptIdentifier mainScript) {
this.mainScript.set(mainScript);
}
public ObjectProperty<MainScriptIdentifier> mainScriptProperty() {
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