Skip to content

Commit 365316e

Browse files
committed
[GR-19220] Add pager support into Launcher (#2542)
PullRequest: truffleruby/3361
2 parents b8b1e7e + 67788c8 commit 365316e

File tree

4 files changed

+74
-19
lines changed

4 files changed

+74
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Compatibility:
3333
* Define `Process::{CLOCK_BOOTTIME,CLOCK_BOOTTIME_ALARM,CLOCK_REALTIME_ALARM}` (#1480, @eregon).
3434
* Improve support of `:chomp` keyword argument in `IO` and `StringIO` methods (#2650, @andrykonchin).
3535
* Implement specializations for immutable ruby objects for ObjectSpace methods (@bjfish).
36+
* Use `$PAGER` for `--help` and `--help*`, similar to CRuby (#2542, @Strech).
3637

3738
Performance:
3839

src/launcher/java/org/truffleruby/launcher/CommandLineParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,10 @@ private void processArgument() throws CommandLineException {
432432
disallowedInRubyOpts(argument);
433433
warnInternalDebugTool(argument);
434434
break FOR;
435-
} else if (rubyOpts && argument.equals("--help")) {
435+
} else if (argument.equals("--help")) {
436436
disallowedInRubyOpts(argument);
437+
// --help is handled by org.graalvm.launcher.Launcher#printDefaultHelp
438+
config.getUnknownArguments().add(argument);
437439
break FOR;
438440
} else if (argument.equals("--version")) {
439441
disallowedInRubyOpts(argument);

src/launcher/java/org/truffleruby/launcher/RubyLauncher.java

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
package org.truffleruby.launcher;
1111

1212
import java.io.PrintStream;
13+
import java.io.IOException;
1314
import java.util.ArrayList;
1415
import java.util.Arrays;
1516
import java.util.Collections;
1617
import java.util.List;
1718
import java.util.Map;
1819
import java.util.Set;
20+
import java.lang.ProcessBuilder.Redirect;
1921

2022
import org.graalvm.launcher.AbstractLanguageLauncher;
2123
import org.graalvm.nativeimage.ProcessProperties;
@@ -33,6 +35,7 @@ public class RubyLauncher extends AbstractLanguageLauncher {
3335

3436
private CommandLineOptions config;
3537
private String implementationName = null;
38+
private boolean helpOptionUsed = false; // Any --help* option
3639

3740
public static void main(String[] args) {
3841
new RubyLauncher().launch(args);
@@ -54,8 +57,8 @@ protected void validateArguments(Map<String, String> polyglotOptions) {
5457

5558
@Override
5659
protected void printVersion() {
57-
System.out.println(TruffleRuby.getVersionString(getImplementationNameFromEngine()));
58-
System.out.println();
60+
getOutput().println(TruffleRuby.getVersionString(getImplementationNameFromEngine()));
61+
getOutput().println();
5962
printPolyglotVersions();
6063
}
6164

@@ -109,9 +112,9 @@ protected List<String> preprocessArguments(List<String> args, Map<String, String
109112
}
110113

111114
} catch (CommandLineException commandLineException) {
112-
System.err.println("truffleruby: " + commandLineException.getMessage());
115+
getError().println("truffleruby: " + commandLineException.getMessage());
113116
if (commandLineException.isUsageError()) {
114-
printHelp(System.err);
117+
printHelp(getError());
115118
}
116119
System.exit(1);
117120
}
@@ -163,7 +166,7 @@ protected void collectArguments(Set<String> options) {
163166

164167
@Override
165168
protected void printHelp(OptionCategory maxCategory) {
166-
printHelp(System.out);
169+
printHelp(getOutput());
167170
}
168171

169172
@Override
@@ -173,6 +176,43 @@ protected AbortException abortUnrecognizedArgument(String argument) {
173176
"truffleruby: invalid option " + argument + " (Use --help for usage instructions.)");
174177
}
175178

179+
@Override
180+
protected boolean parseCommonOption(String defaultOptionPrefix, Map<String, String> polyglotOptions,
181+
boolean experimentalOptions, String arg) {
182+
if (arg.startsWith("--help")) {
183+
helpOptionUsed = true;
184+
}
185+
186+
return super.parseCommonOption(defaultOptionPrefix, polyglotOptions, experimentalOptions, arg);
187+
}
188+
189+
@Override
190+
protected boolean runLauncherAction() {
191+
String pager;
192+
if (helpOptionUsed && System.console() != null && !(pager = getPagerFromEnv()).isEmpty()) {
193+
try {
194+
Process process = new ProcessBuilder(pager.split(" "))
195+
.redirectOutput(Redirect.INHERIT) // set the output of the pager to the terminal and not a pipe
196+
.redirectError(Redirect.INHERIT) // set the error of the pager to the terminal and not a pipe
197+
.start();
198+
PrintStream out = new PrintStream(process.getOutputStream());
199+
200+
setOutput(out);
201+
boolean code = super.runLauncherAction();
202+
203+
out.flush();
204+
out.close();
205+
process.waitFor();
206+
207+
return code;
208+
} catch (IOException | InterruptedException e) {
209+
throw abort(e);
210+
}
211+
} else {
212+
return super.runLauncherAction();
213+
}
214+
}
215+
176216
private int runRubyMain(Context.Builder contextBuilder, CommandLineOptions config) {
177217
if (config.executionAction == ExecutionAction.UNSET) {
178218
switch (config.defaultExecutionAction) {
@@ -184,7 +224,7 @@ private int runRubyMain(Context.Builder contextBuilder, CommandLineOptions confi
184224
case IRB:
185225
config.executionAction = ExecutionAction.PATH;
186226
if (System.console() != null) {
187-
System.err.println(
227+
getError().println(
188228
"[ruby] WARNING: truffleruby starts IRB when stdin is a TTY instead of reading from stdin, use '-' to read from stdin");
189229
config.executionAction = ExecutionAction.PATH;
190230
config.toExecute = "irb";
@@ -203,7 +243,7 @@ private int runRubyMain(Context.Builder contextBuilder, CommandLineOptions confi
203243
// Apply options to run gem/bundle more efficiently
204244
contextBuilder.option("engine.Mode", "latency");
205245
if (Boolean.getBoolean("truffleruby.launcher.log")) {
206-
System.err.println("[ruby] CONFIG: detected gem or bundle command, using --engine.Mode=latency");
246+
getError().println("[ruby] CONFIG: detected gem or bundle command, using --engine.Mode=latency");
207247
}
208248
}
209249

@@ -241,7 +281,7 @@ private int runContext(Context.Builder builder, CommandLineOptions config) {
241281
if (file.isString()) {
242282
config.toExecute = file.asString();
243283
} else {
244-
System.err
284+
getError()
245285
.println("truffleruby: No such file or directory -- " + config.toExecute + " (LoadError)");
246286
return 1;
247287
}
@@ -270,9 +310,9 @@ private int runContext(Context.Builder builder, CommandLineOptions config) {
270310
return exitCode;
271311
} catch (PolyglotException e) {
272312
if (e.isHostException()) { // GR-22071
273-
System.err.println("truffleruby: a host exception reached the top level:");
313+
getError().println("truffleruby: a host exception reached the top level:");
274314
} else {
275-
System.err.println(
315+
getError().println(
276316
"truffleruby: an exception escaped out of the interpreter - this is an implementation bug");
277317
}
278318
e.printStackTrace();
@@ -299,24 +339,36 @@ private static List<String> getPathListFromEnvVariable(String name) {
299339
return Collections.emptyList();
300340
}
301341

342+
private static String getPagerFromEnv() {
343+
String pager = System.getenv("RUBY_PAGER");
344+
if (pager != null) {
345+
return pager.strip();
346+
}
347+
348+
pager = System.getenv("PAGER");
349+
if (pager != null) {
350+
return pager.strip();
351+
}
352+
353+
return "";
354+
}
355+
302356
private void printPreRunInformation(CommandLineOptions config) {
303357
if (config.showVersion) {
304-
System.out.println(TruffleRuby.getVersionString(getImplementationNameFromEngine()));
358+
getOutput().println(TruffleRuby.getVersionString(getImplementationNameFromEngine()));
305359
}
306360

307361
if (config.showCopyright) {
308-
System.out.println(TruffleRuby.RUBY_COPYRIGHT);
362+
getOutput().println(TruffleRuby.RUBY_COPYRIGHT);
309363
}
310364

311365
switch (config.showHelp) {
312366
case NONE:
313367
break;
314368
case SHORT:
315-
printShortHelp(System.out);
316-
break;
317-
case LONG:
318-
printHelp(System.out);
369+
printShortHelp(getOutput());
319370
break;
371+
// --help is handled by org.graalvm.launcher.Launcher#printDefaultHelp
320372
}
321373
}
322374

src/launcher/java/org/truffleruby/launcher/ShowHelp.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111

1212
public enum ShowHelp {
1313
NONE,
14-
SHORT,
15-
LONG
14+
SHORT // -h
15+
// LONG // --help is handled by org.graalvm.launcher.Launcher#printDefaultHelp
1616
}

0 commit comments

Comments
 (0)