Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 73fd040ed314
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5ce8d92bcb4f
Choose a head ref
  • 11 commits
  • 4 files changed
  • 1 contributor

Commits on May 23, 2016

  1. Copy the full SHA
    0502d3e View commit details
  2. Copy the full SHA
    49b6ac7 View commit details
  3. Copy the full SHA
    59d5a6a View commit details
  4. Copy the full SHA
    2ce903d View commit details
  5. [Truffle] Partially implemented Readline.delete_text.

    The full form of this method takes an offset and length, but it's not clear that JLine supports this.
    nirvdrum committed May 23, 2016
    Copy the full SHA
    70cfb2a View commit details
  6. Copy the full SHA
    4ad4426 View commit details
  7. Copy the full SHA
    d31fa15 View commit details
  8. Copy the full SHA
    86e692e View commit details
  9. Copy the full SHA
    f9a9a39 View commit details
  10. Copy the full SHA
    5d6000a View commit details
  11. [Truffle] Removed JRuby-based proc completion for Readline.

    Note that we don't currently support this in JRuby+Truffle, but I've retained the structure to make porting easier in the future.
    nirvdrum committed May 23, 2016
    Copy the full SHA
    5ce8d92 View commit details
12 changes: 12 additions & 0 deletions lib/ruby/truffle/truffle/readline.rb
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
module Readline

HISTORY = Object.new
VERSION = 'JLine wrapper'

module_function

@@ -22,11 +23,22 @@ module Readline
completer_word_break_characters
completer_word_break_characters=
completion_append_character
completion_append_character=
completion_case_fold
completion_case_fold=
completion_proc
completion_proc=
emacs_editing_mode
emacs_editing_mode?
filename_quote_characters
filename_quote_characters=
point=
pre_input_hook
pre_input_hook=
redisplay
set_screen_size
special_prefixes
special_prefixes=
vi_editing_mode
vi_editing_mode?
set_screen_size
1 change: 0 additions & 1 deletion spec/truffle/tags/library/readline/constants_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/library/readline/readline_tags.txt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -43,20 +43,26 @@
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import jline.console.CursorBuffer;
import jline.console.completer.Completer;
import jline.console.completer.FileNameCompleter;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.Ruby;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.*;
import org.jruby.truffle.core.array.ArrayHelpers;
import org.jruby.truffle.core.cast.BooleanCastWithDefaultNodeGen;
import org.jruby.truffle.core.cast.NameToJavaStringNodeGen;
import org.jruby.truffle.core.cast.ToStrNodeGen;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.objects.TaintNode;
import org.jruby.truffle.language.objects.TaintNodeGen;

