1 /* Ruby interface (scripting engine) */
13 #include "bfu/dialog.h"
14 #include "config/home.h"
15 #include "intl/gettext/libintl.h"
16 #include "main/module.h"
17 #include "osdep/osdep.h"
18 #include "scripting/scripting.h"
19 #include "scripting/ruby/core.h"
20 #include "scripting/ruby/ruby.h"
21 #include "util/error.h"
22 #include "util/file.h"
23 #include "util/string.h"
25 #define RUBY_HOOKS_FILENAME "hooks.rb"
28 /* I've decided to use `erb' to refer to this ELinks/ruby thingy. */
33 /* Error reporting. */
36 alert_ruby_error(struct session
*ses
, unsigned char *msg
)
38 report_scripting_error(&ruby_scripting_module
, ses
, msg
);
41 /* Another Vim treat. */
43 erb_report_error(struct session
*ses
, int error
)
47 unsigned char buff
[MAX_STR_LEN
];
50 /* XXX: Ew. These are from the Ruby internals. */
51 #define TAG_RETURN 0x1
63 msg
= "unexpected return";
66 msg
= "unexpected next";
69 msg
= "unexpected break";
72 msg
= "unexpected redo";
75 msg
= "retry outside of rescue clause";
79 eclass
= CLASS_OF(ruby_errinfo
);
80 einfo
= rb_obj_as_string(ruby_errinfo
);
82 if (eclass
== rb_eRuntimeError
&& RSTRING(einfo
)->len
== 0) {
83 msg
= "unhandled exception";
89 epath
= rb_class_path(eclass
);
90 snprintf(buff
, MAX_STR_LEN
, "%s: %s",
91 RSTRING(epath
)->ptr
, RSTRING(einfo
)->ptr
);
93 p
= strchr((const char *)buff
, '\n');
99 snprintf(buff
, MAX_STR_LEN
, "unknown longjmp status %d", error
);
104 alert_ruby_error(ses
, msg
);
108 /* The ELinks module: */
110 /* Inspired by Vim this is used to hook into the stdout write method so written
111 * data is displayed in a nice message box. */
113 erb_module_message(VALUE self
, VALUE str
)
115 unsigned char *message
, *line_end
;
116 struct terminal
*term
;
118 str
= rb_obj_as_string(str
);
119 message
= memacpy(RSTRING(str
)->ptr
, RSTRING(str
)->len
);
120 if (!message
) return Qnil
;
122 line_end
= strchr((const char *)message
, '\n');
123 if (line_end
) *line_end
= '\0';
125 term
= get_default_terminal();
127 usrerror("[Ruby] %s", message
);
132 info_box(term
, MSGBOX_NO_TEXT_INTL
| MSGBOX_FREE_TEXT
,
133 N_("Ruby Message"), ALIGN_LEFT
, message
);
138 /* The global Kernel::p method will for each object, directly write
139 * object.inspect() followed by the current output record separator to the
140 * program's standard output and will bypass the Ruby I/O libraries.
142 * Inspired by Vim we hook into the method and pop up a nice message box so it
143 * can be used to easily debug scripts without dirtying the screen. */
145 erb_stdout_p(int argc
, VALUE
*argv
, VALUE self
)
148 struct string string
;
149 struct terminal
*term
;
151 if (!init_string(&string
))
154 for (i
= 0; i
< argc
; i
++) {
160 add_to_string(&string
, ", ");
162 substr
= rb_inspect(argv
[i
]);
164 /* The Ruby p() function writes variable number of objects using
165 * the inspect() method, which adds quotes to the strings, so
166 * gently ignore them. */
168 ptr
= RSTRING(substr
)->ptr
;
169 len
= RSTRING(substr
)->len
;
174 if (ptr
[len
- 1] == '"')
177 add_bytes_to_string(&string
, ptr
, len
);
180 term
= get_default_terminal();
182 usrerror("[Ruby] %s", string
.source
);
183 done_string(&string
);
187 info_box(term
, MSGBOX_NO_TEXT_INTL
| MSGBOX_FREE_TEXT
,
188 N_("Ruby Message"), ALIGN_LEFT
, string
.source
);
193 /* ELinks::method_missing() is a catch all method that will be called when a
194 * hook is not defined. It might not be so elegant but it removes NoMethodErrors
195 * from popping up. */
196 /* FIXME: It might be useful for user to actually display them to debug scripts,
197 * so maybe it should be optional. --jonas */
199 erb_module_method_missing(VALUE self
, VALUE arg
)
205 init_erb_module(void)
209 erb_module
= rb_define_module("ELinks");
210 rb_define_const(erb_module
, "VERSION", rb_str_new2(VERSION_STRING
));
212 home
= elinks_home
? elinks_home
: (unsigned char *) CONFDIR
;
213 rb_define_const(erb_module
, "HOME", rb_str_new2(home
));
215 rb_define_module_function(erb_module
, "message", erb_module_message
, 1);
216 rb_define_module_function(erb_module
, "method_missing", erb_module_method_missing
, -1);
217 rb_define_module_function(erb_module
, "p", erb_stdout_p
, -1);
222 init_ruby(struct module
*module
)
226 /* Set up and initialize the interpreter. This function should be called
227 * before any other Ruby-related functions. */
229 ruby_script("ELinks-ruby");
230 ruby_init_loadpath();
232 /* ``Trap'' debug prints from scripts. */
233 rb_define_singleton_method(rb_stdout
, "write", erb_module_message
, 1);
234 rb_define_global_function("p", erb_stdout_p
, -1);
236 /* Set up the ELinks module interface. */
240 path
= straconcat(elinks_home
, RUBY_HOOKS_FILENAME
,
241 (unsigned char *) NULL
);
244 path
= stracpy(CONFDIR STRING_DIR_SEP RUBY_HOOKS_FILENAME
);
249 if (file_can_read(path
)) {
252 /* Load ~/.elinks/hooks.rb into the interpreter. */
253 //rb_load_file(path);
254 rb_load_protect(rb_str_new2(path
), 0, &error
);
256 erb_report_error(NULL
, error
);