diff --git a/ChangeLog b/ChangeLog index f2753a36b3..976275c80c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Sun Jan 9 14:47:50 2011 TAKAO Kouji + + * ext/readline/readline.c: apply a patch from Nobuyoshi Nakada. + fixed #3616 [ruby-core:31484] IRB + readline incorrectly counts + non-printing characters in prompt + Sat Jan 8 21:47:26 2011 Tanaka Akira * enum.c (enum_sort_by): use rb_ary_resize. diff --git a/ext/readline/readline.c b/ext/readline/readline.c index ac88c84f59..4e530be194 100644 --- a/ext/readline/readline.c +++ b/ext/readline/readline.c @@ -43,10 +43,20 @@ static VALUE mReadline; #define EDIT_LINE_LIBRARY_VERSION "EditLine wrapper" +#ifndef USE_INSERT_IGNORE_ESCAPE +# ifndef HAVE_EDITLINE_READLINE_H +# define USE_INSERT_IGNORE_ESCAPE 1 +# else +# define USE_INSERT_IGNORE_ESCAPE 0 +# endif +#endif #define COMPLETION_PROC "completion_proc" #define COMPLETION_CASE_FOLD "completion_case_fold" static ID completion_proc, completion_case_fold; +#if USE_INSERT_IGNORE_ESCAPE +static ID id_orig_prompt, id_last_prompt; +#endif #ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION # define rl_filename_completion_function filename_completion_function @@ -145,6 +155,81 @@ readline_event(void) } #endif +#if USE_INSERT_IGNORE_ESCAPE +static VALUE +insert_ignore_escape(VALUE self, VALUE prompt) +{ + VALUE last_prompt, orig_prompt = rb_attr_get(self, id_orig_prompt); + int ignoring = 0; + const char *s0, *s, *e; + long len; + static const char ignore_code[2] = {RL_PROMPT_START_IGNORE, RL_PROMPT_END_IGNORE}; + + prompt = rb_str_new_shared(prompt); + last_prompt = rb_attr_get(self, id_last_prompt); + if (orig_prompt == prompt) return last_prompt; + len = RSTRING_LEN(prompt); + if (NIL_P(last_prompt)) { + last_prompt = rb_str_tmp_new(len); + } + + s = s0 = RSTRING_PTR(prompt); + e = s0 + len; + rb_str_set_len(last_prompt, 0); + while (s < e && *s) { + switch (*s) { + case RL_PROMPT_START_IGNORE: + ignoring = -1; + rb_str_cat(last_prompt, s0, ++s - s0); + s0 = s; + break; + case RL_PROMPT_END_IGNORE: + ignoring = 0; + rb_str_cat(last_prompt, s0, ++s - s0); + s0 = s; + break; + case '\033': + if (++s < e && *s == '[') { + rb_str_cat(last_prompt, s0, s - s0 - 1); + s0 = s - 1; + while (++s < e && *s) { + if (ISALPHA(*s)) { + if (!ignoring) { + ignoring = 1; + rb_str_cat(last_prompt, ignore_code+0, 1); + } + rb_str_cat(last_prompt, s0, ++s - s0); + s0 = s; + break; + } + else if (!('0' <= *s && *s <= '9' || *s == ';')) { + break; + } + } + } + break; + default: + if (ignoring > 0) { + ignoring = 0; + rb_str_cat(last_prompt, ignore_code+1, 1); + } + s++; + break; + } + } + if (ignoring > 0) { + ignoring = 0; + rb_str_cat(last_prompt, ignore_code+1, 1); + } + rb_str_cat(last_prompt, s0, s - s0); + + rb_ivar_set(self, id_orig_prompt, prompt); + rb_ivar_set(self, id_last_prompt, last_prompt); + + return last_prompt; +} +#endif + static VALUE readline_get(VALUE prompt) { @@ -248,6 +333,10 @@ readline_readline(int argc, VALUE *argv, VALUE self) rb_secure(4); if (rb_scan_args(argc, argv, "02", &tmp, &add_hist) > 0) { OutputStringValue(tmp); +#if USE_INSERT_IGNORE_ESCAPE + tmp = insert_ignore_escape(self, tmp); + rb_str_locktmp(tmp); +#endif prompt = RSTRING_PTR(tmp); } @@ -257,6 +346,11 @@ readline_readline(int argc, VALUE *argv, VALUE self) rl_prep_terminal(1); #endif buff = (char*)rb_protect(readline_get, (VALUE)prompt, &status); +#if USE_INSERT_IGNORE_ESCAPE + if (prompt) { + rb_str_unlocktmp(tmp); + } +#endif if (status) { #if defined HAVE_RL_CLEANUP_AFTER_SIGNAL /* restore terminal mode and signal handler*/ @@ -1383,6 +1477,11 @@ Init_readline() rb_define_singleton_method(mReadline, "refresh_line", readline_s_refresh_line, 0); +#if USE_INSERT_IGNORE_ESCAPE + CONST_ID(id_orig_prompt, "orig_prompt"); + CONST_ID(id_last_prompt, "last_prompt"); +#endif + history = rb_obj_alloc(rb_cObject); rb_extend_object(history, rb_mEnumerable); rb_define_singleton_method(history,"to_s", hist_to_s, 0);