Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: CPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Common Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.eclipse.org/legal/cpl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2006 Ola Bini <ola@ologix.com> Copyright (C) 2006 Damian Steer <pldms@mac.com> Copyright (C) 2008 Joseph LaFata <joe@quibb.org> Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the CPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ***
 
 package org.jruby.ext;
 
 import java.util.List;
 
 import static org.jruby.CompatVersion.*;
 
 import org.jruby.Ruby;
 import static org.jruby.runtime.Visibility.*;

Author(s):
Ola Bini
Damian Steer
Koichiro Ohba
 
 @JRubyModule(name = "Readline")
 public class Readline {
     public static final char ESC_KEY_CODE = (char)27;
     private final static boolean DEBUG = false;
     private static IRubyObject COMPLETION_CASE_FOLD = null;
 
 
     public static class ConsoleHolder {
         public ConsoleReader readline;
         public Completer currentCompletor;
         public History history;
     }
 
     public static void createReadline(Ruby runtimethrows IOException {
         ConsoleHolder holder = new ConsoleHolder();
         holder.history = new MemoryHistory();
         holder.currentCompletor = null;
          = runtime.getNil();
 
         RubyModule mReadline = runtime.defineModule("Readline");
 
         mReadline.dataWrapStruct(holder);
 
         mReadline.defineAnnotatedMethods(Readline.class);
         IRubyObject hist = runtime.getObject().callMethod(runtime.getCurrentContext(), "new");
         mReadline.setConstant("HISTORY"hist);
         hist.getSingletonClass().includeModule(runtime.getEnumerable());
 
         // MRI does similar thing on MacOS X with 'EditLine wrapper'.
         mReadline.setConstant("VERSION"runtime.newString("JLine wrapper"));
     }
    // We lazily initialize this in case Readline.readline has been overridden in ruby (s_readline)
    protected static void initReadline(Ruby runtimefinal ConsoleHolder holder) {
        try {
            holder.readline = new ConsoleReader();
        } catch (IOException ioe) {
            throw runtime.newIOErrorFromException(ioe);
        }
        holder.readline.setHistoryEnabled(false);
        holder.readline.setPaginationEnabled(true);
        holder.readline.setBellEnabled(true);
        if (holder.currentCompletor == null) {
            holder.currentCompletor = new RubyFileNameCompletor();
        }
        holder.readline.addCompleter(holder.currentCompletor);
        holder.readline.setHistory(holder.history);
        // JRUBY-852, ignore escape key (it causes IRB to quit if we pass it out through readline)
        holder.readline.addTriggeredAction(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    holder.readline.beep();
                } catch (IOException ioe) {
                    // ignore
                }
            }
        });
