Add completion styling

Readline has a styling feature for completion -- if it is enabled, the
common prefix of completions will be displayed in a different style.
This doesn't work in gdb, because gdb implements its own completer.

This patch implements the feature.  However, it doesn't directly use
the Readline feature, because gdb can do a bit better: it can let the
user control the styling using the existing mechanisms.

This version incorporates an Emacs idea, via Eli: style the prefix,
the "difference character", and the suffix differently.

gdb/ChangeLog
2020-05-23  Tom Tromey  <tom@tromey.com>

	* NEWS: Add entry for completion styling.
	* completer.c (_rl_completion_prefix_display_length): Move
	declaration earlier.
	(gdb_fnprint): Use completion_style.
	(gdb_display_match_list_1): Likewise.
	* cli/cli-style.c (completion_prefix_style)
	(completion_difference_style, completion_suffix_style): New
	globals.
	(_initialize_cli_style): Register new globals.
	* cli/cli-style.h (completion_prefix_style)
	(completion_difference_style, completion_suffix_style): Declare.

gdb/doc/ChangeLog
2020-05-23  Tom Tromey  <tom@tromey.com>

	* gdb.texinfo (Output Styling): Mention completion styling.
	(Editing): Mention readline completion styling.

gdb/testsuite/ChangeLog
2020-05-23  Tom Tromey  <tom@tromey.com>

	* gdb.base/style.exp: Add completion styling test.
	* lib/gdb-utils.exp (style): Add completion styles.
This commit is contained in:
Tom Tromey 2020-05-23 09:23:09 -06:00
parent 51e2cfa2dc
commit eca1f90cf4
10 changed files with 172 additions and 7 deletions

View File

@ -1,3 +1,17 @@
2020-05-23 Tom Tromey <tom@tromey.com>
* NEWS: Add entry for completion styling.
* completer.c (_rl_completion_prefix_display_length): Move
declaration earlier.
(gdb_fnprint): Use completion_style.
(gdb_display_match_list_1): Likewise.
* cli/cli-style.c (completion_prefix_style)
(completion_difference_style, completion_suffix_style): New
globals.
(_initialize_cli_style): Register new globals.
* cli/cli-style.h (completion_prefix_style)
(completion_difference_style, completion_suffix_style): Declare.
2020-05-23 Pedro Alves <palves@redhat.com> 2020-05-23 Pedro Alves <palves@redhat.com>
* utils.c: Include "gdbsupport/gdb-safe-ctype.h". * utils.c: Include "gdbsupport/gdb-safe-ctype.h".

View File

@ -62,6 +62,17 @@ show exec-file-mismatch -- Show exec-file-mismatch handling (ask|warn|off).
executable file; if 'warn', just display a warning; if 'off', don't executable file; if 'warn', just display a warning; if 'off', don't
attempt to detect a mismatch. attempt to detect a mismatch.
set style completion-prefix foreground COLOR
set style completion-prefix background COLOR
set style completion-prefix intensity VALUE
set style completion-difference foreground COLOR
set style completion-difference background COLOR
set style completion-difference intensity VALUE
set style completion-suffix foreground COLOR
set style completion-suffix background COLOR
set style completion-suffix intensity VALUE
Control the styling of completions.
tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]... tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...
Define a new TUI layout, specifying its name and the windows that Define a new TUI layout, specifying its name and the windows that
will be displayed. will be displayed.

View File

