Hi,
And with Readline.completion_proc i have code that will return only dirs
in this directory. But I would like to invoke this specific code part
only
when a user typed in i.e. "cd "
So if i have a directory called "foobar" it should work here:
"cd foo<TAB>" # completed to foobar
but if the user would type
"blabalblabla foo<TAB>" # there should be no result
I want to add some methods that satisfy the Marc Heiler's demands.
The patch contributed to the RubyForge is taken.
[#3212] Readline does not provide enough context to the completion_proc
http://rubyforge.org/tracker/index.php?func=detail&aid=3212&group_id=426&atid=1698
First of all, I will take it into ruby 1.9. Afterwards, backport to 1.8.
I will add the follows methods.
* line_buffer: Returns the full line that is being edited.
(same as rl_line_buffer)
* point: Returns the index of the current cursor position
in Readline.line_buffer. (same as rl_point)
The match_start is computed by subtracting the length of input-string
from Readline.point.
The match_end and Readline.line_buffer are same.
Attached the patch for ruby 1.9 (r18525).
Thanks, TAKAO Kouji.
-----
Index: ext/readline/readline.c
===================================================================
--- ext/readline/readline.c (revision 18525)
+++ ext/readline/readline.c (working copy)
@@ -367,6 +367,56 @@
return rb_attr_get(mReadline, completion_case_fold);
}
+/*
+ * call-seq:
+ * Readline.line_buffer -> string
+ *
+ * Returns the full line that is being edited. This is useful from
+ * within the complete_proc for determining the context of the
+ * completion request.
+ *
+ * The length of +Readline.line_buffer+ and GNU Readline's rl_end are
+ * same.
+ */
+static VALUE
+readline_s_get_line_buffer(VALUE self)
+{
+#ifdef HAVE_RL_LINE_BUFFER
+ rb_secure(4);
+ if (rl_line_buffer == NULL)
+ return Qnil;
+ return rb_tainted_str_new2(rl_line_buffer);
+#else
+ rb_notimplement();
+ return Qnil; /* not reached */
+#endif /* HAVE_RL_LINE_BUFFER */
+}
+
+/*
+ * call-seq:
+ * Readline.point -> int
+ *
+ * Returns the index of the current cursor position in
+ * +Readline.line_buffer+.
+ *
+ * The index in +Readline.line_buffer+ which matches the start of
+ * input-string passed to completion_proc is computed by subtracting
+ * the length of input-string from +Readline.point+.
+ *
+ * start = (the length of input-string) - Readline.point
+ */
+static VALUE
+readline_s_get_point(VALUE self)
+{
+#ifdef HAVE_RL_POINT
+ rb_secure(4);
+ return INT2NUM(rl_point);
+#else
+ rb_notimplement();
+ return Qnil; /* not reached */
+#endif /* HAVE_RL_POINT */
+}
+
static char **
readline_attempted_completion_function(const char *text, int start, int end)
{
@@ -1196,6 +1246,10 @@
readline_s_set_completion_case_fold, 1);
rb_define_singleton_method(mReadline, "completion_case_fold",
readline_s_get_completion_case_fold, 0);
+ rb_define_singleton_method(mReadline, "line_buffer",
+ readline_s_get_line_buffer, 0);
+ rb_define_singleton_method(mReadline, "point",
+ readline_s_get_point, 0);
rb_define_singleton_method(mReadline, "vi_editing_mode",
readline_s_vi_editing_mode, 0);
rb_define_singleton_method(mReadline, "vi_editing_mode?",
Index: ext/readline/extconf.rb
===================================================================
--- ext/readline/extconf.rb (revision 18525)
+++ ext/readline/extconf.rb (working copy)
@@ -59,6 +59,8 @@
have_readline_var("rl_attempted_completion_over")
have_readline_var("rl_library_version")
have_readline_var("rl_editing_mode")
+have_readline_var("rl_line_buffer")
+have_readline_var("rl_point")
# workaround for native windows.
/mswin|bccwin|mingw/ !~ RUBY_PLATFORM && have_readline_var("rl_event_hook")
have_readline_func("rl_cleanup_after_signal")
Index: test/readline/test_readline.rb
===================================================================
--- test/readline/test_readline.rb (revision 18525)
+++ test/readline/test_readline.rb (working copy)
@@ -3,6 +3,8 @@
=begin
class << Readline
[
+ "line_buffer",
+ "point",
"vi_editing_mode",
"emacs_editing_mode",
"completion_append_character=",
@@ -61,6 +63,8 @@
["completer_quote_characters"],
["filename_quote_characters=", "\\"],
["filename_quote_characters"],
+ ["line_buffer"],
+ ["point"],
]
method_args.each do |method_name, *args|
assert_raises(SecurityError, NotImplementedError,
@@ -74,41 +78,83 @@
end
end
- def test_readline
- stdin = Tempfile.new("test_readline_stdin")
- stdout = Tempfile.new("test_readline_stdout")
- begin
- stdin.write("hello\n")
- stdin.close
- stdout.close
- line = replace_stdio(stdin.path, stdout.path) {
- Readline.readline("> ", true)
- }
- assert_equal("hello", line)
- assert_equal(true, line.tainted?)
- stdout.open
- assert_equal("> ", stdout.read(2))
- assert_equal(1, Readline::HISTORY.length)
- assert_equal("hello", Readline::HISTORY[0])
- assert_raises(SecurityError) do
- Thread.start {
- $SAFE = 1
- replace_stdio(stdin.path, stdout.path) do
- Readline.readline("> ".taint)
- end
- }.join
+ if !/EditLine/n.match(Readline::VERSION)
+ def test_readline
+ stdin = Tempfile.new("test_readline_stdin")
+ stdout = Tempfile.new("test_readline_stdout")
+ begin
+ stdin.write("hello\n")
+ stdin.close
+ stdout.close
+ line = replace_stdio(stdin.path, stdout.path) {
+ Readline.readline("> ", true)
+ }
+ assert_equal("hello", line)
+ assert_equal(true, line.tainted?)
+ stdout.open
+ assert_equal("> ", stdout.read(2))
+ assert_equal(1, Readline::HISTORY.length)
+ assert_equal("hello", Readline::HISTORY[0])
+ assert_raises(SecurityError) do
+ Thread.start {
+ $SAFE = 1
+ replace_stdio(stdin.path, stdout.path) do
+ Readline.readline("> ".taint)
+ end
+ }.join
+ end
+ assert_raises(SecurityError) do
+ Thread.start {
+ $SAFE = 4
+ replace_stdio(stdin.path, stdout.path) { Readline.readline("> ") }
+ }.join
+ end
+ ensure
+ stdin.close(true)
+ stdout.close(true)
end
- assert_raises(SecurityError) do
- Thread.start {
- $SAFE = 4
- replace_stdio(stdin.path, stdout.path) { Readline.readline("> ") }
- }.join
+ end
+
+ # line_buffer
+ # point
+ def test_line_buffer__point
+ begin
+ Readline.line_buffer
+ Readline.point
+ rescue NotImplementedError
+ return
end
- ensure
- stdin.close(true)
- stdout.close(true)
+
+ stdin = Tempfile.new("test_readline_stdin")
+ stdout = Tempfile.new("test_readline_stdout")
+ begin
+ actual_text = nil
+ actual_line_buffer = nil
+ actual_point = nil
+ Readline.completion_proc = proc { |text|
+ actual_text = text
+ actual_point = Readline.point
+ actual_buffer_line = Readline.line_buffer
+ stdin.write(" finish\n")
+ stdin.close
+ stdout.close
+ return ["complete"]
+ }
+ stdin.write("first second\t")
+ stdin.flush
+ line = replace_stdio(stdin.path, stdout.path) {
+ Readline.readline("> ", false)
+ }
+ assert_equal("first second", actual_line_buffer)
+ assert_equal(12, actual_point)
+ assert_equal("first complete finish", Readline.line_buffer)
+ assert_equal(21, Readline.point)
+ ensure
+ stdin.close(true)
+ stdout.close(true)
+ end
end
- end if !/EditLine/n.match(Readline::VERSION)
+ end
def test_input=
assert_raise(TypeError) do