//        if (DEBUG) holder.readline.setDebug(new PrintWriter(System.err));
    }
    public static History getHistory(ConsoleHolder holder) {
        return holder.history;
    }
    public static ConsoleHolder getHolder(Ruby runtime) {
        return (ConsoleHolder) (runtime.getModule("Readline").dataGetStruct());
    }
    public static void setCompletor(ConsoleHolder holderCompleter completor) {
        if (holder.readline != null) {
            holder.readline.removeCompleter(holder.currentCompletor);
        }
        holder.currentCompletor = completor;
        if (holder.readline != null) {
            holder.readline.addCompleter(holder.currentCompletor);
        }
    }
    public static Completer getCompletor(ConsoleHolder holder) {
        return holder.currentCompletor;
    }
    public static IRubyObject s_readline(IRubyObject recvIRubyObject promptIRubyObject add_to_hist) {
        return s_readline(recv.getRuntime().getCurrentContext(), recvpromptadd_to_hist);
    }
    @JRubyMethod(name = "readline", module = true, visibility = )
    public static IRubyObject s_readline(ThreadContext contextIRubyObject recvIRubyObject promptIRubyObject add_to_hist) {
        Ruby runtime = context.runtime;
        ConsoleHolder holder = getHolder(runtime);
        if (holder.readline == null) {
            initReadline(runtimeholder); // not overridden, let's go
        }
        holder.readline.setExpandEvents(false);
        
        IRubyObject line = runtime.getNil();
        String v = null;
        while (true) {
            try {
                holder.readline.getTerminal().setEchoEnabled(false);
                v = holder.readline.readLine(prompt.toString());
                break;
            } catch (IOException ioe) {
                throw runtime.newIOErrorFromException(ioe);
            } finally {
                holder.readline.getTerminal().setEchoEnabled(true);
            }
        }
        
        if (null != v) {
            if (add_to_hist.isTrue()) {
                holder.readline.getHistory().add(v);
            }
            // Enebo: This is a little weird and a little broken.  We just ask
            // for the bytes and hope they match default_external.  This will 
            // work for common cases, but not ones in which the user explicitly
            // sets the default_external to something else.  The second problem
            // is that no al M17n encodings are valid encodings in java.lang.String.
            // We clearly need a byte[]-version of JLine since we cannot totally
            // behave properly using Java Strings.
            if (runtime.is1_9()) {
                ByteList list = new ByteList(v.getBytes(), runtime.getDefaultExternalEncoding());
                line = RubyString.newString(runtimelist);
            } else {
                /* Explicitly use UTF-8 here. c.f. history.addToHistory using line.asUTF8() */
                line = RubyString.newUnicodeString(recv.getRuntime(), v);
            }
        }
        return line;
    }
    @JRubyMethod(name = "input=", module = true, visibility = , compat = )
    public static IRubyObject setInput(ThreadContext contextIRubyObject recvIRubyObject input) {
        // FIXME: JRUBY-3604
        return context.runtime.getNil();
    }
    @JRubyMethod(name = "output=", module = true, visibility = , compat = )
    public static IRubyObject setOutput(ThreadContext contextIRubyObject recvIRubyObject output) {
        // FIXME: JRUBY-3604
        return context.runtime.getNil();
    }
    @JRubyMethod(name = "readline", module = true, visibility = )
    public static IRubyObject s_readline(IRubyObject recvIRubyObject prompt) {
        return s_readline(recvpromptrecv.getRuntime().getFalse());
    }
    @JRubyMethod(name = "readline", module = true, visibility = )
    public static IRubyObject s_readline(IRubyObject recv) {
        return s_readline(recv, RubyString.newEmptyString(recv.getRuntime()), recv.getRuntime().getFalse());
    }
    @JRubyMethod(name = "basic_word_break_characters=", module = true, visibility = )
    public static IRubyObject s_set_basic_word_break_character(IRubyObject recvIRubyObject achar) {
        Ruby runtime = recv.getRuntime();
        if (!achar.respondsTo("to_str")) {
            throw runtime.newTypeError("can't convert " + achar.getMetaClass() + " into String");
        }
        ProcCompleter.setDelimiter(achar.convertToString().toString());
        return achar;
    }
    @JRubyMethod(name = "basic_word_break_characters", module = true, visibility = )
        return recv.getRuntime().newString(ProcCompleter.getDelimiter());
    }
    @JRubyMethod(name = "completion_append_character=", module = true, visibility = )
    public static IRubyObject s_set_completion_append_character(IRubyObject recvIRubyObject achar) {
        return recv.getRuntime().getNil();
    }
    @JRubyMethod(name = "completion_proc=", module = true, visibility = )
    public static IRubyObject s_set_completion_proc(IRubyObject recvIRubyObject proc) {
        if (!proc.respondsTo("call")) {
            throw recv.getRuntime().newArgumentError("argument must respond to call");
        }
        setCompletor(getHolder(recv.getRuntime()), new ProcCompleter(proc));
        return recv.getRuntime().getNil();
    }
    @JRubyMethod(name = {
        "basic_quote_characters""basic_quote_characters=",
        "completer_quote_characters""completer_quote_characters=",
        "completer_word_break_characters""completer_word_break_characters=",
        "completion_append_character",
        "completion_proc",
        "emacs_editing_mode",
        "filename_quote_characters""filename_quote_characters=",
        "vi_editing_mode"}, frame = true, module = true, visibility = )
    public static IRubyObject unimplemented(ThreadContext contextIRubyObject recv) {
        Ruby runtime = context.runtime;
        String err = context.getFrameName() + "() function is unimplemented on this machine";
        throw runtime.newNotImplementedError(err);
    }
    @JRubyMethod(name = {
        "basic_quote_characters""basic_quote_characters=",
        "completer_quote_characters""completer_quote_characters=",
        "completer_word_break_characters""completer_word_break_characters=",
        "completion_append_character",
        "completion_proc",
        "emacs_editing_mode""emacs_editing_mode?",
        "filename_quote_characters""filename_quote_characters=",
        "vi_editing_mode""vi_editing_mode?",
        "set_screen_size"}, frame = true, module = true, visibility = , compat = )
    public static IRubyObject unimplemented19(ThreadContext contextIRubyObject recv) {
        Ruby runtime = context.runtime;
        String err = context.getFrameName() + "() function is unimplemented on this machine";
        throw runtime.newNotImplementedError(err);
    }
    @JRubyMethod(name = "completion_case_fold", module = true, visibility = )
    public static IRubyObject s_get_completion_case_fold(ThreadContext contextIRubyObject recv) {
        Ruby runtime = context.runtime;
        return ;
    }
    @JRubyMethod(name = "completion_case_fold=", required = 1, module = true, visibility = )
    // FIXME: this is really a noop
    public static IRubyObject s_set_completion_case_fold(ThreadContext contextIRubyObject recv,
            IRubyObject other) {
        Ruby runtime = context.runtime;
        return  = other;
    }
    @JRubyMethod(name = "get_screen_size", module = true, visibility = , compat = )
    public static IRubyObject s_get_screen_size(ThreadContext contextIRubyObject recv) {
        Ruby runtime = context.runtime;
        ConsoleHolder holder = getHolder(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(runtimeary);
    }
    @JRubyMethod(name = "line_buffer", module = true, visibility = , compat = )
    public static IRubyObject s_get_line_buffer(ThreadContext contextIRubyObject recv) {
        Ruby runtime = context.runtime;
        ConsoleHolder holder = getHolder(runtime);
        if (holder.readline == null) {
            initReadline(runtimeholder);
        }
        CursorBuffer cb = holder.readline.getCursorBuffer();
        return runtime.newString(cb.toString()).taint(context);
    }
    @JRubyMethod(name = "point", module = true, visibility = , compat = )
    public static IRubyObject s_get_point(ThreadContext contextIRubyObject recv) {
        Ruby runtime = context.runtime;
        ConsoleHolder holder = getHolder(runtime);
        if (holder.readline == null) {
            initReadline(runtimeholder);
        }
        CursorBuffer cb = holder.readline.getCursorBuffer();
        return runtime.newFixnum(cb.cursor);
    }
    @JRubyMethod(name = "refresh_line", module = true, visibility = , compat = )
    public static IRubyObject s_refresh_line(ThreadContext contextIRubyObject recv) {
        Ruby runtime = context.runtime;
        ConsoleHolder holder = getHolder(runtime);
        try {
            holder.readline.redrawLine(); // not quite the same as rl_refresh_line()
        } catch (IOException ioe) {
            throw runtime.newIOErrorFromException(ioe);
        }
        return runtime.getNil();
    }
    public static class HistoryMethods {
        @JRubyMethod(name = {"push""<<"}, rest = true)
        public static IRubyObject s_push(IRubyObject recvIRubyObject[] lines) {
            ConsoleHolder holder = getHolder(recv.getRuntime());
            for (int i = 0; i < lines.lengthi++) {
                RubyString line = lines[i].convertToString();
                holder.history.add(line.getUnicodeValue());
            }
            return recv;
        }
        @JRubyMethod(name = "pop")
        @SuppressWarnings("unchecked")
        public static IRubyObject s_pop(IRubyObject recv) {
            Ruby runtime = recv.getRuntime();
            ConsoleHolder holder = getHolder(runtime);
            if (holder.history.isEmpty()) return runtime.getNil();
            return runtime.newString(holder.history.removeLast().toString()).taint(runtime.getCurrentContext());
        }
        @JRubyMethod(name = "to_a")
        public static IRubyObject s_hist_to_a(IRubyObject recv) {
            Ruby runtime = recv.getRuntime();
            ConsoleHolder holder = getHolder(runtime);
            RubyArray histList = runtime.newArray();
            ListIterator<History.EntryhistoryIterator = holder.history.entries();
            while (historyIterator.hasNext()) {
                History.Entry nextEntry = historyIterator.next();
                histList.append(runtime.newString(nextEntry.value().toString()));
            }
            return histList;
        }
        @JRubyMethod(name = "to_s")
        public static IRubyObject s_hist_to_s(IRubyObject recv) {
            return recv.getRuntime().newString("HISTORY");
        }
        @JRubyMethod(name = "[]")
        public static IRubyObject s_hist_get(IRubyObject recvIRubyObject index) {
            Ruby runtime = recv.getRuntime();
            ConsoleHolder holder = getHolder(runtime);
            int i = (intindex.convertToInteger().getLongValue();
            if (i < 0) i += holder.history.size();
            try {
                ThreadContext context = runtime.getCurrentContext();
                return runtime.newString((Stringholder.history.get(i)).taint(context);
            } catch (IndexOutOfBoundsException ioobe) {
                throw runtime.newIndexError("invalid history index: " + i);
            }
        }
        @JRubyMethod(name = "[]=")
        public static IRubyObject s_hist_set(IRubyObject recvIRubyObject indexIRubyObject val) {
            Ruby runtime = recv.getRuntime();
            ConsoleHolder holder = getHolder(runtime);
            int i = (intindex.convertToInteger().getLongValue();
            if (i < 0) i += holder.history.size();
            try {
                holder.history.set(ival.asJavaString());
            } catch (IndexOutOfBoundsException ioobe) {
                throw runtime.newIndexError("invalid history index: " + i);
            }
            return runtime.getNil();
        }
        @JRubyMethod(name = "shift")
        public static IRubyObject s_hist_shift(IRubyObject recv) {
            Ruby runtime = recv.getRuntime();
            ConsoleHolder holder = getHolder(runtime);
            if (holder.history.isEmpty()) return runtime.getNil();
            try {
                return runtime.newString(holder.history.removeFirst().toString()).taint(runtime.getCurrentContext());
            } catch (IndexOutOfBoundsException ioobe) {
                throw runtime.newIndexError("history shift error");
            }
        }
        @JRubyMethod(name = {"length""size"})
        public static IRubyObject s_hist_length(IRubyObject recv) {
            ConsoleHolder holder = getHolder(recv.getRuntime());
            return recv.getRuntime().newFixnum(holder.history.size());
        }
        @JRubyMethod(name = "empty?")
        public static IRubyObject s_hist_empty_p(IRubyObject recv) {
            ConsoleHolder holder = getHolder(recv.getRuntime());
            return recv.getRuntime().newBoolean(holder.history.isEmpty());
        }
        @JRubyMethod(name = "delete_at")
        public static IRubyObject s_hist_delete_at(IRubyObject recvIRubyObject index) {
            Ruby runtime = recv.getRuntime();
            ThreadContext context = runtime.getCurrentContext();
            ConsoleHolder holder = getHolder(runtime);
            int i = RubyNumeric.num2int(index);
            if (i < 0) i += holder.history.size();
            
            try {
                return runtime.newString(holder.history.remove(i).toString()).taint(context);
            } catch (IndexOutOfBoundsException ioobe) {
                throw runtime.newIndexError("invalid history index: " + i);
            }
        }
        @JRubyMethod(name = "each")
        public static IRubyObject s_hist_each(IRubyObject recvBlock block) {
            Ruby runtime = recv.getRuntime();
            ThreadContext context = runtime.getCurrentContext();
            ConsoleHolder holder = getHolder(runtime);
            for (Iterator<History.Entryi = holder.history.iterator(); i.hasNext();) {
                block.yield(contextruntime.newString(i.next().value().toString()).taint(context));
            }
            return recv;
        }
    }
    // Complete using a Proc object
    public static class ProcCompleter implements Completer {
        IRubyObject procCompleter;
        //\t\n\"\\'`@$><=;|&{(
        static private String[] delimiters = {" ""\t""\n""\"""\\""'""`""@""$"">""<""="";""|""&""{""("};
        public ProcCompleter(IRubyObject procCompleter) {
            this. = procCompleter;
        }
        public static String getDelimiter() {
            StringBuilder result = new StringBuilder(.);
            for (String delimiter : ) {
                result.append(delimiter);
            }
            return result.toString();
        }
        public static void setDelimiter(String delimiter) {
            List<Stringl = new ArrayList<String>();
            CharBuffer buf = CharBuffer.wrap(delimiter);
            while (buf.hasRemaining()) {
                l.add(String.valueOf(buf.get()));
            }
             = l.toArray(new String[l.size()]);
        }
        private int wordIndexOf(String buffer) {
            int index = 0;
            for (String c : ) {
                index = buffer.lastIndexOf(c);
                if (index != -1) return index;
            }
            return index;
        }
        public int complete(String bufferint cursorList candidates) {
            buffer = buffer.substring(0, cursor);
            int index = wordIndexOf(buffer);
            if (index != -1) buffer = buffer.substring(index + 1);
            Ruby runtime = .getRuntime();
            ThreadContext context = runtime.getCurrentContext();
            IRubyObject result = .callMethod(context"call"runtime.newString(buffer));
            IRubyObject comps = result.callMethod(context"to_a");
            
            if (comps instanceof List) {
                for (Iterator i = ((Listcomps).iterator(); i.hasNext();) {
                    Object obj = i.next();
                    if (obj != null) {
                        candidates.add(obj.toString());
                    }
                }
                Collections.sort(candidates);
            }
            return cursor - buffer.length();
        }
    }
    // Fix FileNameCompletor to work mid-line
    public static class RubyFileNameCompletor extends FileNameCompleter {
        @Override
        public int complete(String bufferint cursorList candidates) {
            buffer = buffer.substring(0, cursor);
            int index = buffer.lastIndexOf(" ");
            if (index != -1) {
                buffer = buffer.substring(index + 1);
            }
            return index + 1 + super.complete(buffercursorcandidates);
        }
    }
New to GrepCode? Check out our FAQ X