@ -98,6 +98,21 @@ cli_style_option metadata_style ("metadata", ui_file_style::DIM);
/* See cli-style.h. */ /* See cli-style.h. */
cli_style_option completion_prefix_style ("completion-prefix",
ui_file_style::DIM);
/* See cli-style.h. */
cli_style_option completion_difference_style ("completion-difference",
ui_file_style::MAGENTA);
/* See cli-style.h. */
cli_style_option completion_suffix_style ("completion-suffix",
ui_file_style::NONE);
/* See cli-style.h. */
cli_style_option::cli_style_option (const char *name, cli_style_option::cli_style_option (const char *name,
ui_file_style::basic_color fg) ui_file_style::basic_color fg)
: changed (name), : changed (name),
@ -366,6 +381,33 @@ your data, for example \"<unavailable>\""),
&style_set_list, &style_show_list, &style_set_list, &style_show_list,
false); false);
completion_prefix_style.add_setshow_commands (no_class, _("\
Completion prefix display styling.\n\
Configure completion prefix colors and display intensity\n\
The \"completion-prefix\" style is used when GDB displays the shared\n\
prefix common to the possible completions."),
&style_set_list,
&style_show_list,
false);
completion_difference_style.add_setshow_commands (no_class, _("\
Completion difference display styling.\n\
Configure completion difference colors and display intensity\n\
The \"completion-difference\" style is used when GDB displays the\n\
character that differs between the possible completions."),
&style_set_list,
&style_show_list,
false);
completion_suffix_style.add_setshow_commands (no_class, _("\
Completion suffix display styling.\n\
Configure completion suffix colors and display intensity\n\
The \"completion-suffix\" style is used when GDB displays the suffix\n\
of the possible completions."),
&style_set_list,
&style_show_list,
false);
tui_border_style.add_setshow_commands (no_class, _("\ tui_border_style.add_setshow_commands (no_class, _("\
TUI border display styling.\n\ TUI border display styling.\n\
Configure TUI border colors\n\ Configure TUI border colors\n\

View File

@ -124,6 +124,15 @@ extern cli_style_option tui_border_style;
/* The border style of a TUI window that does have the focus. */ /* The border style of a TUI window that does have the focus. */
extern cli_style_option tui_active_border_style; extern cli_style_option tui_active_border_style;
/* The style for the common prefix of completions. */
extern cli_style_option completion_prefix_style;
/* The style for the difference character of completions. */
extern cli_style_option completion_difference_style;
/* The style for the suffix of completions. */
extern cli_style_option completion_suffix_style;
/* True if source styling is enabled. */ /* True if source styling is enabled. */
extern bool source_styling; extern bool source_styling;

View File

@ -31,6 +31,7 @@
#include <algorithm> #include <algorithm>
#include "linespec.h" #include "linespec.h"
#include "cli/cli-decode.h" #include "cli/cli-decode.h"
#include "cli/cli-style.h"
/* FIXME: This is needed because of lookup_cmd_1 (). We should be /* FIXME: This is needed because of lookup_cmd_1 (). We should be
calling a hook instead so we eliminate the CLI dependency. */ calling a hook instead so we eliminate the CLI dependency. */
@ -2714,6 +2715,8 @@ gdb_fnwidth (const char *string)
return width; return width;
} }
extern int _rl_completion_prefix_display_length;
/* Print TO_PRINT, one matching completion. /* Print TO_PRINT, one matching completion.
PREFIX_BYTES is number of common prefix bytes. PREFIX_BYTES is number of common prefix bytes.
Based on readline/complete.c:fnprint. */ Based on readline/complete.c:fnprint. */
@ -2722,7 +2725,7 @@ static int
gdb_fnprint (const char *to_print, int prefix_bytes, gdb_fnprint (const char *to_print, int prefix_bytes,
const struct match_list_displayer *displayer) const struct match_list_displayer *displayer)
{ {
int printed_len, w; int common_prefix_len, printed_len, w;
const char *s; const char *s;
#if defined (HANDLE_MULTIBYTE) #if defined (HANDLE_MULTIBYTE)
mbstate_t ps; mbstate_t ps;
@ -2735,14 +2738,18 @@ gdb_fnprint (const char *to_print, int prefix_bytes,
memset (&ps, 0, sizeof (mbstate_t)); memset (&ps, 0, sizeof (mbstate_t));
#endif #endif
printed_len = 0; printed_len = common_prefix_len = 0;
/* Don't print only the ellipsis if the common prefix is one of the /* Don't print only the ellipsis if the common prefix is one of the
possible completions */ possible completions */
if (to_print[prefix_bytes] == '\0') if (to_print[prefix_bytes] == '\0')
prefix_bytes = 0; prefix_bytes = 0;
if (prefix_bytes) ui_file_style style = completion_prefix_style.style ();
if (!style.is_default ())
displayer->puts (displayer, style.to_ansi ().c_str ());
if (prefix_bytes && _rl_completion_prefix_display_length > 0)
{ {
char ellipsis; char ellipsis;
@ -2751,6 +2758,16 @@ gdb_fnprint (const char *to_print, int prefix_bytes,
displayer->putch (displayer, ellipsis); displayer->putch (displayer, ellipsis);
printed_len = ELLIPSIS_LEN; printed_len = ELLIPSIS_LEN;
} }
else if (prefix_bytes && !style.is_default ())
{
common_prefix_len = prefix_bytes;
prefix_bytes = 0;
}
/* There are 3 states: the initial state (#0), when we use the
prefix style; the difference state (#1), which lasts a single
character; and then the suffix state (#2). */
int state = 0;
s = to_print + prefix_bytes; s = to_print + prefix_bytes;
while (*s) while (*s)
@ -2802,8 +2819,31 @@ gdb_fnprint (const char *to_print, int prefix_bytes,
printed_len++; printed_len++;
#endif #endif
} }
if (common_prefix_len > 0 && (s - to_print) >= common_prefix_len)
{
if (!style.is_default ())
displayer->puts (displayer, ui_file_style ().to_ansi ().c_str ());
++state;
if (state == 1)
{
common_prefix_len = 1;
style = completion_difference_style.style ();
}
else
{
common_prefix_len = 0;
style = completion_suffix_style.style ();
}
if (!style.is_default ())
displayer->puts (displayer, style.to_ansi ().c_str ());
}
} }
if (!style.is_default ())
displayer->puts (displayer, ui_file_style ().to_ansi ().c_str ());
return printed_len; return printed_len;
} }
@ -2912,7 +2952,6 @@ gdb_complete_get_screenwidth (const struct match_list_displayer *displayer)
return displayer->width; return displayer->width;
} }
extern int _rl_completion_prefix_display_length;
extern int _rl_print_completions_horizontally; extern int _rl_print_completions_horizontally;
EXTERN_C int _rl_qsort_string_compare (const void *, const void *); EXTERN_C int _rl_qsort_string_compare (const void *, const void *);
@ -2931,19 +2970,23 @@ gdb_display_match_list_1 (char **matches, int len, int max,
char *temp, *t; char *temp, *t;
int page_completions = displayer->height != INT_MAX && pagination_enabled; int page_completions = displayer->height != INT_MAX && pagination_enabled;
bool want_style = !completion_prefix_style.style ().is_default ();
/* Find the length of the prefix common to all items: length as displayed /* Find the length of the prefix common to all items: length as displayed
characters (common_length) and as a byte index into the matches (sind) */ characters (common_length) and as a byte index into the matches (sind) */
common_length = sind = 0; common_length = sind = 0;
if (_rl_completion_prefix_display_length > 0) if (_rl_completion_prefix_display_length > 0 || want_style)
{ {
t = gdb_printable_part (matches[0]); t = gdb_printable_part (matches[0]);
temp = strrchr (t, '/'); temp = strrchr (t, '/');
common_length = temp ? gdb_fnwidth (temp) : gdb_fnwidth (t); common_length = temp ? gdb_fnwidth (temp) : gdb_fnwidth (t);
sind = temp ? strlen (temp) : strlen (t); sind = temp ? strlen (temp) : strlen (t);
if (common_length > _rl_completion_prefix_display_length && common_length > ELLIPSIS_LEN) if (_rl_completion_prefix_display_length > 0
&& common_length > _rl_completion_prefix_display_length
&& common_length > ELLIPSIS_LEN)
max -= common_length - ELLIPSIS_LEN; max -= common_length - ELLIPSIS_LEN;
else else if (!want_style || common_length > max || sind > max)
common_length = sind = 0; common_length = sind = 0;
} }

View File

@ -1,3 +1,8 @@
2020-05-23 Tom Tromey <tom@tromey.com>
* gdb.texinfo (Output Styling): Mention completion styling.
(Editing): Mention readline completion styling.
2020-05-19 Pedro Alves <palves@redhat.com> 2020-05-19 Pedro Alves <palves@redhat.com>
* gdb.texinfo (Attach): Update exec-file-mismatch description to * gdb.texinfo (Attach): Update exec-file-mismatch description to

View File

@ -25271,6 +25271,10 @@ This command accepts the current line for execution and fetches the
next line relative to the current line from the history for editing. next line relative to the current line from the history for editing.
Any argument is ignored. Any argument is ignored.
Note that @value{GDBN} ignores the Readline
@code{colored-completion-prefix} setting. Instead, this is handled
using the style settings (@xref{Output Styling}).
@node Command History @node Command History
@section Command History @section Command History
@cindex command history @cindex command history
@ -25604,6 +25608,22 @@ general styling to @value{GDBN}. @xref{TUI Configuration}.
Control the styling of the active TUI border; that is, the TUI window Control the styling of the active TUI border; that is, the TUI window
that has the focus. that has the focus.
@item completion-prefix
Control the styling of the completion prefix. When completing, the
common prefix of completion candidates will be shown with this style.
By default, this style's intensity is dim.
@item completion-difference
Control the styling of the completion difference character. When
completing, the character that differs between different completions
will be shown using this style. By default, this style's foreground
color is magenta.
@item completion-suffix
Control the styling of the completion suffix. When completing, the
suffix of completion candidates will be shown with this style. By
default, this style is the same as the default styling.
@end table @end table
@node Numbers @node Numbers

View File

@ -1,3 +1,8 @@
2020-05-23 Tom Tromey <tom@tromey.com>
* gdb.base/style.exp: Add completion styling test.
* lib/gdb-utils.exp (style): Add completion styles.
2020-05-22 Andrew Burgess <andrew.burgess@embecosm.com> 2020-05-22 Andrew Burgess <andrew.burgess@embecosm.com>
* gdb.base/annota1.exp: Update expected results. * gdb.base/annota1.exp: Update expected results.

View File

@ -167,4 +167,18 @@ save_vars { env(TERM) } {
"warning: [style .*? file] is not a directory\\..*" "warning: [style .*? file] is not a directory\\..*"
gdb_test "show data-directory" \ gdb_test "show data-directory" \
"GDB's data directory is \"[style .*? file]\"\\..*" "GDB's data directory is \"[style .*? file]\"\\..*"
if {[readline_is_used]} {
set test "complete print VALUE_"
# ESC-? is the readline binding to show all completions.
send_gdb "print VALUE_\x1b?"
set pfx [style VALUE_ completion-prefix]
set d1 [style O completion-difference]
set d2 [style T completion-difference]
gdb_test_multiple "" $test {
-re "${pfx}${d1}NE\[ \t\]+${pfx}${d2}WO.*$gdb_prompt print VALUE_$" {
gdb_test "ONE" " = .*"
}
}
}
} }

View File

@ -55,6 +55,8 @@ proc style {str style} {
variable { set style 36 } variable { set style 36 }
address { set style 34 } address { set style 34 }
metadata { set style 2 } metadata { set style 2 }
completion-prefix { set style 2 }
completion-difference { set style 35 }
} }
return "\033\\\[${style}m${str}\033\\\[m" return "\033\\\[${style}m${str}\033\\\[m"
} }