import java.io.IOException;
import java.nio.CharBuffer;
@@ -68,7 +74,7 @@
@CoreClass("Truffle::Readline")
public abstract class ReadlineNodes {

@CoreMethod(names = "basic_word_break_characters", isModuleFunction = true)
@CoreMethod(names = "basic_word_break_characters", onSingleton = true)
public abstract static class BasicWordBreakCharactersNode extends CoreMethodArrayArgumentsNode {

@Specialization
@@ -78,7 +84,7 @@ public DynamicObject basicWordBreakCharacters() {

}

@CoreMethod(names = "basic_word_break_characters=", isModuleFunction = true, required = 1)
@CoreMethod(names = "basic_word_break_characters=", onSingleton = true, required = 1)
@NodeChild(type = RubyNode.class, value = "characters")
public abstract static class SetBasicWordBreakCharactersNode extends CoreMethodNode {

@@ -95,7 +101,7 @@ public DynamicObject setBasicWordBreakCharacters(DynamicObject characters) {

}

@CoreMethod(names = "get_screen_size", isModuleFunction = true)
@CoreMethod(names = "get_screen_size", onSingleton = true)
public abstract static class GetScreenSizeNode extends CoreMethodArrayArgumentsNode {

@Specialization
@@ -114,18 +120,25 @@ public DynamicObject getScreenSize() {
})
public abstract static class ReadlineNode extends CoreMethodNode {

@Child private TaintNode taintNode;

public ReadlineNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
taintNode = TaintNodeGen.create(context, sourceSection, null);
}

@CreateCast("addToHistory") public RubyNode coerceToBoolean(RubyNode addToHistory) {
return BooleanCastWithDefaultNodeGen.create(null, null, false, addToHistory);
}

@Specialization(guards = "wasNotProvided(prompt)")
public DynamicObject readlineNoPrompt(Object prompt, boolean addToHistory) {
public Object readlineNoPrompt(Object prompt, boolean addToHistory) {
return readline(coreStrings().EMPTY_STRING.createInstance(), addToHistory);
}

@TruffleBoundary
@Specialization(guards = "isRubyString(prompt)")
public DynamicObject readline(DynamicObject prompt, boolean addToHistory) {
public Object readline(DynamicObject prompt, boolean addToHistory) {
getContext().getConsoleHolder().getReadline().setExpandEvents(false);

DynamicObject line = nil();
@@ -157,7 +170,90 @@ public DynamicObject readline(DynamicObject prompt, boolean addToHistory) {
line = StringOperations.createString(getContext(), StringOperations.createRope(value, getContext().getJRubyRuntime().getDefaultExternalEncoding()));
}

return line;
return taintNode.executeTaint(line);
}

}

@CoreMethod(names = "point", onSingleton = true)
public abstract static class PointNode extends CoreMethodArrayArgumentsNode {

@TruffleBoundary
@Specialization
public int point() {
return getContext().getConsoleHolder().getReadline().getCursorBuffer().cursor;
}

}

@CoreMethod(names = "insert_text", constructor = true, required = 1)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "self"),
@NodeChild(type = RubyNode.class, value = "text")
})
public abstract static class InsertTextNode extends CoreMethodNode {

@CreateCast("text") public RubyNode coerceTextToString(RubyNode text) {
return NameToJavaStringNodeGen.create(null, null, text);
}

@TruffleBoundary
@Specialization
public DynamicObject insertText(DynamicObject readline, String text) {
getContext().getConsoleHolder().getReadline().getCursorBuffer().write(text);

return readline;
}

}

@CoreMethod(names = "delete_text", constructor = true)
public abstract static class DeleteTextNode extends CoreMethodArrayArgumentsNode {

@TruffleBoundary
@Specialization
public DynamicObject deleteText(DynamicObject readline) {
getContext().getConsoleHolder().getReadline().getCursorBuffer().clear();

return readline;
}

}

@CoreMethod(names = "line_buffer", onSingleton = true)
public abstract static class LineBufferNode extends CoreMethodArrayArgumentsNode {

@Child private TaintNode taintNode;

public LineBufferNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
taintNode = TaintNodeGen.create(context, sourceSection, null);
}

@TruffleBoundary
@Specialization
public Object lineBuffer() {
final CursorBuffer cb = getContext().getConsoleHolder().getReadline().getCursorBuffer();

final DynamicObject ret = createString(StringOperations.createRope(cb.toString(), getDefaultInternalEncoding()));
return taintNode.executeTaint(ret);
}

}

@CoreMethod(names = "refresh_line", onSingleton = true)
public abstract static class RefreshLineNode extends CoreMethodArrayArgumentsNode {

@TruffleBoundary
@Specialization
public DynamicObject refreshLine() {
try {
getContext().getConsoleHolder().getReadline().redrawLine();
} catch (IOException e) {
throw new RaiseException(coreExceptions().ioError(e.getMessage(), this));
}

return nil();
}

}
@@ -166,11 +262,11 @@ public DynamicObject readline(DynamicObject prompt, boolean addToHistory) {
// Complete using a Proc object
public static class ProcCompleter implements Completer {

IRubyObject procCompleter;
DynamicObject procCompleter;
//\t\n\"\\'`@$><=;|&{(
static private String[] delimiters = {" ", "\t", "\n", "\"", "\\", "'", "`", "@", "$", ">", "<", "=", ";", "|", "&", "{", "("};

public ProcCompleter(IRubyObject procCompleter) {
public ProcCompleter(DynamicObject procCompleter) {
this.procCompleter = procCompleter;
}

@@ -201,25 +297,7 @@ private int wordIndexOf(String buffer) {
}

public int complete(String buffer, int cursor, List candidates) {
buffer = buffer.substring(0, cursor);
int index = wordIndexOf(buffer);
if (index != -1) buffer = buffer.substring(index + 1);

Ruby runtime = procCompleter.getRuntime();
ThreadContext context = runtime.getCurrentContext();
IRubyObject result = procCompleter.callMethod(context, "call", runtime.newString(buffer));
IRubyObject comps = result.callMethod(context, "to_a");

if (comps instanceof List) {
for (Iterator i = ((List) comps).iterator(); i.hasNext();) {
Object obj = i.next();
if (obj != null) {
candidates.add(obj.toString());
}
}
Collections.sort(candidates);
}
return cursor - buffer.length();
throw new UnsupportedOperationException("auto-completion via proc not yet supported");
}
}