4747import java .util .Map ;
4848import java .util .Set ;
4949import java .util .UUID ;
50- import java .util .function .Function ;
5150import java .util .function .Predicate ;
5251
5352import org .graalvm .launcher .AbstractLanguageLauncher ;
@@ -801,9 +800,8 @@ protected void launch(Builder contextBuilder) {
801800 ConsoleHandler consoleHandler = createConsoleHandler (System .in , System .out );
802801 contextBuilder .arguments (getLanguageId (), programArgs .toArray (new String [programArgs .size ()]));
803802 contextBuilder .in (consoleHandler .createInputStream ());
804- contextBuilder .option ("python.TerminalIsInteractive" , Boolean .toString (isTTY ()));
805- contextBuilder .option ("python.TerminalWidth" , Integer .toString (consoleHandler .getTerminalWidth ()));
806- contextBuilder .option ("python.TerminalHeight" , Integer .toString (consoleHandler .getTerminalHeight ()));
803+ boolean tty = isTTY ();
804+ contextBuilder .option ("python.TerminalIsInteractive" , Boolean .toString (tty ));
807805
808806 contextBuilder .option ("python.CheckHashPycsMode" , checkHashPycsMode );
809807 contextBuilder .option ("python.RunViaLauncher" , "true" );
@@ -841,15 +839,20 @@ protected void launch(Builder contextBuilder) {
841839 evalInternal (context , "__graalpython__.startup_wall_clock_ts = " + startupWallClockTime + "; __graalpython__.startup_nano = " + startupNanoTime );
842840 }
843841
844- if (!quietFlag && (verboseFlag || (commandString == null && inputFile == null && isTTY ()))) {
845- print ("Python " + evalInternal (context , "import sys; sys.version + ' on ' + sys.platform" ).asString ());
842+ Value sysModule = evalInternal (context , "import sys; sys" );
843+ if (!quietFlag && (verboseFlag || (commandString == null && inputFile == null && tty ))) {
844+ print ("Python " + sysModule .getMember ("version" ).asString () + " on " + sysModule .getMember ("platform" ));
846845 if (!noSite ) {
847846 print ("Type \" help\" , \" copyright\" , \" credits\" or \" license\" for more information." );
848847 }
849848 }
850- consoleHandler .setContext (context );
851849
852- if (commandString != null || inputFile != null || !isTTY ()) {
850+ sysModule .putMember ("_console_handler" , consoleHandler );
851+ if (tty && !isolateFlag && (inspectFlag || (commandString == null && inputFile == null ))) {
852+ evalInternal (context , "import readline, rlcompleter" );
853+ }
854+
855+ if (commandString != null || inputFile != null || !tty ) {
853856 try {
854857 evalNonInteractive (context , consoleHandler );
855858 rc = 0 ;
@@ -865,7 +868,7 @@ protected void launch(Builder contextBuilder) {
865868 }
866869 if ((commandString == null && inputFile == null ) || inspectFlag ) {
867870 inspectFlag = false ;
868- rc = readEvalPrint (context , consoleHandler );
871+ rc = readEvalPrint (context , consoleHandler , sysModule );
869872 }
870873 } catch (RuntimeException e ) {
871874 if (e .getMessage () != null && e .getMessage ().contains ("did not complete all polyglot threads" )) {
@@ -878,7 +881,6 @@ protected void launch(Builder contextBuilder) {
878881 // brings up getaddrinfo which may just block in native for an arbitrary amount of
879882 // time and prevent us from shutting down the thread.
880883 if (!verboseFlag ) {
881- tryToResetConsoleHandler (consoleHandler );
882884 System .exit (rc );
883885 }
884886 } else {
@@ -887,20 +889,10 @@ protected void launch(Builder contextBuilder) {
887889 } catch (IOException e ) {
888890 rc = 1 ;
889891 e .printStackTrace ();
890- } finally {
891- tryToResetConsoleHandler (consoleHandler );
892892 }
893893 System .exit (rc );
894894 }
895895
896- private static void tryToResetConsoleHandler (ConsoleHandler consoleHandler ) {
897- try {
898- consoleHandler .setContext (null );
899- } catch (Throwable e ) {
900- // pass
901- }
902- }
903-
904896 private static boolean getBoolEnv (String var ) {
905897 return getEnv (var ) != null ;
906898 }
@@ -1083,10 +1075,6 @@ private static void printFileNotFoundException(NoSuchFileException e) {
10831075 }
10841076
10851077 private void evalNonInteractive (Context context , ConsoleHandler consoleHandler ) throws IOException {
1086- // We need to setup the terminal even when not running the REPL because code may request
1087- // input from the terminal.
1088- setupTerminal (consoleHandler );
1089-
10901078 Source src ;
10911079 if (commandString != null ) {
10921080 src = Source .newBuilder (getLanguageId (), commandString , "<string>" ).build ();
@@ -1189,7 +1177,7 @@ private static ConsoleHandler createConsoleHandler(InputStream inStream, OutputS
11891177 if (!isTTY ()) {
11901178 return new DefaultConsoleHandler (inStream );
11911179 } else {
1192- return new JLineConsoleHandler (inStream , outStream , false );
1180+ return new JLineConsoleHandler (inStream , outStream );
11931181 }
11941182 }
11951183
@@ -1203,19 +1191,24 @@ private static ConsoleHandler createConsoleHandler(InputStream inStream, OutputS
12031191 * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before
12041192 * exiting. So,in either case, we never return.
12051193 */
1206- private int readEvalPrint (Context context , ConsoleHandler consoleHandler ) {
1194+ private int readEvalPrint (Context context , ConsoleHandler consoleHandler , Value sysModule ) {
12071195 int lastStatus = 0 ;
12081196 try {
1209- setupREPL (context , consoleHandler );
1210- Value sys = evalInternal (context , "import sys; sys" );
1211- sys .putMember ("_console_handler" , consoleHandler );
1212-
1197+ Value hook = null ;
1198+ try {
1199+ hook = sysModule .getMember ("__interactivehook__" );
1200+ } catch (PolyglotException e ) {
1201+ // ignore
1202+ }
1203+ if (hook != null ) {
1204+ hook .execute ();
1205+ }
12131206 while (true ) { // processing inputs
12141207 boolean doEcho = doEcho (context );
1215- consoleHandler . setPrompt ( doEcho ? sys .getMember ("ps1" ).asString () : null ) ;
1208+ String ps1 = doEcho ? sysModule .getMember ("ps1" ).asString () : null ;
12161209
12171210 try {
1218- String input = consoleHandler .readLine ();
1211+ String input = consoleHandler .readLine (ps1 );
12191212 if (input == null ) {
12201213 throw new EOFException ();
12211214 }
@@ -1224,26 +1217,25 @@ private int readEvalPrint(Context context, ConsoleHandler consoleHandler) {
12241217 continue ;
12251218 }
12261219
1227- String continuePrompt = null ;
1220+ String ps2 = null ;
12281221 StringBuilder sb = new StringBuilder (input ).append ('\n' );
12291222 while (true ) { // processing subsequent lines while input is incomplete
12301223 lastStatus = 0 ;
12311224 try {
12321225 context .eval (Source .newBuilder (getLanguageId (), sb .toString (), "<stdin>" ).interactive (true ).buildLiteral ());
12331226 } catch (PolyglotException e ) {
1234- if (continuePrompt == null ) {
1235- continuePrompt = doEcho ? sys .getMember ("ps2" ).asString () : null ;
1227+ if (ps2 == null ) {
1228+ ps2 = doEcho ? sysModule .getMember ("ps2" ).asString () : null ;
12361229 }
12371230 if (e .isIncompleteSource ()) {
12381231 // read more input until we get an empty line
1239- consoleHandler .setPrompt (continuePrompt );
12401232 String additionalInput ;
12411233 boolean isIncompleteCode = false ; // this for cases like empty lines
12421234 // in tripplecode, where the
12431235 // additional input can be empty,
12441236 // but we should still continue
12451237 do {
1246- additionalInput = consoleHandler .readLine ();
1238+ additionalInput = consoleHandler .readLine (ps2 );
12471239 sb .append (additionalInput ).append ('\n' );
12481240 try {
12491241 // We try to parse every time, when an additional input is
@@ -1335,52 +1327,6 @@ private Value evalInternal(Context context, String code) {
13351327 return context .eval (Source .newBuilder (getLanguageId (), code , "<internal>" ).internal (true ).buildLiteral ());
13361328 }
13371329
1338- private void setupREPL (Context context , ConsoleHandler consoleHandler ) {
1339- // Then we can get the readline module and see if any completers were registered and use its
1340- // history feature
1341- evalInternal (context , "import sys\n getattr(sys, '__interactivehook__', lambda: None)()\n " );
1342- final Value readline = evalInternal (context , "import readline; readline" );
1343- final Value getCompleter = readline .getMember ("get_completer" ).execute ();
1344- final Value shouldRecord = readline .getMember ("get_auto_history" );
1345- final Value addHistory = readline .getMember ("add_history" );
1346- final Value getHistoryItem = readline .getMember ("get_history_item" );
1347- final Value setHistoryItem = readline .getMember ("replace_history_item" );
1348- final Value deleteHistoryItem = readline .getMember ("remove_history_item" );
1349- final Value clearHistory = readline .getMember ("clear_history" );
1350- final Value getHistorySize = readline .getMember ("get_current_history_length" );
1351-
1352- Function <String , List <String >> completer = null ;
1353- if (getCompleter .canExecute ()) {
1354- completer = (buffer ) -> {
1355- List <String > candidates = new ArrayList <>();
1356- Value candidate = getCompleter .execute (buffer , candidates .size ());
1357- while (candidate .isString ()) {
1358- candidates .add (candidate .asString ());
1359- candidate = getCompleter .execute (buffer , candidates .size ());
1360- }
1361- return candidates ;
1362- };
1363- }
1364- consoleHandler .setupReader (
1365- () -> shouldRecord .execute ().asBoolean (),
1366- () -> getHistorySize .execute ().asInt (),
1367- (item ) -> addHistory .execute (item ),
1368- (pos ) -> getHistoryItem .execute (pos ).asString (),
1369- (pos , item ) -> setHistoryItem .execute (pos , item ),
1370- (pos ) -> deleteHistoryItem .execute (pos ),
1371- () -> clearHistory .execute (),
1372- completer );
1373-
1374- }
1375-
1376- private static void setupTerminal (ConsoleHandler consoleHandler ) {
1377- consoleHandler .setupReader (() -> false , () -> 0 , (item ) -> {
1378- }, (pos ) -> null , (pos , item ) -> {
1379- }, (pos ) -> {
1380- }, () -> {
1381- }, null );
1382- }
1383-
13841330 /**
13851331 * Some system properties have already been read at this point, so to change them, we just
13861332 * re-execute the process with the additional options.
0 commit comments