Skip to content

Commit

Permalink
Merge branch 'main' into rainbow-progress-bar
Browse files Browse the repository at this point in the history
  • Loading branch information
jurgenvinju committed Jun 20, 2024
2 parents 55c7156 + f656c0a commit f71c695
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 86 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<exec.mainClass>org.rascalmpl.shell.RascalShell</exec.mainClass>
<rascal.test.memory>2</rascal.test.memory>
<maven.compiler.release>11</maven.compiler.release>
<rascal-maven.version>0.27.1-BOOT3</rascal-maven.version>
<rascal-maven.version>0.27.3</rascal-maven.version>
</properties>


Expand Down
23 changes: 16 additions & 7 deletions src/org/rascalmpl/debug/IRascalMonitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
import java.util.function.Function;
import java.util.function.Supplier;

import org.rascalmpl.interpreter.ConsoleRascalMonitor;
import org.rascalmpl.interpreter.BatchProgressMonitor;
import org.rascalmpl.interpreter.NullRascalMonitor;
import org.rascalmpl.repl.TerminalProgressBarMonitor;

import io.usethesource.vallang.ISourceLocation;
import jline.Terminal;
import jline.TerminalFactory;

public interface IRascalMonitor {
Expand Down Expand Up @@ -153,18 +154,26 @@ default void jobStep(String name, String message) {
public void warning(String message, ISourceLocation src);

/**
* Convenience method will produce a monitor with ANSI progress bars if possible,
* Convenience method will produce a monitor with ANSI progress bars if not in batch mode,
* and otherwise default to a dumn terminal console progress logger.
* @return
*/
public static IRascalMonitor buildConsoleMonitor(InputStream in, OutputStream out) {
return buildConsoleMonitor(in, out, System.console() != null);
return buildConsoleMonitor(in, out, inBatchMode());
}

public static IRascalMonitor buildConsoleMonitor(InputStream in, OutputStream out, boolean ansiEnabled) {
return ansiEnabled
? new TerminalProgressBarMonitor(out, in, TerminalFactory.get())
: new ConsoleRascalMonitor(new PrintStream(out))
public static boolean inBatchMode() {
return "true".equals(System.getenv("CI"))
|| System.getProperty("rascal.monitor.batch") != null
;
}

public static IRascalMonitor buildConsoleMonitor(InputStream in, OutputStream out, boolean batchMode) {
Terminal terminal = TerminalFactory.get();

return !batchMode && terminal.isAnsiSupported()
? new TerminalProgressBarMonitor(out, in, terminal)
: new BatchProgressMonitor(new PrintStream(out))
;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,31 @@

import io.usethesource.vallang.ISourceLocation;

public class ConsoleRascalMonitor implements IRascalMonitor {
public class BatchProgressMonitor implements IRascalMonitor {
PrintWriter out;

public ConsoleRascalMonitor() {
public BatchProgressMonitor() {
this.out = new PrintWriter(System.err);
}

public ConsoleRascalMonitor(PrintStream out) {
public BatchProgressMonitor(PrintStream out) {
this.out = new PrintWriter(out);
}

@Override
public int jobEnd(String name, boolean succeeded) {
out.println("\tJob done: " + name);
return 0;
}

@Override
public void jobStep(String name, String msg, int inc) {
out.println(name);
out.flush();
// not printing intermediate steps to keep the logs clean.
}

@Override
public void jobStart(String name, int workShare, int totalWork) {
out.println(name);
out.println("Job started: " + name);
out.flush();
}

Expand Down
43 changes: 8 additions & 35 deletions src/org/rascalmpl/library/Location.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ This conversion supports generic Unix path syntax, including:
loc locFromUnixPath(str path) = parseUnixPath(path);
@synopsis{Check that two locations refer to the same file.}
bool isSameFile(loc l, loc r) = l.top[fragment=""] == r.top[fragment=""];
@javaClass{org.rascalmpl.library.Prelude}
java bool isSameFile(loc l, loc r);
@synopsis{Compare two location values lexicographically.}
@description{
Expand Down Expand Up @@ -100,22 +101,8 @@ Strict containment between two locations `inner` and `outer` holds when
- both.
}
bool isStrictlyContainedIn(loc inner, loc outer){
if(inner == outer){
return false;
}
if(isSameFile(inner, outer)){
if(inner.offset?){
if(outer.offset?){
return inner.offset == outer.offset && inner.offset + inner.length < outer.offset + outer.length
|| inner.offset > outer.offset && inner.offset + inner.length <= outer.offset + outer.length;
} else {
return inner.offset > 0;
}
}
}
return false;
}
@javaClass{org.rascalmpl.library.Prelude}
java bool isStrictlyContainedIn(loc inner, loc outer);
@synopsis{Is a location textually contained in another location?}
Expand All @@ -127,20 +114,8 @@ Containment between two locations `inner` and `outer` holds when
- `inner` is strictly contained in `outer`.
}
bool isContainedIn(loc inner, loc outer){
if(isSameFile(inner, outer)){
if(inner.offset?){
if(outer.offset?){
return (inner.offset >= outer.offset && inner.offset + inner.length <= outer.offset + outer.length);
} else {
return true;
}
} else {
return !outer.offset?;
}
}
return false;
}
@javaClass{org.rascalmpl.library.Prelude}
java bool isContainedIn(loc inner, loc outer);
@synopsis{Begins a location's text before (but may overlap with) another location's text?}
Expand Down Expand Up @@ -184,10 +159,8 @@ bool isImmediatelyAfter(loc l, loc r)
@synopsis{Refer two locations to text that overlaps?}
bool isOverlapping(loc l, loc r)
= isSameFile(l, r) && ( (l.offset <= r.offset && l.offset + l.length > r.offset)
|| (r.offset <= l.offset && r.offset + r.length > l.offset)
);
@javaClass{org.rascalmpl.library.Prelude}
java bool isOverlapping(loc l, loc r);
@synopsis{Compute a location that textually covers the text of a list of locations.}
Expand Down
89 changes: 89 additions & 0 deletions src/org/rascalmpl/library/Prelude.java
Original file line number Diff line number Diff line change
Expand Up @@ -3972,5 +3972,94 @@ public void unwatch(ISourceLocation src, IBool recursive, IFunction callback) {
}


// this fact that this is just a java function helps the jitter with inline it
private static boolean isSameFilePure(ISourceLocation a, ISourceLocation b) {
a = a.top();
b = b.top();
if (!a.hasFragment() && !b.hasFragment()) {
// fast path: use equals of ISourceLocations
return a.equals(b);
}
// fallback, just compare everything except the fragment
return a.getScheme().equals(b.getScheme())
&& a.getAuthority().equals(b.getAuthority())
&& a.getPath().equals(b.getPath())
&& a.getQuery().equals(b.getQuery())
;
}

public IBool isSameFile(ISourceLocation a, ISourceLocation b) {
return values.bool(isSameFilePure(a, b));
}

public IBool isStrictlyContainedIn(ISourceLocation inner, ISourceLocation outer) {
if (!isSameFilePure(inner, outer)) {
return values.bool(false);
}
// original code would also do full equality, but we don't need that due to the logic in the outer &
// inner offset compares
if (inner.hasOffsetLength()) {
if (outer.hasOffsetLength()) {
int innerStart = inner.getOffset();
int innerEnd = innerStart + inner.getLength();
int outerStart = outer.getOffset();
int outerEnd = outerStart + outer.getLength();

return values.bool(
(innerStart == outerStart && innerEnd < outerEnd)
|| (innerStart > outerStart && innerEnd <= outerEnd)
);
}
else {
return values.bool(inner.getLength() > 0);
}
}
return values.bool(false);
}

public IBool isContainedIn(ISourceLocation inner, ISourceLocation outer) {
if (!isSameFilePure(inner, outer)) {
return values.bool(false);
}
if (inner.hasOffsetLength()) {
if (outer.hasOffsetLength()) {
int innerStart = inner.getOffset();
int innerEnd = innerStart + inner.getLength();
int outerStart = outer.getOffset();
int outerEnd = outerStart + outer.getLength();

return values.bool(
outerStart <= innerStart && innerEnd <= outerEnd
);
}
return values.bool(true);
}

return values.bool(!outer.hasOffsetLength());
}

public IBool isOverlapping(ISourceLocation first, ISourceLocation second) {
if (!isSameFilePure(first, second)) {
return values.bool(false);
}
if (first.hasOffsetLength()) {
if (second.hasOffsetLength()) {
int firstStart = first.getOffset();
int firstEnd = firstStart + first.getLength();
int secondStart = second.getOffset();
int secondEnd = secondStart + second.getLength();

return values.bool(
(firstStart <= secondStart && secondStart <= firstEnd)
|| (secondStart <= firstStart && firstStart <= secondEnd)
);

}
}
return values.bool(true);

}


}

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ str getParserMethodName(conditional(Symbol s, _)) = getParserMethodName(s);
default str getParserMethodName(Symbol s) = value2id(s);

public str newGenerate(str package, str name, Grammar gr) {
return job("Generating <name>", str (void (str m, int w) worked) {
return job("Generating parser; <for (st <- gr.rules, st is sort || st is lex) {><type(st,())> <}>"[..-1], str (void (str m, int w) worked) {
int uniqueItem = 1; // -1 and -2 are reserved by the SGTDBF implementation
int newItem() { uniqueItem += 1; return uniqueItem; };
Expand Down
24 changes: 24 additions & 0 deletions src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,30 @@ test bool isContainedIn2(int f, int len){
return report(l1, l2, !isContainedIn(l2, l1));
}
// isStrictlyContainedIn
test bool isStrictlyContainedIn1(int f, int len) {
f1 = restrict(f); t1 = restrict(f1 + len);
len1 = t1 - f1;
delta = (t1-f1)/2;
l1 = getLoc(f1, t1); l2 = getLoc(f1 + delta, t1 - delta);
return report(l1, l2, delta > 0 ==> isStrictlyContainedIn(l2, l1));
}
test bool isStrictlyContainedIn2(int f, int len) {
f1 = restrict(f); t1 = restrict(f1 + len);
len1 = t1 - f1;
delta = (t1-f1)/2;
l1 = getLoc(f1, t1); l2 = getLoc(f1, t1 - delta);
return report(l1, l2, delta > 0 ==> isStrictlyContainedIn(l2, l1));
}
test bool isStrictlyContainedIn3(int f, int len) {
f1 = restrict(f); t1 = restrict(f1 + len);
l1 = getLoc(f1, t1);
return report(l1, l1, !isStrictlyContainedIn(l1, l1));
}
// beginsBefore
@ignore{unknown}
Expand Down
26 changes: 16 additions & 10 deletions src/org/rascalmpl/repl/TerminalProgressBarMonitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public TerminalProgressBarMonitor(OutputStream out, InputStream in, Terminal tm)
this.writer = debug ? new PrintWriter(new AlwaysFlushAlwaysShowCursor(theWriter)) : theWriter;
this.lineWidth = tm.getWidth();
this.unicodeEnabled = ANSI.isUTF8enabled(theWriter, in);

assert tm.isSupported() && tm.isAnsiSupported(): "interactive progress bar needs a working ANSI terminal";
assert out.getClass() != TerminalProgressBarMonitor.class : "accidentally wrapping the wrapper.";
}
Expand Down Expand Up @@ -518,16 +518,12 @@ static String showCursor() {
* Simply print the bars. No cursor movement here. Hiding the cursor prevents flickering.
*/
private void printBars() {
if (bars.isEmpty()) {
// no more bars to show, so cursor goes back.
writer.write(ANSI.showCursor());
}

for (var pb : bars) {
pb.write();
}

writer.flush();

}

/**
Expand Down Expand Up @@ -557,8 +553,6 @@ public synchronized void jobStart(String name, int workShare, int totalWork) {
if (bars.size() == 0) {
// first new job, we take time to react to window resizing
lineWidth = tm.getWidth();
// remove the cursor
writer.write(ANSI.hideCursor());
}

if (totalWork == 0) {
Expand All @@ -569,33 +563,43 @@ public synchronized void jobStart(String name, int workShare, int totalWork) {

var pb = findBarByName(name);

if (pb == null) {
writer.write(ANSI.hideCursor());

if (pb == null) {
eraseBars(); // to make room for the new bars
bars.add(new ProgressBar(name, totalWork));
printBars(); // probably one line longer than before!
printBars(); // probably one line longer than before!
}
else {
// Zeno-bar: we add the new work to the already existing work
pb.max += totalWork;
pb.nesting++;
pb.update();
}

writer.write(ANSI.showCursor());
writer.flush();
}

@Override
public synchronized void jobStep(String name, String message, int workShare) {
ProgressBar pb = findBarByName(name);

if (pb != null) {
writer.write(ANSI.hideCursor());
pb.worked(workShare, message);
pb.update();
writer.write(ANSI.showCursor());
writer.flush();
}
}

@Override
public synchronized int jobEnd(String name, boolean succeeded) {
var pb = findBarByName(name);

writer.write(ANSI.hideCursor());

if (pb != null && --pb.nesting == -1) {
eraseBars();
// write it one last time into the scrollback buffer (on top)
Expand All @@ -611,6 +615,8 @@ else if (pb != null) {
pb.update();
}

writer.write(ANSI.showCursor());

return -1;
}

Expand Down
Loading

0 comments on commit f71c695

Please sign in to comment.