Bugs item #3212, was opened at 2006-01-09 17:44
You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=1698&aid=3212&group_id=426

Category: Core
Group: None
Status: Open
Resolution: None
Priority: 3
Submitted By: Geoff Jacobsen (gonwin)
Assigned to: Nobody (None)
Summary: Readline does not provide enough context to the completion_proc

Initial Comment:
below is a patch for ext/readline (for version 1.8.4 - should I be patching the HEAD?) that allows the completion to get the entire input line plus the start and end position of the word being completed.

The patch is designed to be backwards compatible with the current API. I have added a test to test_readline.


Index: ext/readline/README
===================================================================
RCS file: /src/ruby/ext/readline/README,v
retrieving revision 1.4
diff -u -r1.4 README
--- ext/readline/README	5 Jul 2001 15:47:03 -0000	1.4
+++ ext/readline/README	9 Jan 2006 04:35:59 -0000
@@ -47,6 +47,22 @@
   Returns a string containing a character to be appended on
   completion.  The default is a space (" ").
 
+line_buffer
+
+  Returns the full line that is being edited. This is useful from
+  within the complete_proc for determining the context of the
+  completion request.
+
+match_start
+
+  Returns the index in line_buffer which matches the start of
+  input-string passed to completion_proc.
+
+match_end
+
+  Returns the index in line_buffer which matches the end of
+  input-string passed to completion_proc.
+
 vi_editing_mode
 
   Specifies VI editing mode.
Index: ext/readline/README.ja
===================================================================
RCS file: /src/ruby/ext/readline/README.ja,v
retrieving revision 1.1
diff -u -r1.1 README.ja
--- ext/readline/README.ja	19 Jul 2001 05:42:07 -0000	1.1
+++ ext/readline/README.ja	9 Jan 2006 04:35:59 -0000
@@ -47,6 +47,22 @@
   ´°¬£¥¥¥
   ¶ (" ") £
 
+line_buffer
+
+  Returns the full line that is being edited. This is useful from
+  within the complete_proc for determining the context of the
+  completion request.
+
+match_start
+
+  Returns the index in line_buffer which matches the start of
+  input-string passed to completion_proc.
+
+match_end
+
+  Returns the index in line_buffer which matches the end of
+  input-string passed to completion_proc.
+
 vi_editing_mode
 
   VIテつ・筍シテつ・ノ、ヒ、ハ、テδェテつ、゛、テつケテつ。テつ」
Index: ext/readline/readline.c
===================================================================
RCS file: /src/ruby/ext/readline/readline.c,v
retrieving revision 1.16.2.8
diff -u -r1.16.2.8 readline.c
--- ext/readline/readline.c	30 Oct 2005 18:20:53 -0000	1.16.2.8
+++ ext/readline/readline.c	9 Jan 2006 04:36:00 -0000
@@ -24,7 +24,8 @@
 #endif
 
 static VALUE mReadline;
-
+static VALUE match_start=Qnil;
+static VALUE match_end=Qnil;
 #define TOLOWER(c) (isupper(c) ? tolower(c) : c)
 
 #define COMPLETION_PROC "completion_proc"
@@ -155,6 +156,10 @@
     rl_attempted_completion_over = 1;
 #endif
     case_fold = RTEST(rb_attr_get(mReadline, completion_case_fold));
+
+    match_start=INT2NUM(start);
+    match_end=INT2NUM(end);
+
     ary = rb_funcall(proc, rb_intern("call"), 1, rb_tainted_str_new2(text));
     if (TYPE(ary) != T_ARRAY)
 	ary = rb_Array(ary);
@@ -490,6 +495,34 @@
 }
 
 static VALUE
+readline_s_get_line_buffer(self)
+    VALUE self;
+{
+  if(rl_line_buffer==NULL)
+    return Qnil;
+
+  return rb_tainted_str_new2(rl_line_buffer);
+}
+
+static VALUE
+readline_s_get_match_start(self)
+    VALUE self;
+{
+  if(NIL_P(match_start))
+    return Qnil;
+  return match_start;
+}
+
+static VALUE
+readline_s_get_match_end(self)
+    VALUE self;
+{
+  if(NIL_P(match_end))
+    return Qnil;
+  return match_end;
+}
+
+static VALUE
 hist_to_s(self)
     VALUE self;
 {
@@ -774,6 +807,13 @@
 			       readline_s_set_filename_quote_characters, 1);
     rb_define_singleton_method(mReadline, "filename_quote_characters",
 			       readline_s_get_filename_quote_characters, 0);
+    rb_define_singleton_method(mReadline, "line_buffer",
+			       readline_s_get_line_buffer, 0);
+    rb_define_singleton_method(mReadline, "match_start",
+			       readline_s_get_match_start, 0);
+    rb_define_singleton_method(mReadline, "match_end",
+			       readline_s_get_match_end, 0);
+
 
     history = rb_obj_alloc(rb_cObject);
     rb_extend_object(history, rb_mEnumerable);
Index: test/readline/test_readline.rb
===================================================================
RCS file: /src/ruby/test/readline/test_readline.rb,v
retrieving revision 1.3.2.5
diff -u -r1.3.2.5 test_readline.rb
--- test/readline/test_readline.rb	22 Sep 2005 07:44:32 -0000	1.3.2.5
+++ test/readline/test_readline.rb	9 Jan 2006 04:36:07 -0000
@@ -59,6 +59,42 @@
     end
   end
 
+  def test_completion_proc
+    actual_line=nil
+    actual_start=nil
+    actual_end=nil
+    actual_text=nil
+
+    stdin = Tempfile.new("test_readline_stdin")
+    stdout = Tempfile.new("test_readline_stdout")
+    begin
+      expected_proc= proc { |text|
+        actual_text=text
+        actual_start=Readline.match_start
+        actual_end=Readline.match_end
+        actual_line=Readline.line_buffer
+        stdin.write(" finish\n")
+        stdin.close
+        stdout.close
+        return ["complete"]
+      }
+      Readline.completion_proc=expected_proc
+      assert_equal expected_proc, Readline.completion_proc
+      stdin.write("first second\t")
+      stdin.flush
+      line = replace_stdio(stdin.path, stdout.path) {
+        Readline.readline("> ", false)
+      }
+      assert_equal "first second",actual_line
+      assert_equal 6,actual_start
+      assert_equal 12,actual_end
+      assert_equal "first complete finish",Readline.line_buffer
+    ensure
+      stdin.close(true)
+      stdout.close(true)
+    end
+  end
+
   private
 
   def replace_stdio(stdin_path, stdout_path)

----------------------------------------------------------------------

You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=1698&aid=3212&group_id=426