diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java index ac19422484151593412e9ea2407b5c1b6475f8cc..0e5040ee582fd8423eda42aeb596e77094ab5c8d 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java @@ -23,7 +23,9 @@ package com.oracle.truffle.r.engine.shell; import com.oracle.truffle.r.runtime.RInterfaceCallbacks; +import com.oracle.truffle.r.runtime.RStartParams; import com.oracle.truffle.r.runtime.context.ConsoleHandler; +import com.oracle.truffle.r.runtime.context.DefaultConsoleHandler; import com.oracle.truffle.r.runtime.ffi.REmbedRFFI; import com.oracle.truffle.r.runtime.ffi.RFFIFactory; @@ -31,26 +33,42 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory; * In embedded mode the console functions as defined in {@code Rinterface.h} can be overridden. This * class supports that, delegating to a standard console handler if not redirected. * + * N.B. At the time the constructor is created, we do not know if the console is overridden so we + * have be lazy about that. + * */ public class EmbeddedConsoleHandler implements ConsoleHandler { + private final RStartParams startParams; + /** + * Only not {@code null} when console is not overridden. + */ private ConsoleHandler delegate; private REmbedRFFI rEmbedRFFI; + private String prompt; - EmbeddedConsoleHandler(ConsoleHandler delegate) { - this.delegate = delegate; + EmbeddedConsoleHandler(RStartParams startParams) { + this.startParams = startParams; } private REmbedRFFI getREmbedRFFI() { if (rEmbedRFFI == null) { rEmbedRFFI = RFFIFactory.getRFFI().getREmbedRFFI(); + if (!(RInterfaceCallbacks.R_WriteConsole.isOverridden() || RInterfaceCallbacks.R_ReadConsole.isOverridden())) { + if (startParams.getNoReadline()) { + delegate = new DefaultConsoleHandler(System.in, System.out); + } else { + delegate = new JLineConsoleHandler(startParams); + } + } } return rEmbedRFFI; } @Override public void println(String s) { - if (RInterfaceCallbacks.R_WriteConsole.isOverridden()) { + getREmbedRFFI(); + if (delegate == null) { getREmbedRFFI().writeConsole(s); getREmbedRFFI().writeConsole("\n"); } else { @@ -61,8 +79,9 @@ public class EmbeddedConsoleHandler implements ConsoleHandler { @Override public void print(String s) { - if (RInterfaceCallbacks.R_WriteConsole.isOverridden()) { - getREmbedRFFI().writeConsole(s); + getREmbedRFFI(); + if (delegate == null) { + rEmbedRFFI.writeConsole(s); } else { delegate.print(s); } @@ -71,9 +90,10 @@ public class EmbeddedConsoleHandler implements ConsoleHandler { @Override public void printErrorln(String s) { - if (RInterfaceCallbacks.R_WriteConsole.isOverridden()) { - getREmbedRFFI().writeErrConsole(s); - getREmbedRFFI().writeErrConsole("\n"); + getREmbedRFFI(); + if (delegate == null) { + rEmbedRFFI.writeErrConsole(s); + rEmbedRFFI.writeErrConsole("\n"); } else { delegate.printErrorln(s); } @@ -82,8 +102,9 @@ public class EmbeddedConsoleHandler implements ConsoleHandler { @Override public void printError(String s) { - if (RInterfaceCallbacks.R_WriteConsole.isOverridden()) { - getREmbedRFFI().writeErrConsole(s); + getREmbedRFFI(); + if (delegate == null) { + rEmbedRFFI.writeErrConsole(s); } else { delegate.printError(s); } @@ -92,8 +113,9 @@ public class EmbeddedConsoleHandler implements ConsoleHandler { @Override public String readLine() { - if (RInterfaceCallbacks.R_ReadConsole.isOverridden()) { - return getREmbedRFFI().readConsole(delegate.getPrompt()); + getREmbedRFFI(); + if (delegate == null) { + return rEmbedRFFI.readConsole(prompt); } else { return delegate.readLine(); } @@ -101,28 +123,26 @@ public class EmbeddedConsoleHandler implements ConsoleHandler { @Override public boolean isInteractive() { - return delegate.isInteractive(); + return startParams.getInteractive(); } @Override public String getPrompt() { - return delegate.getPrompt(); + return prompt; } @Override public void setPrompt(String prompt) { - delegate.setPrompt(prompt); - - } + this.prompt = prompt; + if (delegate != null) { + delegate.setPrompt(prompt); + } - @Override - public int getWidth() { - return delegate.getWidth(); } @Override public String getInputDescription() { - return delegate.getInputDescription(); + return "<embedded input>"; } } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java index 3dca9591b06ab35ffaa1a8af64fc0bf1e73f400f..1f78b479c4aa03cfb1b2c0c0e475cd9349ff906b 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java @@ -28,9 +28,9 @@ import java.io.PrintWriter; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.RInternalSourceDescriptions; +import com.oracle.truffle.r.runtime.RStartParams; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.ConsoleHandler; -import com.oracle.truffle.r.runtime.context.RContext; import jline.console.ConsoleReader; import jline.console.UserInterruptException; @@ -42,10 +42,17 @@ class JLineConsoleHandler implements ConsoleHandler { private final boolean isInteractive; private final PrintWriter printWriter; - JLineConsoleHandler(boolean isInteractive, ConsoleReader console) { - this.console = console; + JLineConsoleHandler(RStartParams startParams) { + try { + console = new ConsoleReader(System.in, System.out); + console.setHandleUserInterrupt(true); + console.setExpandEvents(false); + } catch (IOException ex) { + throw Utils.fail("unexpected error opening console reader"); + } + // long start = System.currentTimeMillis(); printWriter = new PrintWriter(console.getOutput()); - this.isInteractive = isInteractive; + this.isInteractive = startParams.getInteractive(); } @Override @@ -108,11 +115,6 @@ class JLineConsoleHandler implements ConsoleHandler { console.setPrompt(prompt); } - @Override - public int getWidth() { - return RContext.CONSOLE_WIDTH; - } - @Override public String getInputDescription() { return RInternalSourceDescriptions.SHELL_INPUT; diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java index c0e4ab7be462292d853b6bf2a518a62d09b072ed..ee7e0b1aedda41b65891cb4b3a5bc8577e71819d 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java @@ -29,8 +29,6 @@ import java.io.Console; import java.io.EOFException; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.nio.file.Files; import java.util.List; @@ -58,7 +56,6 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind; import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RStringVector; -import jline.console.ConsoleReader; import jline.console.UserInterruptException; /** @@ -119,8 +116,6 @@ public class RCommand { * checked. */ ConsoleHandler consoleHandler; - InputStream consoleInput = System.in; - OutputStream consoleOutput = System.out; if (fileArg != null) { List<String> lines; String filePath; @@ -148,31 +143,25 @@ public class RCommand { * GnuR behavior differs from the manual entry for {@code interactive} in that {@code * --interactive} never applies to {@code -e/-f}, only to console input that has been * redirected from a pipe/file etc. + * + * If we are in embedded mode, the creation of ConsoleReader and the ConsoleHandler + * should be lazy, as these may not be necessary and can cause hangs if stdin has been + * redirected. */ Console sysConsole = System.console(); - boolean useReadLine = !rsp.getNoReadline(); - ConsoleReader consoleReader = null; - if (useReadLine) { - try { - consoleReader = new ConsoleReader(consoleInput, consoleOutput); - consoleReader.setHandleUserInterrupt(true); - consoleReader.setExpandEvents(false); - } catch (IOException ex) { - throw Utils.fail("unexpected error opening console reader"); - } - } boolean isInteractive = options.getBoolean(INTERACTIVE) || sysConsole != null; if (!isInteractive && rsp.getSaveAction() != SA_TYPE.SAVE && rsp.getSaveAction() != SA_TYPE.NOSAVE) { throw Utils.rSuicide("you must specify '--save', '--no-save' or '--vanilla'"); } - // long start = System.currentTimeMillis(); - if (useReadLine) { - consoleHandler = new JLineConsoleHandler(isInteractive, consoleReader); - } else { - consoleHandler = new DefaultConsoleHandler(consoleInput, consoleOutput); - } if (embedded) { - consoleHandler = new EmbeddedConsoleHandler(consoleHandler); + consoleHandler = new EmbeddedConsoleHandler(rsp); + } else { + boolean useReadLine = !rsp.getNoReadline(); + if (useReadLine) { + consoleHandler = new JLineConsoleHandler(rsp); + } else { + consoleHandler = new DefaultConsoleHandler(System.in, System.out); + } } } return ContextInfo.create(rsp, ContextKind.SHARE_NOTHING, null, consoleHandler).apply(PolyglotEngine.newBuilder()).build(); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java index 341d931b557617042d056209c20a990866a20d96..b109af35f29084be8fa77a41d8f27da46f0cf198 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java @@ -57,7 +57,7 @@ public abstract class Format extends RBuiltinNode { if (printConfig == null) { printConfig = new Config(); } - printConfig.width = RContext.getInstance().getConsoleHandler().getWidth(); + printConfig.width = (int) RContext.getInstance().stateROptions.getValue("width"); printConfig.naWidth = RRuntime.STRING_NA.length(); printConfig.naWidthNoQuote = RRuntime.NA_HEADER.length(); printConfig.digits = 7 /* default */; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java index 7d2ed0909aba8ea8ad62c789ba7a4dd89ed852e4..a2a7f8b73f94f5d27ff9000e7dbcd12dea93177b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java @@ -130,7 +130,7 @@ public class ROptions { map.put("verbose", RDataFactory.createLogicalVectorFromScalar(startParams.getVerbose())); map.put("nwarnings", RDataFactory.createIntVectorFromScalar(50)); map.put("warning.length", RDataFactory.createIntVectorFromScalar(1000)); - map.put("width", RDataFactory.createIntVectorFromScalar(80)); + map.put("width", RDataFactory.createIntVectorFromScalar(RContext.CONSOLE_WIDTH)); map.put("browserNLdisabled", RDataFactory.createLogicalVectorFromScalar(false)); boolean cBoundsCheck = optionFromEnvVar("R_C_BOUNDS_CHECK", envVars); map.put("CBoundsCheck", RDataFactory.createLogicalVectorFromScalar(cBoundsCheck)); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java index ab347547db7f780f485681e80130085479e6ca0c..f238108b70c6963f407b0fb1bcaaf09e6df6f49f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java @@ -95,12 +95,6 @@ public interface ConsoleHandler { @TruffleBoundary void setPrompt(String prompt); - /** - * Get the console width. - */ - @TruffleBoundary - int getWidth(); - String getInputDescription(); default void setHistoryFrom(@SuppressWarnings("unused") File file) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java index e7cd144b26891a3aaa4c7872024a40c8afd99f5e..18f2a36cceb1ed6df87252416c914869ebb2d624 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java @@ -87,11 +87,6 @@ public class DefaultConsoleHandler implements ConsoleHandler { this.prompt = prompt; } - @Override - public int getWidth() { - return 80; - } - @Override public String getInputDescription() { return "<PolyglotEngine env input>";