#include #include #include #include #include struct bshell_line_ed_core_p { bshell_line_ed_keybind *c_key_cursor_left; bshell_line_ed_keybind *c_key_cursor_right; bshell_line_ed_keybind *c_key_return; bshell_line_ed_keybind *c_key_eof; bshell_line_ed_keybind *c_key_generic; bshell_line_ed_keybind *c_key_backspace; fx_hashtable *c_data; }; static void init(fx_object *obj, void *priv) { struct bshell_line_ed_core_p *core = priv; core->c_data = fx_hashtable_create(); } static void fini(fx_object *obj, void *priv) { struct bshell_line_ed_core_p *core = priv; fx_hashtable_unref(core->c_data); } static struct bshell_line_ed_keybind_result delete_backward( bshell_line_ed *ed, fx_keycode key) { return BSHELL_LINE_EDITOR_KEYBIND_RESULT( BSHELL_SUCCESS, BSHELL_LINE_EDITOR_KEYBIND_CONTINUE); } static struct bshell_line_ed_keybind_result cursor_left( bshell_line_ed *ed, fx_keycode key) { bshell_line_ed_move_cursor(ed, -1); return BSHELL_LINE_EDITOR_KEYBIND_RESULT( BSHELL_SUCCESS, BSHELL_LINE_EDITOR_KEYBIND_CONTINUE); } static struct bshell_line_ed_keybind_result cursor_right( bshell_line_ed *ed, fx_keycode key) { bshell_line_ed_move_cursor(ed, 1); return BSHELL_LINE_EDITOR_KEYBIND_RESULT( BSHELL_SUCCESS, BSHELL_LINE_EDITOR_KEYBIND_CONTINUE); } static struct bshell_line_ed_keybind_result eof_key( bshell_line_ed *ed, fx_keycode key) { bshell_line_ed_set_eof(ed); return BSHELL_LINE_EDITOR_KEYBIND_RESULT( BSHELL_SUCCESS, BSHELL_LINE_EDITOR_KEYBIND_CONTINUE); } static struct bshell_line_ed_keybind_result return_key( bshell_line_ed *ed, fx_keycode key) { bshell_line_ed_set_done(ed); fx_string *buf = bshell_line_ed_get_buffer(ed); fx_string_append_c(buf, '\n'); return BSHELL_LINE_EDITOR_KEYBIND_RESULT( BSHELL_SUCCESS, BSHELL_LINE_EDITOR_KEYBIND_CONTINUE); } static struct bshell_line_ed_keybind_result backspace( bshell_line_ed *ed, fx_keycode key) { fx_string *buf = bshell_line_ed_get_buffer(ed); unsigned long cursor = bshell_line_ed_get_cursor(ed); if (cursor > 0) { fx_string_remove(buf, cursor - 1, 1); bshell_line_ed_move_cursor(ed, -1); bshell_line_ed_buffer_changed(ed); } return BSHELL_LINE_EDITOR_KEYBIND_RESULT( BSHELL_SUCCESS, BSHELL_LINE_EDITOR_KEYBIND_CONTINUE); } static struct bshell_line_ed_keybind_result generic_key( bshell_line_ed *ed, fx_keycode key) { fx_wchar c = key; bool valid = fx_wchar_utf8_is_valid_scalar(c) && fx_wchar_is_graph(c); if (valid) { fx_string *buf = bshell_line_ed_get_buffer(ed); unsigned long cursor = bshell_line_ed_get_cursor(ed); char cstr[5] = {0}; fx_string_insert_wc(buf, c, cursor); bshell_line_ed_move_cursor(ed, 1); bshell_line_ed_buffer_changed(ed); } return BSHELL_LINE_EDITOR_KEYBIND_RESULT( BSHELL_SUCCESS, BSHELL_LINE_EDITOR_KEYBIND_CONTINUE); } static enum bshell_status load( bshell_line_ed_plugin *plugin, bshell_line_ed *ed) { struct bshell_line_ed_core_p *core = fx_object_get_private(plugin, BSHELL_TYPE_LINE_EDITOR_CORE); core->c_key_eof = bshell_line_ed_bind_key(ed, "^d", eof_key, 100); core->c_key_cursor_left = bshell_line_ed_bind_key(ed, "left", cursor_left, 100); core->c_key_cursor_right = bshell_line_ed_bind_key(ed, "right", cursor_right, 100); core->c_key_cursor_right = bshell_line_ed_bind_key(ed, "return", return_key, 100); core->c_key_generic = bshell_line_ed_bind_key(ed, "*", generic_key, 100); core->c_key_backspace = bshell_line_ed_bind_key(ed, "backspace", backspace, 100); return BSHELL_SUCCESS; } static enum bshell_status render_prompt( bshell_line_ed_plugin *plugin, bshell_line_ed *ed) { fx_string *prompt = bshell_line_ed_get_prompt(ed); fx_tty *tty = bshell_line_ed_get_tty(ed); const char *s = fx_string_get_cstr(prompt); fx_tty_puts(tty, 0, s); return BSHELL_SUCCESS; } static enum bshell_status render_buffer( bshell_line_ed_plugin *plugin, bshell_line_ed *ed) { fx_string *buf = bshell_line_ed_get_buffer(ed); fx_tty *tty = bshell_line_ed_get_tty(ed); const char *s = fx_string_get_cstr(buf); for (unsigned long i = 0; *s; i++) { fx_wchar c = fx_wchar_utf8_codepoint_decode(s); unsigned int stride = fx_wchar_utf8_codepoint_size(c); if (stride == 0) { break; } char cs[5] = {0}; fx_wchar_utf8_codepoint_encode(c, cs); fx_tty_puts(tty, 0, cs); s += stride; } return BSHELL_SUCCESS; } static enum bshell_status get_data( bshell_line_ed_plugin *plugin, bshell_line_ed *ed, const char *key, fx_value *out) { struct bshell_line_ed_core_p *core = fx_object_get_private(plugin, BSHELL_TYPE_LINE_EDITOR_CORE); const fx_value *v = fx_hashtable_get(core->c_data, &FX_CSTR(key)); if (v) { fx_value_copy(out, v); } else { *out = FX_VALUE_EMPTY; } return BSHELL_SUCCESS; } static enum bshell_status put_data( bshell_line_ed_plugin *plugin, bshell_line_ed *ed, const char *key, const fx_value *value) { struct bshell_line_ed_core_p *core = fx_object_get_private(plugin, BSHELL_TYPE_LINE_EDITOR_CORE); fx_hashtable_put(core->c_data, &FX_CSTR(key), (fx_value *)value); return BSHELL_SUCCESS; } FX_TYPE_CLASS_BEGIN(bshell_line_ed_core) FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) FX_INTERFACE_ENTRY(to_string) = NULL; FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT) FX_TYPE_VTABLE_INTERFACE_BEGIN( bshell_line_ed_plugin, BSHELL_TYPE_LINE_EDITOR_PLUGIN) FX_INTERFACE_ENTRY(p_load) = load; FX_INTERFACE_ENTRY(p_render_prompt) = render_prompt; FX_INTERFACE_ENTRY(p_render_buffer) = render_buffer; FX_INTERFACE_ENTRY(p_get_data) = get_data; FX_INTERFACE_ENTRY(p_put_data) = put_data; FX_TYPE_VTABLE_INTERFACE_END(bshell_command, BSHELL_TYPE_COMMAND) FX_TYPE_CLASS_END(bshell_line_ed_core) FX_TYPE_DEFINITION_BEGIN(bshell_line_ed_core) FX_TYPE_ID(0xf5174a63, 0x8fe4, 0x4720, 0xa861, 0x4ebb0d170dd3); FX_TYPE_NAME("bshell.runtime.line_editor.plugins.core"); FX_TYPE_EXTENDS(BSHELL_TYPE_LINE_EDITOR_PLUGIN); FX_TYPE_CLASS(bshell_line_ed_core_class); FX_TYPE_INSTANCE_INIT(init); FX_TYPE_INSTANCE_FINI(fini); FX_TYPE_INSTANCE_PRIVATE(struct bshell_line_ed_core_p); FX_TYPE_DEFINITION_END(bshell_line_ed_core)