11package org .rascalmpl .tutor .lang .rascal .tutor .repl ;
22
3- import java .io .BufferedInputStream ;
4- import java .io .ByteArrayInputStream ;
53import java .io .ByteArrayOutputStream ;
64import java .io .File ;
75import java .io .IOException ;
86import java .io .InputStream ;
9- import java .io .InputStreamReader ;
107import java .io .OutputStream ;
11- import java .io .UnsupportedEncodingException ;
8+ import java .io .PrintWriter ;
9+ import java .io .Reader ;
10+ import java .io .StringWriter ;
1211import java .lang .reflect .InvocationTargetException ;
1312import java .net .URISyntaxException ;
1413import java .nio .charset .StandardCharsets ;
1514import java .nio .file .Paths ;
16- import java .util .Arrays ;
1715import java .util .Base64 ;
1816import java .util .HashMap ;
1917import java .util .Map ;
18+
19+ import org .jline .terminal .Terminal ;
20+ import org .jline .terminal .TerminalBuilder ;
21+ import org .rascalmpl .debug .IRascalMonitor ;
2022import org .rascalmpl .ideservices .IDEServices ;
2123import org .rascalmpl .interpreter .Evaluator ;
22- import org .rascalmpl .interpreter .env .GlobalEnvironment ;
23- import org .rascalmpl .interpreter .env .ModuleEnvironment ;
24- import org .rascalmpl .interpreter .load .StandardLibraryContributor ;
2524import org .rascalmpl .interpreter .utils .RascalManifest ;
26- import org .rascalmpl .library . Prelude ;
25+ import org .rascalmpl .interpreter . utils . ReadEvalPrintDialogMessages ;
2726import org .rascalmpl .library .util .PathConfig ;
28- import org .rascalmpl .repl .RascalInterpreterREPL ;
27+ import org .rascalmpl .parser .gtd .exception .ParseError ;
28+ import org .rascalmpl .repl .StopREPLException ;
29+ import org .rascalmpl .repl .output .IBinaryOutputPrinter ;
30+ import org .rascalmpl .repl .output .IErrorCommandOutput ;
31+ import org .rascalmpl .repl .output .IImageCommandOutput ;
32+ import org .rascalmpl .repl .output .IWebContentOutput ;
33+ import org .rascalmpl .repl .rascal .RascalInterpreterREPL ;
2934import org .rascalmpl .shell .ShellEvaluatorFactory ;
3035import org .rascalmpl .uri .URIResolverRegistry ;
3136import org .rascalmpl .uri .URIUtil ;
3237import org .rascalmpl .uri .classloaders .SourceLocationClassLoader ;
3338import org .rascalmpl .uri .project .ProjectURIResolver ;
3439import org .rascalmpl .uri .project .TargetURIResolver ;
35- import org .rascalmpl .values .ValueFactoryFactory ;
3640
3741import io .usethesource .vallang .IList ;
3842import io .usethesource .vallang .ISourceLocation ;
3943import io .usethesource .vallang .IValue ;
40- import io .usethesource .vallang .IValueFactory ;
44+ import io .usethesource .vallang .io . StandardTextWriter ;
4145
4246public class TutorCommandExecutor {
43- private final RascalInterpreterREPL repl ;
44- private final ByteArrayOutputStream shellStandardOutput ;
45- private final ByteArrayOutputStream shellErrorOutput ;
47+ private final RascalInterpreterREPL interpreter ;
48+ private final StringWriter outWriter = new StringWriter ();
49+ private final PrintWriter outPrinter = new PrintWriter (outWriter );
50+ private final StringWriter errWriter = new StringWriter ();
51+ private final PrintWriter errPrinter = new PrintWriter (errWriter , true );
4652 private final ITutorScreenshotFeature screenshot ;
4753
4854 public TutorCommandExecutor (PathConfig pcfg ) throws IOException , URISyntaxException {
49- shellStandardOutput = new ByteArrayOutputStream ();
50- shellErrorOutput = new ByteArrayOutputStream ();
51- ByteArrayInputStream shellInputNotUsed = new ByteArrayInputStream ("***this inputstream should not be used***" .getBytes ());
52- repl = new RascalInterpreterREPL (false , false , null ) {
55+ interpreter = new RascalInterpreterREPL () {
5356 @ Override
54- protected Evaluator constructEvaluator (InputStream input , OutputStream stdout , OutputStream stderr , IDEServices services ) {
55- GlobalEnvironment heap = new GlobalEnvironment ();
56- ModuleEnvironment root = heap .addModule (new ModuleEnvironment (ModuleEnvironment .SHELL_MODULE , heap ));
57- IValueFactory vf = ValueFactoryFactory .getValueFactory ();
58- Evaluator eval = new Evaluator (vf , input , stderr , stdout , root , heap , services );
59-
60- eval .addRascalSearchPathContributor (StandardLibraryContributor .getInstance ());
61- eval .setMonitor (services );
57+ protected Evaluator buildEvaluator (Reader input , PrintWriter stdout , PrintWriter stderr ,
58+ IDEServices services ) {
59+ var eval = super .buildEvaluator (input , stdout , stderr , services );
6260 eval .getConfiguration ().setRascalJavaClassPathProperty (javaCompilerPathAsString (pcfg .getJavaCompilerPath ()));
63- eval .setMonitor (services );
6461
6562 ISourceLocation projectRoot = inferProjectRoot ((ISourceLocation ) pcfg .getSrcs ().get (0 ));
6663 String projectName = new RascalManifest ().getProjectName (projectRoot );
@@ -81,13 +78,26 @@ protected Evaluator constructEvaluator(InputStream input, OutputStream stdout, O
8178
8279 return eval ;
8380 }
81+
82+ @ Override
83+ protected IDEServices buildIDEService (PrintWriter err , IRascalMonitor monitor , Terminal term ) {
84+ return (monitor instanceof IDEServices ) ? (IDEServices )monitor : new TutorIDEServices (err );
85+ }
86+
8487 };
8588
86- TutorIDEServices services = new TutorIDEServices ();
87- repl .initialize (shellInputNotUsed , shellStandardOutput , shellErrorOutput , services );
88- repl .setMeasureCommandTime (false );
89-
90- this .screenshot = loadScreenShotter ();
89+ var terminal = TerminalBuilder .builder ()
90+ .system (false )
91+ .streams (InputStream .nullInputStream (), OutputStream .nullOutputStream ())
92+ .dumb (true )
93+ .color (false )
94+ .encoding (StandardCharsets .UTF_8 )
95+ .build ();
96+
97+
98+
99+ interpreter .initialize (Reader .nullReader (), outPrinter , errPrinter , new TutorIDEServices (errPrinter ), terminal );
100+ screenshot = loadScreenShotter ();
91101 }
92102
93103 private ITutorScreenshotFeature loadScreenShotter () {
@@ -97,14 +107,14 @@ private ITutorScreenshotFeature loadScreenShotter() {
97107 .loadClass ("org.rascalmpl.tutor.Screenshotter" )
98108 .getDeclaredConstructor ()
99109 .newInstance ();
100- }
110+ }
101111 catch (ClassNotFoundException e ) {
102112 // that is normal; we just don't have the feature available.
103113 return null ;
104114 }
105- catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e ) {
106- throw new Error ("WARNING: Could not load screenshot feature from org.rascalmpl.tutor.Screenshotter" , e );
107- }
115+ catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e ) {
116+ throw new Error ("WARNING: Could not load screenshot feature from org.rascalmpl.tutor.Screenshotter" , e );
117+ }
108118 }
109119
110120 private static ISourceLocation inferProjectRoot (ISourceLocation member ) {
@@ -148,112 +158,83 @@ private String javaCompilerPathAsString(IList javaCompilerPath) {
148158 return b .toString ();
149159 }
150160
151-
152- public void reset () {
153- try {
154- // make sure previously unterminated commands are cleared up
155- repl .handleInput ("" , new HashMap <>(), new HashMap <>());
156- }
157- catch (InterruptedException e ) {
158- // nothing needed
159- }
160- repl .cleanEnvironment ();
161- shellStandardOutput .reset ();
162- shellErrorOutput .reset ();
163- }
164161
165- public String getPrompt () {
166- return repl .getPrompt ();
162+ public void reset () {
163+ interpreter .cancelRunningCommandRequested ();
164+ interpreter .cleanEnvironment ();
165+ outPrinter .flush ();
166+ outWriter .getBuffer ().setLength (0 );
167+ errPrinter .flush ();
168+ errWriter .getBuffer ().setLength (0 );
167169 }
168170
169171 public Map <String , String > eval (String line ) throws InterruptedException , IOException {
170- Map <String , InputStream > output = new HashMap <>();
171172 Map <String , String > result = new HashMap <>();
172- Map <String , String > metadata = new HashMap <>();
173-
174- repl .handleInput (line , output , metadata );
175-
176- for (String mimeType : output .keySet ()) {
177- InputStream content = output .get (mimeType );
178-
179- if (mimeType .startsWith ("text/plain" )) {
180- result .put (mimeType , Prelude .consumeInputStream (new InputStreamReader (content , StandardCharsets .UTF_8 )));
173+ try {
174+ var replResult = interpreter .handleInput (line );
175+ if (replResult instanceof IErrorCommandOutput ) {
176+ ((IErrorCommandOutput )replResult ).asPlain ().write (errPrinter , true );
181177 }
182- else {
183- result .put (mimeType , uuencode (content ));
178+ else if (replResult instanceof IImageCommandOutput ) {
179+ var img = ((IImageCommandOutput )replResult ).asImage ();
180+ result .put (img .mimeType (), uuencode (img ));
184181 }
185-
186- if ( metadata . get ( "url" ) != null && screenshot != null ) {
182+ else if ( replResult instanceof IWebContentOutput ) {
183+ var webResult = ( IWebContentOutput ) replResult ;
187184 try {
188- // load the page
189- String pngImage = screenshot .takeScreenshotAsBase64PNG (metadata .get ("url" ));
185+ String pngImage = screenshot .takeScreenshotAsBase64PNG (webResult .webUri ().toASCIIString ());
190186
191187 if (!pngImage .isEmpty ()) {
192188 result .put ("application/rascal+screenshot" , pngImage );
193189 }
194-
195190 }
196191 catch (Throwable e ) {
197- shellErrorOutput .write (e .getMessage (). getBytes ( "UTF-8" ));
192+ errPrinter .write (e .getMessage ());
198193 }
199- }
200- }
201-
202- result .put ("application/rascal+stdout" , getPrintedOutput ());
203- result .put ("application/rascal+stderr" , getErrorOutput ());
204-
205- return result ;
206- }
207-
208- public String uuencode (InputStream content ) throws IOException {
209- int BUFFER_SIZE = 3 * 512 ;
210- Base64 .Encoder encoder = Base64 .getEncoder ();
211-
212- try (BufferedInputStream in = new BufferedInputStream (content , BUFFER_SIZE ); ) {
213- StringBuilder result = new StringBuilder ();
214- byte [] chunk = new byte [BUFFER_SIZE ];
215- int len = 0 ;
216-
217- // read multiples of 3 until not possible anymore
218- while ( (len = in .read (chunk )) == BUFFER_SIZE ) {
219- result .append ( encoder .encodeToString (chunk ) );
220194 }
221-
222- // read final chunk which is not a multiple of 3
223- if ( len > 0 ) {
224- chunk = Arrays .copyOf (chunk ,len );
225- result .append ( encoder .encodeToString (chunk ) );
195+ // we ignore IAnsiCommandOutput, as we know that we cannot render that.
196+ // else if (replResult instanceof IAnsiCommandOutput) {}
197+ else if (replResult != null ) {
198+ var txt = new StringWriter ();
199+ var txtPrinter = new PrintWriter (txt , false );
200+ replResult .asPlain ().write (txtPrinter , true );
201+ txtPrinter .flush ();
202+ result .put ("text/plain" , txt .toString ());
226203 }
227-
228- return result .toString ();
204+ else {
205+ result .put ("text/plain" , "ok\n " );
206+ }
207+ } catch (ParseError pe ) {
208+ ReadEvalPrintDialogMessages .parseErrorMessage (errPrinter , line , interpreter .promptRootLocation ().getScheme (), pe , new StandardTextWriter (true ));
209+ }
210+ catch (StopREPLException e1 ) {
211+ errWriter .write ("Quiting REPL" );
212+ } finally {
213+ result .put ("application/rascal+stdout" , getPrintedOutput ());
214+ result .put ("application/rascal+stderr" , getErrorOutput ());
229215 }
216+ return result ;
230217 }
231218
232- public boolean isStatementComplete (String line ){
233- return repl .isStatementComplete (line );
219+ private String uuencode (IBinaryOutputPrinter content ) throws IOException {
220+ var result = new ByteArrayOutputStream ();
221+ try (var wrapped = Base64 .getEncoder ().wrap (result )) {
222+ content .write (wrapped );
223+ }
224+ return result .toString (StandardCharsets .ISO_8859_1 ); // help java recognize the compact strings can be used
234225 }
235226
236- private String getPrintedOutput () throws UnsupportedEncodingException {
237- try {
238- repl .getOutputWriter ().flush ();
239- String result = shellStandardOutput .toString (StandardCharsets .UTF_8 .name ());
240- shellStandardOutput .reset ();
241- return result ;
242- }
243- catch (UnsupportedEncodingException e ) {
244- return "" ;
245- }
227+ private String getPrintedOutput (){
228+ outPrinter .flush ();
229+ String result = outWriter .toString ();
230+ outWriter .getBuffer ().setLength (0 );
231+ return result ;
246232 }
247233
248234 private String getErrorOutput () {
249- try {
250- repl .getErrorWriter ().flush ();
251- String result = shellErrorOutput .toString (StandardCharsets .UTF_8 .name ());
252- shellErrorOutput .reset ();
253- return result ;
254- }
255- catch (UnsupportedEncodingException e ) {
256- return "" ;
257- }
235+ errPrinter .flush ();
236+ String result = errWriter .toString ();
237+ errWriter .getBuffer ().setLength (0 );
238+ return result ;
258239 }
259240}
0 commit comments