Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion lib/readline/version.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Readline
module Version
VERSION = "1.3.6"
VERSION = "1.3.7"
JLINE_VERSION = "2.14.6"
end
end
92 changes: 57 additions & 35 deletions src/main/java/org/jruby/ext/readline/Readline.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public class Readline {
}

public static final char ESC_KEY_CODE = (char) 27;

public static class ConsoleHolder {
public ConsoleReader readline;
transient volatile Completer currentCompletor;
Expand Down Expand Up @@ -116,26 +117,28 @@ public static void createReadline(final Ruby runtime) {

// We lazily initialize this in case Readline.readline has been overridden in ruby (s_readline)
protected static void initReadline(final Ruby runtime, final ConsoleHolder holder) {
final ConsoleReader readline;
final ConsoleReader reader;
try {
final Terminal terminal = TerminalFactory.create();
readline = holder.readline = new ConsoleReader(null, runtime.getInputStream(), runtime.getOutputStream(), terminal);
reader = new ConsoleReader("JRuby", runtime.getInputStream(), runtime.getOutputStream(), terminal);
holder.readline = reader;
} catch (IOException ioe) {
throw runtime.newIOErrorFromException(ioe);
}

readline.setHistoryEnabled(false);
readline.setPaginationEnabled(true);
readline.setBellEnabled(true);
reader.setHistoryEnabled(false);
reader.setPaginationEnabled(true);
reader.setBellEnabled(true);
reader.setHandleLitteralNext(false);

if (holder.currentCompletor == null) {
holder.currentCompletor = new RubyFileNameCompletor();
}
readline.addCompleter(holder.currentCompletor);
readline.setHistory(holder.history);
reader.addCompleter(holder.currentCompletor);
reader.setHistory(holder.history);

// JRUBY-852, ignore escape key (it causes IRB to quit if we pass it out through readline)
readline.addTriggeredAction(ESC_KEY_CODE, new ActionListener() {
reader.addTriggeredAction(ESC_KEY_CODE, new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
holder.readline.beep();
Expand All @@ -145,9 +148,9 @@ public void actionPerformed(ActionEvent e) {
}
});

RubyModule Readline = runtime.getModule("Readline");
RubyModule readline = runtime.getModule("Readline");
BlockCallback callback = new BlockCallback() {
public IRubyObject call(ThreadContext context, IRubyObject[] iRubyObjects, Block block) {
public IRubyObject call(ThreadContext context, IRubyObject[] args, Block block) {
LOG.debug("finalizing readline (console) backend");

try {
Expand All @@ -165,33 +168,43 @@ public IRubyObject call(ThreadContext context, IRubyObject[] iRubyObjects, Block
return context.nil;
}
};
Block block = CallBlock.newCallClosure(Readline, Readline, Signature.NO_ARGUMENTS, callback, runtime.getCurrentContext());
Readline.addFinalizer(RubyProc.newProc(runtime, block, block.type));
Block block = CallBlock.newCallClosure(readline, readline, Signature.NO_ARGUMENTS, callback, runtime.getCurrentContext());
readline.addFinalizer(RubyProc.newProc(runtime, block, block.type));
}

public static History getHistory(ConsoleHolder holder) {
return holder.history;
}

public static ConsoleHolder getHolder(Ruby runtime) {
return (ConsoleHolder) (runtime.getModule("Readline").dataGetStruct());
return getHolderImpl(runtime.getModule("Readline"));
}

private static ConsoleHolder getHolderImpl(final RubyModule readline) {
return (ConsoleHolder) readline.dataGetStruct();
}

public static ConsoleHolder getHolderWithReadline(Ruby runtime) {
ConsoleHolder holder = getHolder(runtime);
RubyModule readline = runtime.getModule("Readline");
ConsoleHolder holder = getHolderImpl(readline);
if (holder.readline == null) {
initReadline(runtime, holder);
synchronized (holder) {
if (holder.readline == null) {
initReadline(runtime, holder);
}
}
}
return holder;
}

public static void setCompletor(ConsoleHolder holder, Completer completor) {
if (holder.readline != null) {
holder.readline.removeCompleter(holder.currentCompletor);
final ConsoleReader reader = holder.readline;
if (reader != null) {
reader.removeCompleter(holder.currentCompletor);
}
holder.currentCompletor = completor;
if (holder.readline != null) {
holder.readline.addCompleter(holder.currentCompletor);
if (reader != null) {
reader.addCompleter(holder.currentCompletor);
}
}

Expand All @@ -217,24 +230,22 @@ public static IRubyObject readline(ThreadContext context, IRubyObject recv, IRub
private static IRubyObject readlineImpl(ThreadContext context, String prompt, final boolean addHistory) {
final Ruby runtime = context.runtime;
ConsoleHolder holder = getHolderWithReadline(runtime);
holder.readline.setExpandEvents(false);
final ConsoleReader reader = holder.readline;

reader.setExpandEvents(false);

String line;
while (true) {
try {
holder.readline.getTerminal().setEchoEnabled(false);
line = holder.readline.readLine(prompt);
break;
} catch (IOException ioe) {
throw runtime.newIOErrorFromException(ioe);
} finally {
holder.readline.getTerminal().setEchoEnabled(true);
}
try {
line = readlineLoop(reader, prompt);
} catch (IOException ex) {
throw runtime.newIOErrorFromException(ex);
} catch (Exception ex) {
Helpers.throwException(ex); return null; // likely init/restore failure
}

if (line == null) return context.nil;

if (addHistory) holder.readline.getHistory().add(line);
if (addHistory) reader.getHistory().add(line);

// Enebo: This is a little weird and a little broken. We just ask
// for the bytes and hope they match default_external. This will
Expand All @@ -247,6 +258,17 @@ private static IRubyObject readlineImpl(ThreadContext context, String prompt, fi
return RubyString.newString(runtime, bytes);
}

private static String readlineLoop(final ConsoleReader reader, final String prompt) throws Exception {
while (true) {
try {
reader.getTerminal().init();
return reader.readLine(prompt);
} finally {
reader.getTerminal().restore();
}
}
}

@JRubyMethod(name = "input=", module = true, visibility = PRIVATE)
public static IRubyObject setInput(ThreadContext context, IRubyObject recv, IRubyObject input) {
// FIXME: JRUBY-3604
Expand Down Expand Up @@ -296,10 +318,10 @@ public static IRubyObject s_set_completion_proc(IRubyObject recv, IRubyObject pr
public static IRubyObject s_get_screen_size(ThreadContext context, IRubyObject recv) {
Ruby runtime = context.runtime;
ConsoleHolder holder = getHolderWithReadline(runtime);
IRubyObject[] ary = new IRubyObject[2];
ary[0] = runtime.newFixnum(holder.readline.getTerminal().getHeight());
ary[1] = runtime.newFixnum(holder.readline.getTerminal().getWidth());
return RubyArray.newArray(runtime, ary);
final Terminal terminal = holder.readline.getTerminal();
IRubyObject h = runtime.newFixnum(terminal.getHeight());
IRubyObject w = runtime.newFixnum(terminal.getWidth());
return RubyArray.newArray(runtime, h, w);
}

@JRubyMethod(name = "set_screen_size", module = true, visibility = PRIVATE)
Expand Down