1 /* readline.c -- GNU Readline module
2 Copyright (C) 1997-2001 Shugo Maeda */
9 #ifdef HAVE_READLINE_READLINE_H
10 #include <readline/readline.h>
12 #ifdef HAVE_READLINE_HISTORY_H
13 #include <readline/history.h>
15 #ifdef HAVE_EDITLINE_READLINE_H
16 #include <editline/readline.h>
27 static VALUE mReadline
;
29 #define TOLOWER(c) (isupper(c) ? tolower(c) : c)
31 #define COMPLETION_PROC "completion_proc"
32 #define COMPLETION_CASE_FOLD "completion_case_fold"
33 static ID completion_proc
, completion_case_fold
;
35 #ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION
36 # define rl_filename_completion_function filename_completion_function
38 #ifndef HAVE_RL_USERNAME_COMPLETION_FUNCTION
39 # define rl_username_completion_function username_completion_function
41 #ifndef HAVE_RL_COMPLETION_MATCHES
42 # define rl_completion_matches completion_matches
45 static int readline_event(void);
46 static char **readline_attempted_completion_function(const char *text
,
58 readline_readline(argc
, argv
, self
)
63 VALUE tmp
, add_hist
, result
;
70 if (rb_scan_args(argc
, argv
, "02", &tmp
, &add_hist
) > 0) {
72 prompt
= RSTRING(tmp
)->ptr
;
75 if (!isatty(0) && errno
== EBADF
) rb_raise(rb_eIOError
, "stdin closed");
77 Check_Type(rb_stdout
, T_FILE
);
78 GetOpenFile(rb_stdout
, ofp
);
79 rl_outstream
= GetWriteFile(ofp
);
80 Check_Type(rb_stdin
, T_FILE
);
81 GetOpenFile(rb_stdin
, ifp
);
82 rl_instream
= GetReadFile(ifp
);
83 buff
= (char*)rb_protect((VALUE(*)_((VALUE
)))readline
, (VALUE
)prompt
,
86 #if defined HAVE_RL_CLEANUP_AFTER_SIGNAL
87 /* restore terminal mode and signal handler*/
88 rl_cleanup_after_signal();
89 #elif defined HAVE_RL_DEPREP_TERM_FUNCTION
90 /* restore terminal mode */
91 if (rl_deprep_term_function
!= NULL
) /* NULL in libedit. [ruby-dev:29116] */
92 (*rl_deprep_term_function
)();
100 if (RTEST(add_hist
) && buff
) {
104 result
= rb_tainted_str_new2(buff
);
107 if (buff
) free(buff
);
112 readline_s_set_completion_proc(self
, proc
)
117 if (!rb_respond_to(proc
, rb_intern("call")))
118 rb_raise(rb_eArgError
, "argument must respond to `call'");
119 return rb_ivar_set(mReadline
, completion_proc
, proc
);
123 readline_s_get_completion_proc(self
)
127 return rb_attr_get(mReadline
, completion_proc
);
131 readline_s_set_completion_case_fold(self
, val
)
136 return rb_ivar_set(mReadline
, completion_case_fold
, val
);
140 readline_s_get_completion_case_fold(self
)
144 return rb_attr_get(mReadline
, completion_case_fold
);
148 readline_attempted_completion_function(text
, start
, end
)
153 VALUE proc
, ary
, temp
;
158 proc
= rb_attr_get(mReadline
, completion_proc
);
161 #ifdef HAVE_RL_ATTEMPTED_COMPLETION_OVER
162 rl_attempted_completion_over
= 1;
164 case_fold
= RTEST(rb_attr_get(mReadline
, completion_case_fold
));
165 ary
= rb_funcall(proc
, rb_intern("call"), 1, rb_tainted_str_new2(text
));
166 if (TYPE(ary
) != T_ARRAY
)
168 matches
= RARRAY(ary
)->len
;
171 result
= ALLOC_N(char *, matches
+ 2);
172 for (i
= 0; i
< matches
; i
++) {
173 temp
= rb_obj_as_string(RARRAY(ary
)->ptr
[i
]);
174 result
[i
+ 1] = ALLOC_N(char, RSTRING(temp
)->len
+ 1);
175 strcpy(result
[i
+ 1], RSTRING(temp
)->ptr
);
177 result
[matches
+ 1] = NULL
;
180 result
[0] = strdup(result
[1]);
186 while (i
< matches
) {
187 register int c1
, c2
, si
;
191 (c1
= TOLOWER(result
[i
][si
])) &&
192 (c2
= TOLOWER(result
[i
+ 1][si
]));
197 (c1
= result
[i
][si
]) &&
198 (c2
= result
[i
+ 1][si
]);
203 if (low
> si
) low
= si
;
206 result
[0] = ALLOC_N(char, low
+ 1);
207 strncpy(result
[0], result
[1], low
);
208 result
[0][low
] = '\0';
215 readline_s_vi_editing_mode(self
)
218 #ifdef HAVE_RL_VI_EDITING_MODE
220 rl_vi_editing_mode(1,0);
224 return Qnil
; /* not reached */
225 #endif /* HAVE_RL_VI_EDITING_MODE */
229 readline_s_emacs_editing_mode(self
)
232 #ifdef HAVE_RL_EMACS_EDITING_MODE
234 rl_emacs_editing_mode(1,0);
238 return Qnil
; /* not reached */
239 #endif /* HAVE_RL_EMACS_EDITING_MODE */
243 readline_s_set_completion_append_character(self
, str
)
246 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
249 rl_completion_append_character
= '\0';
252 SafeStringValue(str
);
253 if (RSTRING(str
)->len
== 0) {
254 rl_completion_append_character
= '\0';
256 rl_completion_append_character
= RSTRING(str
)->ptr
[0];
262 return Qnil
; /* not reached */
263 #endif /* HAVE_RL_COMPLETION_APPEND_CHARACTER */
267 readline_s_get_completion_append_character(self
)
270 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
274 if (rl_completion_append_character
== '\0')
277 str
= rb_str_new("", 1);
278 RSTRING(str
)->ptr
[0] = rl_completion_append_character
;
282 return Qnil
; /* not reached */
283 #endif /* HAVE_RL_COMPLETION_APPEND_CHARACTER */
287 readline_s_set_basic_word_break_characters(self
, str
)
290 #ifdef HAVE_RL_BASIC_WORD_BREAK_CHARACTERS
291 static char *basic_word_break_characters
= NULL
;
294 SafeStringValue(str
);
295 if (basic_word_break_characters
== NULL
) {
296 basic_word_break_characters
=
297 ALLOC_N(char, RSTRING(str
)->len
+ 1);
300 REALLOC_N(basic_word_break_characters
, char, RSTRING(str
)->len
+ 1);
302 strncpy(basic_word_break_characters
,
303 RSTRING(str
)->ptr
, RSTRING(str
)->len
);
304 basic_word_break_characters
[RSTRING(str
)->len
] = '\0';
305 rl_basic_word_break_characters
= basic_word_break_characters
;
309 return Qnil
; /* not reached */
310 #endif /* HAVE_RL_BASIC_WORD_BREAK_CHARACTERS */
314 readline_s_get_basic_word_break_characters(self
, str
)
317 #ifdef HAVE_RL_BASIC_WORD_BREAK_CHARACTERS
319 if (rl_basic_word_break_characters
== NULL
)
321 return rb_tainted_str_new2(rl_basic_word_break_characters
);
324 return Qnil
; /* not reached */
325 #endif /* HAVE_RL_BASIC_WORD_BREAK_CHARACTERS */
329 readline_s_set_completer_word_break_characters(self
, str
)
332 #ifdef HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS
333 static char *completer_word_break_characters
= NULL
;
336 SafeStringValue(str
);
337 if (completer_word_break_characters
== NULL
) {
338 completer_word_break_characters
=
339 ALLOC_N(char, RSTRING(str
)->len
+ 1);
342 REALLOC_N(completer_word_break_characters
, char, RSTRING(str
)->len
+ 1);
344 strncpy(completer_word_break_characters
,
345 RSTRING(str
)->ptr
, RSTRING(str
)->len
);
346 completer_word_break_characters
[RSTRING(str
)->len
] = '\0';
347 rl_completer_word_break_characters
= completer_word_break_characters
;
351 return Qnil
; /* not reached */
352 #endif /* HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS */
356 readline_s_get_completer_word_break_characters(self
, str
)
359 #ifdef HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS
361 if (rl_completer_word_break_characters
== NULL
)
363 return rb_tainted_str_new2(rl_completer_word_break_characters
);
366 return Qnil
; /* not reached */
367 #endif /* HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS */
371 readline_s_set_basic_quote_characters(self
, str
)
374 #ifdef HAVE_RL_BASIC_QUOTE_CHARACTERS
375 static char *basic_quote_characters
= NULL
;
378 SafeStringValue(str
);
379 if (basic_quote_characters
== NULL
) {
380 basic_quote_characters
=
381 ALLOC_N(char, RSTRING(str
)->len
+ 1);
384 REALLOC_N(basic_quote_characters
, char, RSTRING(str
)->len
+ 1);
386 strncpy(basic_quote_characters
,
387 RSTRING(str
)->ptr
, RSTRING(str
)->len
);
388 basic_quote_characters
[RSTRING(str
)->len
] = '\0';
389 rl_basic_quote_characters
= basic_quote_characters
;
394 return Qnil
; /* not reached */
395 #endif /* HAVE_RL_BASIC_QUOTE_CHARACTERS */
399 readline_s_get_basic_quote_characters(self
, str
)
402 #ifdef HAVE_RL_BASIC_QUOTE_CHARACTERS
404 if (rl_basic_quote_characters
== NULL
)
406 return rb_tainted_str_new2(rl_basic_quote_characters
);
409 return Qnil
; /* not reached */
410 #endif /* HAVE_RL_BASIC_QUOTE_CHARACTERS */
414 readline_s_set_completer_quote_characters(self
, str
)
417 #ifdef HAVE_RL_COMPLETER_QUOTE_CHARACTERS
418 static char *completer_quote_characters
= NULL
;
421 SafeStringValue(str
);
422 if (completer_quote_characters
== NULL
) {
423 completer_quote_characters
=
424 ALLOC_N(char, RSTRING(str
)->len
+ 1);
427 REALLOC_N(completer_quote_characters
, char, RSTRING(str
)->len
+ 1);
429 strncpy(completer_quote_characters
,
430 RSTRING(str
)->ptr
, RSTRING(str
)->len
);
431 completer_quote_characters
[RSTRING(str
)->len
] = '\0';
432 rl_completer_quote_characters
= completer_quote_characters
;
437 return Qnil
; /* not reached */
438 #endif /* HAVE_RL_COMPLETER_QUOTE_CHARACTERS */
442 readline_s_get_completer_quote_characters(self
, str
)
445 #ifdef HAVE_RL_COMPLETER_QUOTE_CHARACTERS
447 if (rl_completer_quote_characters
== NULL
)
449 return rb_tainted_str_new2(rl_completer_quote_characters
);
452 return Qnil
; /* not reached */
453 #endif /* HAVE_RL_COMPLETER_QUOTE_CHARACTERS */
457 readline_s_set_filename_quote_characters(self
, str
)
460 #ifdef HAVE_RL_FILENAME_QUOTE_CHARACTERS
461 static char *filename_quote_characters
= NULL
;
464 SafeStringValue(str
);
465 if (filename_quote_characters
== NULL
) {
466 filename_quote_characters
=
467 ALLOC_N(char, RSTRING(str
)->len
+ 1);
470 REALLOC_N(filename_quote_characters
, char, RSTRING(str
)->len
+ 1);
472 strncpy(filename_quote_characters
,
473 RSTRING(str
)->ptr
, RSTRING(str
)->len
);
474 filename_quote_characters
[RSTRING(str
)->len
] = '\0';
475 rl_filename_quote_characters
= filename_quote_characters
;
480 return Qnil
; /* not reached */
481 #endif /* HAVE_RL_FILENAME_QUOTE_CHARACTERS */
485 readline_s_get_filename_quote_characters(self
, str
)
488 #ifdef HAVE_RL_FILENAME_QUOTE_CHARACTERS
490 if (rl_filename_quote_characters
== NULL
)
492 return rb_tainted_str_new2(rl_filename_quote_characters
);
495 return Qnil
; /* not reached */
496 #endif /* HAVE_RL_FILENAME_QUOTE_CHARACTERS */
503 return rb_str_new2("HISTORY");
507 hist_get(self
, index
)
519 entry
= history_get(history_base
+ i
);
521 rb_raise(rb_eIndexError
, "invalid index");
523 return rb_tainted_str_new2(entry
->line
);
527 hist_set(self
, index
, str
)
532 #ifdef HAVE_REPLACE_HISTORY_ENTRY
538 SafeStringValue(str
);
542 entry
= replace_history_entry(i
, RSTRING(str
)->ptr
, NULL
);
544 rb_raise(rb_eIndexError
, "invalid index");
549 return Qnil
; /* not reached */
559 SafeStringValue(str
);
560 add_history(RSTRING(str
)->ptr
);
565 hist_push_method(argc
, argv
, self
)
575 SafeStringValue(str
);
576 add_history(RSTRING(str
)->ptr
);
582 rb_remove_history(index
)
585 #ifdef HAVE_REMOVE_HISTORY
590 entry
= remove_history(index
);
592 val
= rb_tainted_str_new2(entry
->line
);
600 return Qnil
; /* not reached */
609 if (history_length
> 0) {
610 return rb_remove_history(history_length
- 1);
621 if (history_length
> 0) {
622 return rb_remove_history(0);
636 for (i
= 0; i
< history_length
; i
++) {
637 entry
= history_get(history_base
+ i
);
640 rb_yield(rb_tainted_str_new2(entry
->line
));
650 return INT2NUM(history_length
);
658 return history_length
== 0 ? Qtrue
: Qfalse
;
662 hist_delete_at(self
, index
)
672 if (i
< 0 || i
> history_length
- 1) {
673 rb_raise(rb_eIndexError
, "invalid index");
675 return rb_remove_history(i
);
679 filename_completion_proc_call(self
, str
)
687 matches
= rl_completion_matches(StringValuePtr(str
),
688 rl_filename_completion_function
);
690 result
= rb_ary_new();
691 for (i
= 0; matches
[i
]; i
++) {
692 rb_ary_push(result
, rb_tainted_str_new2(matches
[i
]));
696 if (RARRAY(result
)->len
>= 2)
697 rb_ary_shift(result
);
706 username_completion_proc_call(self
, str
)
714 matches
= rl_completion_matches(StringValuePtr(str
),
715 rl_username_completion_function
);
717 result
= rb_ary_new();
718 for (i
= 0; matches
[i
]; i
++) {
719 rb_ary_push(result
, rb_tainted_str_new2(matches
[i
]));
723 if (RARRAY(result
)->len
>= 2)
724 rb_ary_shift(result
);
735 VALUE history
, fcomp
, ucomp
;
737 /* Allow conditional parsing of the ~/.inputrc file. */
738 rl_readline_name
= "Ruby";
742 completion_proc
= rb_intern(COMPLETION_PROC
);
743 completion_case_fold
= rb_intern(COMPLETION_CASE_FOLD
);
745 mReadline
= rb_define_module("Readline");
746 rb_define_module_function(mReadline
, "readline",
747 readline_readline
, -1);
748 rb_define_singleton_method(mReadline
, "completion_proc=",
749 readline_s_set_completion_proc
, 1);
750 rb_define_singleton_method(mReadline
, "completion_proc",
751 readline_s_get_completion_proc
, 0);
752 rb_define_singleton_method(mReadline
, "completion_case_fold=",
753 readline_s_set_completion_case_fold
, 1);
754 rb_define_singleton_method(mReadline
, "completion_case_fold",
755 readline_s_get_completion_case_fold
, 0);
756 rb_define_singleton_method(mReadline
, "vi_editing_mode",
757 readline_s_vi_editing_mode
, 0);
758 rb_define_singleton_method(mReadline
, "emacs_editing_mode",
759 readline_s_emacs_editing_mode
, 0);
760 rb_define_singleton_method(mReadline
, "completion_append_character=",
761 readline_s_set_completion_append_character
, 1);
762 rb_define_singleton_method(mReadline
, "completion_append_character",
763 readline_s_get_completion_append_character
, 0);
764 rb_define_singleton_method(mReadline
, "basic_word_break_characters=",
765 readline_s_set_basic_word_break_characters
, 1);
766 rb_define_singleton_method(mReadline
, "basic_word_break_characters",
767 readline_s_get_basic_word_break_characters
, 0);
768 rb_define_singleton_method(mReadline
, "completer_word_break_characters=",
769 readline_s_set_completer_word_break_characters
, 1);
770 rb_define_singleton_method(mReadline
, "completer_word_break_characters",
771 readline_s_get_completer_word_break_characters
, 0);
772 rb_define_singleton_method(mReadline
, "basic_quote_characters=",
773 readline_s_set_basic_quote_characters
, 1);
774 rb_define_singleton_method(mReadline
, "basic_quote_characters",
775 readline_s_get_basic_quote_characters
, 0);
776 rb_define_singleton_method(mReadline
, "completer_quote_characters=",
777 readline_s_set_completer_quote_characters
, 1);
778 rb_define_singleton_method(mReadline
, "completer_quote_characters",
779 readline_s_get_completer_quote_characters
, 0);
780 rb_define_singleton_method(mReadline
, "filename_quote_characters=",
781 readline_s_set_filename_quote_characters
, 1);
782 rb_define_singleton_method(mReadline
, "filename_quote_characters",
783 readline_s_get_filename_quote_characters
, 0);
785 history
= rb_obj_alloc(rb_cObject
);
786 rb_extend_object(history
, rb_mEnumerable
);
787 rb_define_singleton_method(history
,"to_s", hist_to_s
, 0);
788 rb_define_singleton_method(history
,"[]", hist_get
, 1);
789 rb_define_singleton_method(history
,"[]=", hist_set
, 2);
790 rb_define_singleton_method(history
,"<<", hist_push
, 1);
791 rb_define_singleton_method(history
,"push", hist_push_method
, -1);
792 rb_define_singleton_method(history
,"pop", hist_pop
, 0);
793 rb_define_singleton_method(history
,"shift", hist_shift
, 0);
794 rb_define_singleton_method(history
,"each", hist_each
, 0);
795 rb_define_singleton_method(history
,"length", hist_length
, 0);
796 rb_define_singleton_method(history
,"size", hist_length
, 0);
797 rb_define_singleton_method(history
,"empty?", hist_empty_p
, 0);
798 rb_define_singleton_method(history
,"delete_at", hist_delete_at
, 1);
799 rb_define_const(mReadline
, "HISTORY", history
);
801 fcomp
= rb_obj_alloc(rb_cObject
);
802 rb_define_singleton_method(fcomp
, "call",
803 filename_completion_proc_call
, 1);
804 rb_define_const(mReadline
, "FILENAME_COMPLETION_PROC", fcomp
);
806 ucomp
= rb_obj_alloc(rb_cObject
);
807 rb_define_singleton_method(ucomp
, "call",
808 username_completion_proc_call
, 1);
809 rb_define_const(mReadline
, "USERNAME_COMPLETION_PROC", ucomp
);
810 #if defined HAVE_RL_LIBRARY_VERSION
811 rb_define_const(mReadline
, "VERSION", rb_str_new2(rl_library_version
));
813 rb_define_const(mReadline
, "VERSION",
814 rb_str_new2("2.0 or before version"));
817 rl_attempted_completion_function
= readline_attempted_completion_function
;
818 #ifdef HAVE_RL_EVENT_HOOK
819 rl_event_hook
= readline_event
;
821 #ifdef HAVE_RL_CLEAR_SIGNALS