From: Ondrej Bilka Date: 2006-08-14T03:02:40+09:00 Subject: Re: [PATCH] readline --/9DWx/yDrRhgMJTb Content-Type: text/plain; charset=us-ascii Content-Disposition: inline I rewritten my patch Part write is in ruby as lib/readlinerb.rb --/9DWx/yDrRhgMJTb Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="readlinerb.rb" #require 'readline_bin' module Readline @@namesno=0 @@bindprocs=[] @@function=Object.new # # #function[function name]= proc class<<@@function def []=(k,pro) if !@@hash.has_key?(k) @@bindprocs<< k @@namesno+=1 Readline.instance_eval{add_funcname(k)} end @@hash[k]=pro end def [](k) @@hash[k] end end @@hash={} def self.callback(code) pro=@@hash[ @@bindprocs[code]] pro.call if pro end #bind function with name name to given keyseq def self.bindfunction(name,keyseq) if @@hash.has_key?(name) keyseq(keyseq,@@bindprocs.index(name)) end end #return array of strings. Each string is like at inputrc #"keyseq": function def self.dump tmpr,tmpw=IO.pipe Readline.output=tmpw _dump Readline.output=$stdout tmpw.close a=[] while (g=tmpr.gets) a<< g end a end #parses line like it was in inputrc file def self.init_line(l) l.strip! return if l.strip[0]==?# key, com=l.split(":") return if !com com.strip! if @@hash.has_key?(com) bindfunction(com,key.strip[1...-1]) else parse_init_line(l); end end def self.init if !@inited reinit end @inited=true end #binds functions defined in ruby to keybindings assigned to them in inputrc def self.reinit() dump.each{|l| init_line(l)} end def self.function () @@function end def self.add_macro(keyseq,subst) init_line("\"#{keyseq}\": \"#{subst}\"") end end class << Readline private :add_funcname, :_dump, :callback , :keyseq , :parse_init_line,:init end --/9DWx/yDrRhgMJTb Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=diffrl Index: readline.c =================================================================== RCS file: /src/ruby/ext/readline/readline.c,v retrieving revision 1.31 diff -u -p -r1.31 readline.c --- readline.c 7 Aug 2006 08:59:42 -0000 1.31 +++ readline.c 13 Aug 2006 17:59:36 -0000 @@ -53,7 +53,13 @@ readline_event() rb_thread_schedule(); return 0; } - +static int readline_startup() +{ + rb_funcall( mReadline,rb_intern("init"),0); + return 0; +} +/* + * */ static VALUE readline_readline(int argc, VALUE *argv, VALUE self) { @@ -121,13 +127,139 @@ readline_s_set_output(VALUE self, VALUE rl_outstream = rb_io_stdio_file(ofp); return output; } +static VALUE readline_bindings; +int readline_dummy(int a,int b){return 0;} +static VALUE readline_add_funcname(VALUE self, VALUE name){ +#ifdef HAVE_RL_GENERIC_BIND + rl_add_funmap_entry (strdup(StringValuePtr(name)),readline_dummy); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static int __readline_keyno_part; +int readline_funa(int a,int b){ + __readline_keyno_part=b-64; + return 0; +} +int readline_funb(int a,int b){ + rb_funcall(mReadline,rb_intern("callback") ,1,INT2FIX(__readline_keyno_part*64+ b-64)); + return 0; +} + +/* + * call-seq + * Readline.keyseq(keyseq,proc) + * + * when keyseq is typed proc is executed + * + */ +static VALUE readline_s_set_keyseq(VALUE self,VALUE seq,VALUE num){ +#ifdef HAVE_RL_GENERIC_BIND + rb_secure(4); + int n=FIX2INT(num); + char *ptr=StringValuePtr(seq); + char *macro=malloc(5);/*macro that results 2 func calls*/ + if (n>=4096) rb_raise(rb_eArgError, "cannot define more than 4096 keybindings"); + + //30- record separator hope that nobody uses it + macro[0]=30; macro[1]=64+(n/64); macro[2]=0; + rl_generic_bind(ISFUNC,macro,(char *)readline_funa,rl_get_keymap()); + //29- group separator + macro[2]=29; macro[3]=64+(n%64); macro[4]=0; + rl_generic_bind(ISFUNC,macro+2,(char *)readline_funb,rl_get_keymap()); + rl_generic_bind(ISMACR,ptr,macro,rl_get_keymap());/*macro is used by rl do not delete it*/ +#else + rb_notimplement(); +#endif + return Qnil; +} static VALUE -readline_s_set_completion_proc(VALUE self, VALUE proc) +readline_s_get_getc(VALUE self) { rb_secure(4); + return rb_iv_get(mReadline, "@getc_proc"); +} +int mygetc(FILE *in){ + int r; + VALUE rlin=readline_s_get_getc(mReadline); + if RTEST(rlin) + r=NUM2INT(rb_funcall(rlin,rb_intern("call"),0)); + else + r=getc(rl_instream); + return r; +} + + +/* + * + * call-seq getc=proc + * + *proc becomes custom getc used by readline + *use when you cant stdin directly(remote connection) + *otherwise use input= to redirect input + * + */ + +static VALUE +readline_s_set_getc(VALUE self, VALUE proc) +{ + rb_secure(4); + if (NIL_P(proc)){ + return rb_iv_set(mReadline, "@getc_proc", proc); + } + + if (!rb_respond_to(proc, rb_intern("call"))) rb_raise(rb_eArgError, "argument must respond to `call'"); + rl_getc_function=mygetc; + return rb_iv_set(mReadline, "@getc_proc", proc); +} + +static VALUE +readline_s_get_redisplay(VALUE self) +{ + rb_secure(4); + return rb_iv_get(mReadline, "@redisplay"); +} +void readline_redisplay(){ + VALUE rdisp=rb_iv_get(mReadline, "@redisplay"); + if RTEST(rdisp) + rb_funcall(rdisp,rb_intern("call"),0); +} + + +/* + * + * call-seq redisplay=proc + * callback when readline needs redisplay line_buffer + * + */ + +static VALUE +readline_s_set_redisplay(VALUE self, VALUE proc) +{ + rb_secure(4); + if (NIL_P(proc)){ + return rb_iv_set(mReadline, "@redisplay", proc); + } + if (!rb_respond_to(proc, rb_intern("call"))) + rb_raise(rb_eArgError, "argument must respond to `call'"); + rl_redisplay_function=readline_redisplay; + return rb_iv_set(mReadline, "@redisplay", proc); +} + + + + +static VALUE +readline_s_set_completion_proc(VALUE self, VALUE proc) +{ + rb_secure(4); + if (!rb_respond_to(proc, rb_intern("call"))) + rb_raise(rb_eArgError, "argument must respond to `call'"); return rb_ivar_set(mReadline, completion_proc, proc); } @@ -696,27 +828,100 @@ username_completion_proc_call(VALUE self } return result; } - +static VALUE readline_s_set_line_buffer(VALUE self,VALUE buf){ + rb_secure(4); + VALUE buf2=StringValue(buf); + rl_extend_line_buffer(RSTRING (buf2)->len); + rl_modifying(0,rl_end-1); + strcpy( rl_line_buffer,RSTRING(buf2)->ptr); + return buf; +} +static VALUE readline_s_get_line_buffer(VALUE self){ + rb_secure(4); + return rb_str_new(rl_line_buffer,rl_end); +} +static VALUE readline_s_set_point(VALUE self,VALUE num){ + rb_secure(4); + rl_point=NUM2INT(num); + return num; +} +static VALUE readline_s_get_point(VALUE self){ + return INT2NUM(rl_point); +} +static VALUE readline_set_name(VALUE self,VALUE name){ + rb_secure(4); + free((char *)rl_readline_name);/* */ + rl_readline_name=strdup(StringValuePtr(name)); + return name; +} +static VALUE readline_init_line(VALUE self,VALUE line){ + rb_secure(4); + rl_parse_and_bind(StringValuePtr(line)); + return Qnil; +} +static VALUE readline_dump(VALUE self){ + rb_secure(4); + rl_function_dumper(1); + return Qnil; +} +int readline_reload_init_file(int a,int b){ + rl_read_init_file(NULL); + rb_funcall(mReadline,rb_intern("reinit"),0); + return 0; +} + void Init_readline() { VALUE history, fcomp, ucomp; /* Allow conditional parsing of the ~/.inputrc file. */ - rl_readline_name = "Ruby"; + rl_readline_name = strdup("Ruby"); using_history(); completion_proc = rb_intern(COMPLETION_PROC); completion_case_fold = rb_intern(COMPLETION_CASE_FOLD); + mReadline = rb_define_module("Readline"); + rb_define_singleton_method(mReadline, "_dump", + readline_dump, 0); + + rb_define_singleton_method(mReadline, "keyseq", + readline_s_set_keyseq, 2); + rb_define_singleton_method(mReadline, "add_funcname", + readline_add_funcname, 1); + + rb_define_singleton_method(mReadline, "redisplay=", + readline_s_set_redisplay, 1); + rb_define_singleton_method(mReadline, "redisplay", + readline_s_get_redisplay, 0); + + rb_define_singleton_method(mReadline, "parse_init_line", + readline_init_line, 1); + rb_define_singleton_method(mReadline, "app_name=", + readline_set_name, 1); + + rb_define_singleton_method(mReadline, "line_buffer=", + readline_s_set_line_buffer, 1); + rb_define_singleton_method(mReadline, "line_buffer", + readline_s_get_line_buffer, 0); + rb_define_singleton_method(mReadline, "point=", + readline_s_set_point, 1); + rb_define_singleton_method(mReadline, "point", + readline_s_get_point, 0); + rb_define_module_function(mReadline, "readline", readline_readline, -1); rb_define_singleton_method(mReadline, "input=", readline_s_set_input, 1); rb_define_singleton_method(mReadline, "output=", readline_s_set_output, 1); + rb_define_singleton_method(mReadline, "getc_proc=", + readline_s_set_getc, 1); + rb_define_singleton_method(mReadline, "getc_proc", + readline_s_get_getc, 0); rb_define_singleton_method(mReadline, "completion_proc=", readline_s_set_completion_proc, 1); rb_define_singleton_method(mReadline, "completion_proc", @@ -768,6 +973,8 @@ Init_readline() rb_define_singleton_method(history,"size", hist_length, 0); rb_define_singleton_method(history,"empty?", hist_empty_p, 0); rb_define_singleton_method(history,"delete_at", hist_delete_at, 1); + readline_bindings=rb_ary_new(); + rb_iv_set(mReadline,"@bindings",readline_bindings) ; rb_define_const(mReadline, "HISTORY", history); fcomp = rb_obj_alloc(rb_cObject); @@ -786,10 +993,16 @@ Init_readline() #endif rl_attempted_completion_function = readline_attempted_completion_function; +#ifdef HAVE_RL_STARTUP_HOOK + rl_startup_hook=readline_startup; + rl_bind_keyseq("\\C-x\\C-r",readline_reload_init_file); +#endif #ifdef HAVE_RL_EVENT_HOOK rl_event_hook = readline_event; #endif #ifdef HAVE_RL_CLEAR_SIGNALS rl_clear_signals(); #endif + + rb_eval_string("require \"readlinerb\""); } --/9DWx/yDrRhgMJTb Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=diffext Index: extconf.rb =================================================================== RCS file: /src/ruby/ext/readline/extconf.rb,v retrieving revision 1.10 diff -u -r1.10 extconf.rb --- extconf.rb 19 May 2005 16:26:50 -0000 1.10 +++ extconf.rb 13 Aug 2006 17:59:14 -0000 @@ -53,6 +53,8 @@ have_readline_var("rl_attempted_completion_over") have_readline_var("rl_library_version") have_readline_var("rl_event_hook") +have_readline_var("rl_startup_hook") +have_func("rl_generic_bind") have_func("rl_cleanup_after_signal") have_func("rl_clear_signals") have_func("rl_vi_editing_mode") --/9DWx/yDrRhgMJTb--