mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-21 04:42:53 +08:00
7d793aa9f0
This PR came from a Red Hat bug that was filed recently. I checked and it still exists on HEAD, so here's a proposed fix. Although this is marked as a Python backend bug, this is really about the completion mechanism used by GDB. Since this code reminds me of my first attempt to make a good noodle, it took me quite some time to fix it in a non-intrusive way. The problem is triggered when one registers a completion method inside a class in a Python script, rather than registering the command using a completer class directly. For example, consider the following script: class MyFirstCommand(gdb.Command): def __init__(self): gdb.Command.__init__(self,'myfirstcommand',gdb.COMMAND_USER,gdb.COMPLETE_FILENAME) def invoke(self,argument,from_tty): raise gdb.GdbError('not implemented') class MySecondCommand(gdb.Command): def __init__(self): gdb.Command.__init__(self,'mysecondcommand',gdb.COMMAND_USER) def invoke(self,argument,from_tty): raise gdb.GdbError('not implemented') def complete(self,text,word): return gdb.COMPLETE_FILENAME MyFirstCommand () MySecondCommand () When one loads this into GDB and tries to complete filenames for both myfirstcommand and mysecondcommand, she gets: (gdb) myfirstcommand /hom<TAB> (gdb) myfirstcommand /home/ ^ ... (gdb) mysecondcommand /hom<TAB> (gdb) mysecondcommand /home ^ (The "^" marks the final position of the cursor after the TAB). So we see that myfirstcommand honors the COMPLETE_FILENAME class (as specified in the command creation), but mysecondcommand does not. After some investigation, I found that the problem lies with the set of word break characters that is used for each case. The set should be the same for both commands, but it is not. During the process of deciding which type of completion should be used, the code in gdb/completer.c:complete_line_internal analyses the command that requested the completion and tries to determine the type of completion wanted by checking which completion function will be called (e.g., filename_completer for filenames, location_completer for locations, etc.). This all works fine for myfirstcommand, because immediately after the command registration the Python backend already sets its completion function to filename_completer (which then causes the complete_line_internal function to choose the right set of word break chars). However, for mysecondcommand, this decision is postponed to when the completer function is evaluated, and the Python backend uses an internal completer (called cmdpy_completer). complete_line_internal doesn't know about this internal completer, and can't choose the right set of word break chars in time, which then leads to a bad decision when completing the "/hom" word. So, after a few attempts, I decided to create another callback in "struct cmd_list_element" that will be responsible for handling the case when there is an unknown completer function for complete_line_internal to work with. So far, only the Python backend uses this callback, and only when the user provides a completer method instead of registering the command directly with a completer class. I think this is the best option because it not very intrusive (all the other commands will still work normally), but especially because the whole completion code is so messy that it would be hard to fix this without having to redesign things. I have regtested this on Fedora 18 x86_64, without regressions. I also included a testcase. gdb/ChangeLog: 2014-09-03 Sergio Durigan Junior <sergiodj@redhat.com> PR python/16699 * cli/cli-decode.c (set_cmd_completer_handle_brkchars): New function. (add_cmd): Set "completer_handle_brkchars" to NULL. * cli/cli-decode.h (struct cmd_list_element) <completer_handle_brkchars>: New field. * command.h (completer_ftype_void): New typedef. (set_cmd_completer_handle_brkchars): New prototype. * completer.c (set_gdb_completion_word_break_characters): New function. (complete_line_internal): Call "completer_handle_brkchars" callback from command. * completer.h: Include "command.h". (set_gdb_completion_word_break_characters): New prototype. * python/py-cmd.c (cmdpy_completer_helper): New function. (cmdpy_completer_handle_brkchars): New function. (cmdpy_completer): Adjust to use cmdpy_completer_helper. (cmdpy_init): Set completer_handle_brkchars to cmdpy_completer_handle_brkchars. gdb/testsuite/ChangeLog: 2014-09-03 Sergio Durigan Junior <sergiodj@redhat.com> PR python/16699 * gdb.python/py-completion.exp: New file. * gdb.python/py-completion.py: Likewise.
67 lines
2.3 KiB
C
67 lines
2.3 KiB
C
/* Header for GDB line completion.
|
|
Copyright (C) 2000-2014 Free Software Foundation, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#if !defined (COMPLETER_H)
|
|
#define COMPLETER_H 1
|
|
|
|
#include "gdb_vecs.h"
|
|
#include "command.h"
|
|
|
|
extern VEC (char_ptr) *complete_line (const char *text,
|
|
const char *line_buffer,
|
|
int point);
|
|
|
|
extern char *readline_line_completion_function (const char *text,
|
|
int matches);
|
|
|
|
extern VEC (char_ptr) *noop_completer (struct cmd_list_element *,
|
|
const char *, const char *);
|
|
|
|
extern VEC (char_ptr) *filename_completer (struct cmd_list_element *,
|
|
const char *, const char *);
|
|
|
|
extern VEC (char_ptr) *expression_completer (struct cmd_list_element *,
|
|
const char *, const char *);
|
|
|
|
extern VEC (char_ptr) *location_completer (struct cmd_list_element *,
|
|
const char *, const char *);
|
|
|
|
extern VEC (char_ptr) *command_completer (struct cmd_list_element *,
|
|
const char *, const char *);
|
|
|
|
extern VEC (char_ptr) *signal_completer (struct cmd_list_element *,
|
|
const char *, const char *);
|
|
|
|
extern char *get_gdb_completer_quote_characters (void);
|
|
|
|
extern char *gdb_completion_word_break_characters (void);
|
|
|
|
/* Set the word break characters array to the corresponding set of
|
|
chars, based on FN. This function is useful for cases when the
|
|
completer doesn't know the type of the completion until some
|
|
calculation is done (e.g., for Python functions). */
|
|
|
|
extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
|
|
|
|
/* Exported to linespec.c */
|
|
|
|
extern const char *skip_quoted_chars (const char *, const char *,
|
|
const char *);
|
|
|
|
extern const char *skip_quoted (const char *);
|
|
|
|
#endif /* defined (COMPLETER_H) */
|