Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to jline3 #2063

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
31cb437
Working on jline3
DavyLandman May 28, 2024
c67a197
Working on jline3
DavyLandman May 29, 2024
08ffabd
Working on jline3
DavyLandman May 30, 2024
b02f63f
Cleaning up pom to drop jline2 related dependencies
DavyLandman Oct 15, 2024
57b43d1
Removing InputStream and OutputStreams from the evaluator
DavyLandman Oct 15, 2024
61d4387
Rewriting away old parts of the jline2 code
DavyLandman Oct 15, 2024
94b9425
Rewrote TerminalProgressBarMonitor
DavyLandman Oct 15, 2024
1fd8348
Working on migrating to the new repl api
DavyLandman Oct 22, 2024
91998c1
Got the first working repl to do multiline
DavyLandman Oct 24, 2024
3aa2626
Got ctrl+c to work correctly
DavyLandman Oct 24, 2024
de6d79f
Added lines to the continuation prompt
DavyLandman Oct 24, 2024
38989b9
A bit more tweaking of the prompts
DavyLandman Oct 24, 2024
3145e2f
Added initial support for command completion
DavyLandman Nov 20, 2024
79bdf53
Added module completion support
DavyLandman Nov 21, 2024
27bf01f
Also added support for keywords and identifier completion
DavyLandman Nov 21, 2024
c0387b0
Support ctrl+c to interrupt a running rascal command
DavyLandman Nov 21, 2024
3d53007
Added location completion support
DavyLandman Nov 21, 2024
26d6052
Tuned completion a bit around locations and strings
DavyLandman Nov 25, 2024
922c61e
Fixed word lexer test
DavyLandman Nov 25, 2024
11a9103
Detect keywords and escape them in completions
DavyLandman Nov 25, 2024
4adaced
Updated todo list
DavyLandman Nov 25, 2024
2370802
Added queued command support
DavyLandman Nov 25, 2024
a58f57e
Added clear capability
DavyLandman Dec 17, 2024
0a911ac
Remove old implementation of REPL
DavyLandman Dec 17, 2024
43d4b65
Rewrote everything into output streams to reduce all the strings
DavyLandman Dec 18, 2024
d793d68
Working on support for the parametric repl and compiler
DavyLandman Dec 19, 2024
98c3e8b
Finished rewriting REPL framework to prepare for compiler and parametric
DavyLandman Dec 20, 2024
f498c27
Cleaning more old code and getting history to work correctly
DavyLandman Dec 20, 2024
712e848
Forgotten commit after rename
DavyLandman Dec 20, 2024
9f84a1a
Cleaning up old code
DavyLandman Dec 20, 2024
bcac0a1
Implemented TermREPL support
DavyLandman Dec 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Got the first working repl to do multiline
DavyLandman committed Oct 24, 2024

Verified

This commit was signed with the committer’s verified signature.
DavyLandman Davy Landman
commit 91998c13b2c52f61390861795cedb8e2bb1bc1b3
20 changes: 11 additions & 9 deletions src/org/rascalmpl/debug/IRascalMonitor.java
Original file line number Diff line number Diff line change
@@ -15,18 +15,21 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;


