diff options
Diffstat (limited to 'gdb/python/py-cmd.c')
-rw-r--r-- | gdb/python/py-cmd.c | 176 |
1 files changed, 148 insertions, 28 deletions
diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c index 21f2a20..8bc4bf7 100644 --- a/gdb/python/py-cmd.c +++ b/gdb/python/py-cmd.c @@ -208,45 +208,163 @@ cmdpy_function (struct cmd_list_element *command, char *args, int from_tty) do_cleanups (cleanup); } +/* Helper function for the Python command completers (both "pure" + completer and brkchar handler). This function takes COMMAND, TEXT + and WORD and tries to call the Python method for completion with + these arguments. It also takes HANDLE_BRKCHARS_P, an argument to + identify whether it is being called from the brkchar handler or + from the "pure" completer. In the first case, it effectively calls + the Python method for completion, and records the PyObject in a + static variable (used as a "cache"). In the second case, it just + returns that variable, without actually calling the Python method + again. This saves us one Python method call. + + The reason for this two step dance is that we need to know the set + of "brkchars" to use early on, before we actually try to perform + the completion. But if a Python command supplies a "complete" + method then we have to call that method first: it may return as its + result the kind of completion to perform and that will in turn + specify which brkchars to use. IOW, we need the result of the + "complete" method before we actually perform the completion. + + It is important to mention that this function is built on the + assumption that the calls to cmdpy_completer_handle_brkchars and + cmdpy_completer will be subsequent with nothing intervening. This + is true for our completer mechanism. + + This function returns the PyObject representing the Python method + call. */ + +static PyObject * +cmdpy_completer_helper (struct cmd_list_element *command, + const char *text, const char *word, + int handle_brkchars_p) +{ + cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command); + PyObject *textobj, *wordobj; + /* This static variable will server as a "cache" for us, in order to + store the PyObject that results from calling the Python + function. */ + static PyObject *resultobj = NULL; + + if (handle_brkchars_p) + { + /* If we were called to handle brkchars, it means this is the + first function call of two that will happen in a row. + Therefore, we need to call the completer ourselves, and cache + the return value in the static variable RESULTOBJ. Then, in + the second call, we can just use the value of RESULTOBJ to do + our job. */ + if (resultobj != NULL) + Py_DECREF (resultobj); + + resultobj = NULL; + if (obj == NULL) + error (_("Invalid invocation of Python command object.")); + if (!PyObject_HasAttr ((PyObject *) obj, complete_cst)) + { + /* If there is no complete method, don't error. */ + return NULL; + } + + textobj = PyUnicode_Decode (text, strlen (text), host_charset (), NULL); + if (textobj == NULL) + error (_("Could not convert argument to Python string.")); + wordobj = PyUnicode_Decode (word, sizeof (word), host_charset (), NULL); + if (wordobj == NULL) + { + Py_DECREF (textobj); + error (_("Could not convert argument to Python string.")); + } + + resultobj = PyObject_CallMethodObjArgs ((PyObject *) obj, complete_cst, + textobj, wordobj, NULL); + Py_DECREF (textobj); + Py_DECREF (wordobj); + if (!resultobj) + { + /* Just swallow errors here. */ + PyErr_Clear (); + } + + Py_XINCREF (resultobj); + } + + return resultobj; +} + +/* Python function called to determine the break characters of a + certain completer. We are only interested in knowing if the + completer registered by the user will return one of the integer + codes (see COMPLETER_* symbols). */ + +static void +cmdpy_completer_handle_brkchars (struct cmd_list_element *command, + const char *text, const char *word) +{ + PyObject *resultobj = NULL; + struct cleanup *cleanup; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + /* Calling our helper to obtain the PyObject of the Python + function. */ + resultobj = cmdpy_completer_helper (command, text, word, 1); + + /* Check if there was an error. */ + if (resultobj == NULL) + goto done; + + if (PyInt_Check (resultobj)) + { + /* User code may also return one of the completion constants, + thus requesting that sort of completion. We are only + interested in this kind of return. */ + long value; + + if (!gdb_py_int_as_long (resultobj, &value)) + { + /* Ignore. */ + PyErr_Clear (); + } + else if (value >= 0 && value < (long) N_COMPLETERS) + { + /* This is the core of this function. Depending on which + completer type the Python function returns, we have to + adjust the break characters accordingly. */ + set_gdb_completion_word_break_characters + (completers[value].completer); + } + } + + done: + + /* We do not call Py_XDECREF here because RESULTOBJ will be used in + the subsequent call to cmdpy_completer function. */ + do_cleanups (cleanup); +} + /* Called by gdb for command completion. */ static VEC (char_ptr) * cmdpy_completer (struct cmd_list_element *command, const char *text, const char *word) { - cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command); - PyObject *textobj, *wordobj, *resultobj = NULL; + PyObject *resultobj = NULL; VEC (char_ptr) *result = NULL; struct cleanup *cleanup; cleanup = ensure_python_env (get_current_arch (), current_language); - if (! obj) - error (_("Invalid invocation of Python command object.")); - if (! PyObject_HasAttr ((PyObject *) obj, complete_cst)) - { - /* If there is no complete method, don't error -- instead, just - say that there are no completions. */ - goto done; - } + /* Calling our helper to obtain the PyObject of the Python + function. */ + resultobj = cmdpy_completer_helper (command, text, word, 0); - textobj = PyUnicode_Decode (text, strlen (text), host_charset (), NULL); - if (! textobj) - error (_("Could not convert argument to Python string.")); - wordobj = PyUnicode_Decode (word, strlen (word), host_charset (), NULL); - if (! wordobj) - error (_("Could not convert argument to Python string.")); - - resultobj = PyObject_CallMethodObjArgs ((PyObject *) obj, complete_cst, - textobj, wordobj, NULL); - Py_DECREF (textobj); - Py_DECREF (wordobj); - if (! resultobj) - { - /* Just swallow errors here. */ - PyErr_Clear (); - goto done; - } + /* If the result object of calling the Python function is NULL, it + means that there was an error. In this case, just give up and + return NULL. */ + if (resultobj == NULL) + goto done; result = NULL; if (PyInt_Check (resultobj)) @@ -302,7 +420,6 @@ cmdpy_completer (struct cmd_list_element *command, done: - Py_XDECREF (resultobj); do_cleanups (cleanup); return result; @@ -548,6 +665,9 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw) set_cmd_context (cmd, self); set_cmd_completer (cmd, ((completetype == -1) ? cmdpy_completer : completers[completetype].completer)); + if (completetype == -1) + set_cmd_completer_handle_brkchars (cmd, + cmdpy_completer_handle_brkchars); } if (except.reason < 0) { |