diff --git a/builtin/readline_osh.py b/builtin/readline_osh.py index 283fb526c..5db239e91 100644 --- a/builtin/readline_osh.py +++ b/builtin/readline_osh.py @@ -125,9 +125,7 @@ def Run(self, cmd_val): readline.unbind_rl_function(arg.u) if arg.r: - self.errfmt.Print_("warning: bind -r isn't implemented", - blame_loc=cmd_val.arg_locs[0]) - return 1 + readline.unbind_keyseq(arg.r) if arg.x: self.errfmt.Print_("warning: bind -x isn't implemented", diff --git a/frontend/py_readline.py b/frontend/py_readline.py index 8a8013ba5..a1b22c13e 100644 --- a/frontend/py_readline.py +++ b/frontend/py_readline.py @@ -133,6 +133,10 @@ def restore_orig_keymap(self): def print_shell_cmd_map(self): # type: () -> None line_input.print_shell_cmd_map() + + def unbind_keyseq(self, keyseq): + # type: (str) -> None + line_input.unbind_keyseq(keyseq) def MaybeGetReadline(): diff --git a/pyext/line_input.c b/pyext/line_input.c index 1a8719ab5..4ebce53df 100644 --- a/pyext/line_input.c +++ b/pyext/line_input.c @@ -919,10 +919,10 @@ Unbind all keys bound to the named readline function in the current keymap."); static PyObject* unbind_shell_cmd(PyObject *self, PyObject *args) { - char *kseq; + char *keyseq; Keymap cmd_map; - if (!PyArg_ParseTuple(args, "s:unbind_shell_cmd", &kseq)) + if (!PyArg_ParseTuple(args, "s:unbind_shell_cmd", &keyseq)) return NULL; cmd_map = _get_associated_cmd_map(rl_get_keymap()); @@ -931,8 +931,8 @@ unbind_shell_cmd(PyObject *self, PyObject *args) return NULL; } - if (rl_bind_keyseq_in_map(kseq, (rl_command_func_t *)NULL, cmd_map) != 0) { - PyErr_Format(PyExc_ValueError, "'%s': can't unbind from shell command keymap", kseq); + if (rl_bind_keyseq_in_map(keyseq, (rl_command_func_t *)NULL, cmd_map) != 0) { + PyErr_Format(PyExc_ValueError, "'%s': can't unbind from shell command keymap", keyseq); return NULL; } @@ -969,6 +969,56 @@ PyDoc_STRVAR(doc_print_shell_cmd_map, Print all bindings for shell commands in the current keymap."); +/* Remove all bindings for a given keyseq */ + +static PyObject* +unbind_keyseq(PyObject *self, PyObject *args) +{ + char *seq, *keyseq; + int kslen, type; + rl_command_func_t *fn; + + if (!PyArg_ParseTuple(args, "s:unbind_keyseq", &seq)) + return NULL; + + keyseq = (char *)malloc((2 * strlen(seq)) + 1); + if (rl_translate_keyseq(seq, keyseq, &kslen) != 0) { + free(keyseq); + PyErr_Format(PyExc_ValueError, "'%s': cannot translate key sequence", seq); + return NULL; + } + + fn = rl_function_of_keyseq_len(keyseq, kslen, (Keymap)NULL, &type); + if (!fn) { + free(keyseq); + Py_RETURN_NONE; + } + + if (type == ISKMAP) { + fn = ((Keymap)fn)[ANYOTHERKEY].function; + } + + if (rl_bind_keyseq(seq, (rl_command_func_t *)NULL) != 0) { + free(keyseq); + PyErr_Format(PyExc_ValueError, "'%s': cannot unbind", seq); + return NULL; + } + + /* + TODO: Handle shell command unbinding if f == bash_execute_unix_command or + rather, whatever the osh equivalent will be + */ + + free(keyseq); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(doc_unbind_keyseq, +"unbind_keyseq(sequence) -> None\n\ +Unbind a key sequence from the current keymap."); + + + /* Keymap toggling code */ @@ -1073,6 +1123,7 @@ static struct PyMethodDef readline_methods[] = { {"restore_orig_keymap", restore_orig_keymap, METH_NOARGS, doc_restore_orig_keymap}, {"unbind_shell_cmd", unbind_shell_cmd, METH_VARARGS, doc_unbind_shell_cmd}, {"print_shell_cmd_map", print_shell_cmd_map, METH_NOARGS, doc_print_shell_cmd_map}, + {"unbind_keyseq", unbind_keyseq, METH_VARARGS, doc_unbind_keyseq}, {0, 0} }; #endif diff --git a/pyext/line_input.pyi b/pyext/line_input.pyi index 604c0994c..4061f6859 100644 --- a/pyext/line_input.pyi +++ b/pyext/line_input.pyi @@ -52,3 +52,6 @@ def use_temp_keymap(keymap_name: str) -> None: ... def restore_orig_keymap() -> None: ... def print_shell_cmd_map() -> None: ... + +def unbind_keyseq(keyseq: str) -> None: ... +