1/* CLI colorizing
2
3   Copyright (C) 2018-2020 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20#include "defs.h"
21#include "cli/cli-cmds.h"
22#include "cli/cli-style.h"
23#include "source-cache.h"
24#include "observable.h"
25
26/* True if styling is enabled.  */
27
28#if defined (__MSDOS__)
29bool cli_styling = false;
30#else
31bool cli_styling = true;
32#endif
33
34/* True if source styling is enabled.  Note that this is only
35   consulted when cli_styling is true.  */
36
37bool source_styling = true;
38
39/* Name of colors; must correspond to ui_file_style::basic_color.  */
40static const char * const cli_colors[] = {
41  "none",
42  "black",
43  "red",
44  "green",
45  "yellow",
46  "blue",
47  "magenta",
48  "cyan",
49  "white",
50  nullptr
51};
52
53/* Names of intensities; must correspond to
54   ui_file_style::intensity.  */
55static const char * const cli_intensities[] = {
56  "normal",
57  "bold",
58  "dim",
59  nullptr
60};
61
62/* See cli-style.h.  */
63
64cli_style_option file_name_style ("filename", ui_file_style::GREEN);
65
66/* See cli-style.h.  */
67
68cli_style_option function_name_style ("function", ui_file_style::YELLOW);
69
70/* See cli-style.h.  */
71
72cli_style_option variable_name_style ("variable", ui_file_style::CYAN);
73
74/* See cli-style.h.  */
75
76cli_style_option address_style ("address", ui_file_style::BLUE);
77
78/* See cli-style.h.  */
79
80cli_style_option highlight_style ("highlight", ui_file_style::RED);
81
82/* See cli-style.h.  */
83
84cli_style_option title_style ("title", ui_file_style::BOLD);
85
86/* See cli-style.h.  */
87
88cli_style_option tui_border_style ("tui-border", ui_file_style::CYAN);
89
90/* See cli-style.h.  */
91
92cli_style_option tui_active_border_style ("tui-active-border",
93					  ui_file_style::CYAN);
94
95/* See cli-style.h.  */
96
97cli_style_option metadata_style ("metadata", ui_file_style::DIM);
98
99/* See cli-style.h.  */
100
101cli_style_option::cli_style_option (const char *name,
102				    ui_file_style::basic_color fg)
103  : changed (name),
104    m_name (name),
105    m_foreground (cli_colors[fg - ui_file_style::NONE]),
106    m_background (cli_colors[0]),
107    m_intensity (cli_intensities[ui_file_style::NORMAL])
108{
109}
110
111/* See cli-style.h.  */
112
113cli_style_option::cli_style_option (const char *name,
114				    ui_file_style::intensity i)
115  : changed (name),
116    m_name (name),
117    m_foreground (cli_colors[0]),
118    m_background (cli_colors[0]),
119    m_intensity (cli_intensities[i])
120{
121}
122
123/* Return the color number corresponding to COLOR.  */
124
125static int
126color_number (const char *color)
127{
128  for (int i = 0; i < ARRAY_SIZE (cli_colors); ++i)
129    {
130      if (color == cli_colors[i])
131	return i - 1;
132    }
133  gdb_assert_not_reached ("color not found");
134}
135
136/* See cli-style.h.  */
137
138ui_file_style
139cli_style_option::style () const
140{
141  int fg = color_number (m_foreground);
142  int bg = color_number (m_background);
143  ui_file_style::intensity intensity = ui_file_style::NORMAL;
144
145  for (int i = 0; i < ARRAY_SIZE (cli_intensities); ++i)
146    {
147      if (m_intensity == cli_intensities[i])
148	{
149	  intensity = (ui_file_style::intensity) i;
150	  break;
151	}
152    }
153
154  return ui_file_style (fg, bg, intensity);
155}
156
157/* See cli-style.h.  */
158
159void
160cli_style_option::do_set_value (const char *ignore, int from_tty,
161				struct cmd_list_element *cmd)
162{
163  cli_style_option *cso = (cli_style_option *) get_cmd_context (cmd);
164  cso->changed.notify ();
165}
166
167/* Implements the cli_style_option::do_show_* functions.
168   WHAT and VALUE are the property and value to show.
169   The style for which WHAT is shown is retrieved from CMD context.  */
170
171static void
172do_show (const char *what, struct ui_file *file,
173	 struct cmd_list_element *cmd,
174	 const char *value)
175{
176  cli_style_option *cso = (cli_style_option *) get_cmd_context (cmd);
177  fputs_filtered (_("The "), file);
178  fprintf_styled (file, cso->style (), _("\"%s\" style"), cso->name ());
179  fprintf_filtered (file, _(" %s is: %s\n"), what, value);
180}
181
182/* See cli-style.h.  */
183
184void
185cli_style_option::do_show_foreground (struct ui_file *file, int from_tty,
186				      struct cmd_list_element *cmd,
187				      const char *value)
188{
189  do_show (_("foreground color"), file, cmd, value);
190}
191
192/* See cli-style.h.  */
193
194void
195cli_style_option::do_show_background (struct ui_file *file, int from_tty,
196				      struct cmd_list_element *cmd,
197				      const char *value)
198{
199  do_show (_("background color"), file, cmd, value);
200}
201
202/* See cli-style.h.  */
203
204void
205cli_style_option::do_show_intensity (struct ui_file *file, int from_tty,
206				     struct cmd_list_element *cmd,
207				     const char *value)
208{
209  do_show (_("display intensity"), file, cmd, value);
210}
211
212/* See cli-style.h.  */
213
214void
215cli_style_option::add_setshow_commands (enum command_class theclass,
216					const char *prefix_doc,
217					struct cmd_list_element **set_list,
218					struct cmd_list_element **show_list,
219					bool skip_intensity)
220{
221  m_set_prefix = std::string ("set style ") + m_name + " ";
222  m_show_prefix = std::string ("show style ") + m_name + " ";
223
224  add_basic_prefix_cmd (m_name, no_class, prefix_doc, &m_set_list,
225			m_set_prefix.c_str (), 0, set_list);
226  add_show_prefix_cmd (m_name, no_class, prefix_doc, &m_show_list,
227		       m_show_prefix.c_str (), 0, show_list);
228
229  add_setshow_enum_cmd ("foreground", theclass, cli_colors,
230			&m_foreground,
231			_("Set the foreground color for this property."),
232			_("Show the foreground color for this property."),
233			nullptr,
234			do_set_value,
235			do_show_foreground,
236			&m_set_list, &m_show_list, (void *) this);
237  add_setshow_enum_cmd ("background", theclass, cli_colors,
238			&m_background,
239			_("Set the background color for this property."),
240			_("Show the background color for this property."),
241			nullptr,
242			do_set_value,
243			do_show_background,
244			&m_set_list, &m_show_list, (void *) this);
245  if (!skip_intensity)
246    add_setshow_enum_cmd ("intensity", theclass, cli_intensities,
247			  &m_intensity,
248			  _("Set the display intensity for this property."),
249			  _("Show the display intensity for this property."),
250			  nullptr,
251			  do_set_value,
252			  do_show_intensity,
253			  &m_set_list, &m_show_list, (void *) this);
254}
255
256static cmd_list_element *style_set_list;
257static cmd_list_element *style_show_list;
258
259static void
260set_style_enabled  (const char *args, int from_tty, struct cmd_list_element *c)
261{
262  g_source_cache.clear ();
263  gdb::observers::source_styling_changed.notify ();
264}
265
266static void
267show_style_enabled (struct ui_file *file, int from_tty,
268		    struct cmd_list_element *c, const char *value)
269{
270  if (cli_styling)
271    fprintf_filtered (file, _("CLI output styling is enabled.\n"));
272  else
273    fprintf_filtered (file, _("CLI output styling is disabled.\n"));
274}
275
276static void
277show_style_sources (struct ui_file *file, int from_tty,
278		    struct cmd_list_element *c, const char *value)
279{
280  if (source_styling)
281    fprintf_filtered (file, _("Source code styling is enabled.\n"));
282  else
283    fprintf_filtered (file, _("Source code styling is disabled.\n"));
284}
285
286void _initialize_cli_style ();
287void
288_initialize_cli_style ()
289{
290  add_basic_prefix_cmd ("style", no_class, _("\
291Style-specific settings.\n\
292Configure various style-related variables, such as colors"),
293		  &style_set_list, "set style ", 0, &setlist);
294  add_show_prefix_cmd ("style", no_class, _("\
295Style-specific settings.\n\
296Configure various style-related variables, such as colors"),
297		  &style_show_list, "show style ", 0, &showlist);
298
299  add_setshow_boolean_cmd ("enabled", no_class, &cli_styling, _("\
300Set whether CLI styling is enabled."), _("\
301Show whether CLI is enabled."), _("\
302If enabled, output to the terminal is styled."),
303			   set_style_enabled, show_style_enabled,
304			   &style_set_list, &style_show_list);
305
306  add_setshow_boolean_cmd ("sources", no_class, &source_styling, _("\
307Set whether source code styling is enabled."), _("\
308Show whether source code styling is enabled."), _("\
309If enabled, source code is styled.\n"
310#ifdef HAVE_SOURCE_HIGHLIGHT
311"Note that source styling only works if styling in general is enabled,\n\
312see \"show style enabled\"."
313#else
314"Source highlighting may be disabled in this installation of gdb, because\n\
315it was not linked against GNU Source Highlight.  However, it might still be\n\
316available if the appropriate extension is available at runtime."
317#endif
318			   ), set_style_enabled, show_style_sources,
319			   &style_set_list, &style_show_list);
320
321  file_name_style.add_setshow_commands (no_class, _("\
322Filename display styling.\n\
323Configure filename colors and display intensity."),
324					&style_set_list, &style_show_list,
325					false);
326
327  function_name_style.add_setshow_commands (no_class, _("\
328Function name display styling.\n\
329Configure function name colors and display intensity"),
330					    &style_set_list, &style_show_list,
331					    false);
332
333  variable_name_style.add_setshow_commands (no_class, _("\
334Variable name display styling.\n\
335Configure variable name colors and display intensity"),
336					    &style_set_list, &style_show_list,
337					    false);
338
339  address_style.add_setshow_commands (no_class, _("\
340Address display styling.\n\
341Configure address colors and display intensity"),
342				      &style_set_list, &style_show_list,
343				      false);
344
345  title_style.add_setshow_commands (no_class, _("\
346Title display styling.\n\
347Configure title colors and display intensity\n\
348Some commands (such as \"apropos -v REGEXP\") use the title style to improve\n\
349readability."),
350				    &style_set_list, &style_show_list,
351				    false);
352
353  highlight_style.add_setshow_commands (no_class, _("\
354Highlight display styling.\n\
355Configure highlight colors and display intensity\n\
356Some commands use the highlight style to draw the attention to a part\n\
357of their output."),
358					&style_set_list, &style_show_list,
359					false);
360
361  metadata_style.add_setshow_commands (no_class, _("\
362Metadata display styling.\n\
363Configure metadata colors and display intensity\n\
364The \"metadata\" style is used when GDB displays information about\n\
365your data, for example \"<unavailable>\""),
366				       &style_set_list, &style_show_list,
367				       false);
368
369  tui_border_style.add_setshow_commands (no_class, _("\
370TUI border display styling.\n\
371Configure TUI border colors\n\
372The \"tui-border\" style is used when GDB displays the border of a\n\
373TUI window that does not have the focus."),
374					 &style_set_list, &style_show_list,
375					 true);
376
377  tui_active_border_style.add_setshow_commands (no_class, _("\
378TUI active border display styling.\n\
379Configure TUI active border colors\n\
380The \"tui-active-border\" style is used when GDB displays the border of a\n\
381TUI window that does have the focus."),
382						&style_set_list,
383						&style_show_list,
384						true);
385}
386