import org.jline.terminal.Terminal;
import org.jline.utils.InfoCmp.Capability;
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 {
/**
@@ -158,8 +161,8 @@ default void jobStep(String name, String message) {
* and otherwise default to a dumn terminal console progress logger.
* @return
*/
public static IRascalMonitor buildConsoleMonitor(InputStream in, OutputStream out) {
return buildConsoleMonitor(in, out, inBatchMode());
public static IRascalMonitor buildConsoleMonitor(Terminal term) {
return buildConsoleMonitor(term, inBatchMode());
}

public static boolean inBatchMode() {
@@ -168,12 +171,11 @@ public static boolean inBatchMode() {
;
}

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

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

8 changes: 6 additions & 2 deletions src/org/rascalmpl/interpreter/BatchProgressMonitor.java
Original file line number Diff line number Diff line change
@@ -24,11 +24,15 @@ public class BatchProgressMonitor implements IRascalMonitor {
PrintWriter out;

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

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

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

@Override
File renamed without changes.
153 changes: 153 additions & 0 deletions src/org/rascalmpl/repl/BaseREPL2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package org.rascalmpl.repl;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.UserInterruptException;
import org.jline.reader.LineReader.Option;
import org.jline.reader.impl.completer.AggregateCompleter;
import org.jline.reader.impl.history.DefaultHistory;
import org.jline.terminal.Terminal;
import org.jline.utils.ShutdownHooks;

public class BaseREPL2 {

private final IREPLService replService;
private final Terminal term;
private final LineReader reader;
private volatile boolean keepRunning = true;
private final @MonotonicNonNull DefaultHistory history;
private String currentPrompt;
private static final String FALLBACK_MIME_TYPE = "text/plain";
private static final String ANSI_MIME_TYPE = "text/x-ansi";
private final boolean ansiSupported;
private final String mimeType;

public BaseREPL2(IREPLService replService, Terminal term) {
this.replService = replService;
this.term = term;

var reader = LineReaderBuilder.builder()
.appName(replService.name())
.terminal(term)
.parser(replService.inputParser())
;

if (replService.storeHistory()) {
reader.variable(LineReader.HISTORY_FILE, replService.historyFile());
this.history = new DefaultHistory();
reader.history(this.history);
ShutdownHooks.add(this.history::save);
} else {
this.history = null;
}
reader.option(Option.HISTORY_IGNORE_DUPS, replService.historyIgnoreDuplicates());

if (replService.supportsCompletion()) {
reader.completer(new AggregateCompleter(replService.completers()));
}

switch (term.getType()) {
case Terminal.TYPE_DUMB:
this.ansiSupported = false;
this.mimeType = FALLBACK_MIME_TYPE;
break;
case Terminal.TYPE_DUMB_COLOR:
this.ansiSupported = false;
this.mimeType = ANSI_MIME_TYPE;
break;
default:
this.ansiSupported = true;
this.mimeType = ANSI_MIME_TYPE;
break;
}
this.currentPrompt = replService.prompt(ansiSupported);
reader.variable(LineReader.SECONDARY_PROMPT_PATTERN, replService.parseErrorPrompt(ansiSupported));

this.reader = reader.build();



// todo:
// - ctrl + c support
// - ctrl + / support
// - multi-line input
// - highlighting in the prompt?
// -

}

public void run() throws IOException {
try {
replService.connect(term);
while (keepRunning) {
String line = reader.readLine(this.currentPrompt);
if (line == null) {
// EOF
break;
}
try {
handleInput(line);
}
catch (UserInterruptException u) {
reader.printAbove("");
term.flush();
replService.handleReset(new HashMap<>(), new HashMap<>());
}
}
}
catch (InterruptedException _e) {
// closing the runner
}
catch (Throwable e) {

var err = replService.errorWriter();
if (err.checkError()) {
err = new PrintWriter(System.err, false);
}

err.println("Unexpected (uncaught) exception, closing the REPL: ");
err.print(e.toString());
e.printStackTrace(err);

err.flush();

throw e;
}
finally {
try {
replService.flush();
} catch (Throwable _t) { /* ignore */ }
term.flush();
if (this.history != null) {
ShutdownHooks.remove(this.history::save);
this.history.save();
}
}
}


private void handleInput(String line) throws InterruptedException {
var result = new HashMap<String, IOutputPrinter>();
var meta = new HashMap<String, String>();
replService.handleInput(line, result, meta);
writeResult(result);
}

private void writeResult(HashMap<String, IOutputPrinter> result) {
var writer = result.get(this.mimeType);
if (writer == null) {
writer = result.get(FALLBACK_MIME_TYPE);
}
if (writer == null) {
replService.outputWriter().println("Ok");
}
else {
writer.write(replService.outputWriter());
}
}
}
9 changes: 9 additions & 0 deletions src/org/rascalmpl/repl/IOutputPrinter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.rascalmpl.repl;

import java.io.PrintWriter;
import java.io.Reader;

public interface IOutputPrinter {
void write(PrintWriter target);
Reader asReader();
}
86 changes: 86 additions & 0 deletions src/org/rascalmpl/repl/IREPLService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.rascalmpl.repl;

import java.io.PrintWriter;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.jline.reader.Completer;
import org.jline.reader.Parser;
import org.jline.reader.impl.DefaultParser;
import org.jline.terminal.Terminal;

public interface IREPLService {

String MIME_PLAIN = "text/plain";
String MIME_ANSI = "text/x-ansi";

default boolean supportsCompletion() {
return false;
}

/**
* Supply completers for this REPL.
* Note that a completor is only triggered on a per word basis, so you might want to overwrite {@see #completionParser()}
*/
default List<Completer> completers() {
return Collections.emptyList();
}

/**
* This parser is respossible for multi-line support, as well as word splitting for completion.
*/
default Parser inputParser() {
return new DefaultParser();
}


default boolean storeHistory() {
return false;
}

default boolean historyIgnoreDuplicates() {
return true;
}

default Path historyFile() {
throw new IllegalAccessError("Not implemented if storeHistory is false");
}

/**
* Name of the REPL, no ansi allowed
*/
default String name() { return "Rascal REPL"; }


/**
* Check if an input is valid, for multi-line support
*/
boolean isInputComplete(String input);


// todo see if we really need the meta-data
void handleInput(String input, Map<String, IOutputPrinter> output, Map<String, String> metadata) throws InterruptedException;


// todo see if we really need the meta-data
void handleReset(Map<String, IOutputPrinter> output, Map<String, String> metadata) throws InterruptedException;

/**
* Default prompt
*/
String prompt(boolean ansiSupported);
/**
* Continuation prompt
*/
String parseErrorPrompt(boolean ansiSupported);

void connect(Terminal term);

PrintWriter errorWriter();
PrintWriter outputWriter();

void flush();

}
Loading