Allow use of Pygments to colorize source code
While GNU Source Highlight is good, it's also difficult to build and distribute. For one thing, it needs Boost. For another, it has an unusual configuration and installation setup. Pygments, a Python library, doesn't suffer from these issues, and so I thought it would be a reasonable fallback. This patch implements this idea. GNU Source Highlight is preferred, but if it is unavailable (or fails), the extension languages are tried. This patch also implements support for Pygments. Something similar could be done for Guile, using: https://dthompson.us/projects/guile-syntax-highlight.html However, I don't know enough about Guile internals to make this happen, so I have not done it here. gdb/ChangeLog 2020-01-21 Tom Tromey <tromey@adacore.com> * source-cache.c (source_cache::ensure): Call ext_lang_colorize. * python/python.c (python_extension_ops): Update. (gdbpy_colorize): New function. * python/lib/gdb/__init__.py (colorize): New function. * extension.h (ext_lang_colorize): Declare. * extension.c (ext_lang_colorize): New function. * extension-priv.h (struct extension_language_ops) <colorize>: New member. * cli/cli-style.c (_initialize_cli_style): Update help text. Change-Id: I5e21623ee05f1f66baaa6deaeca78b578c031bf4
This commit is contained in:
parent
b4654b109b
commit
f6474de9aa
@ -1,3 +1,15 @@
|
|||||||
|
2020-01-21 Tom Tromey <tromey@adacore.com>
|
||||||
|
|
||||||
|
* source-cache.c (source_cache::ensure): Call ext_lang_colorize.
|
||||||
|
* python/python.c (python_extension_ops): Update.
|
||||||
|
(gdbpy_colorize): New function.
|
||||||
|
* python/lib/gdb/__init__.py (colorize): New function.
|
||||||
|
* extension.h (ext_lang_colorize): Declare.
|
||||||
|
* extension.c (ext_lang_colorize): New function.
|
||||||
|
* extension-priv.h (struct extension_language_ops) <colorize>: New
|
||||||
|
member.
|
||||||
|
* cli/cli-style.c (_initialize_cli_style): Update help text.
|
||||||
|
|
||||||
2020-01-21 Luis Machado <luis.machado@linaro.org>
|
2020-01-21 Luis Machado <luis.machado@linaro.org>
|
||||||
|
|
||||||
* aarch64-tdep.c (struct aarch64_displaced_step_closure)
|
* aarch64-tdep.c (struct aarch64_displaced_step_closure)
|
||||||
|
@ -341,8 +341,9 @@ If enabled, source code is styled.\n"
|
|||||||
"Note that source styling only works if styling in general is enabled,\n\
|
"Note that source styling only works if styling in general is enabled,\n\
|
||||||
see \"show style enabled\"."
|
see \"show style enabled\"."
|
||||||
#else
|
#else
|
||||||
"Source highlighting is disabled in this installation of gdb, because\n\
|
"Source highlighting may be disabled in this installation of gdb, because\n\
|
||||||
it was not linked against GNU Source Highlight."
|
it was not linked against GNU Source Highlight. However, it might still be\n\
|
||||||
|
available if the appropriate extension is available at runtime."
|
||||||
#endif
|
#endif
|
||||||
), set_style_enabled, show_style_sources,
|
), set_style_enabled, show_style_sources,
|
||||||
&style_set_list, &style_show_list);
|
&style_set_list, &style_show_list);
|
||||||
|
@ -254,6 +254,13 @@ struct extension_language_ops
|
|||||||
struct type *obj_type,
|
struct type *obj_type,
|
||||||
const char *method_name,
|
const char *method_name,
|
||||||
std::vector<xmethod_worker_up> *dm_vec);
|
std::vector<xmethod_worker_up> *dm_vec);
|
||||||
|
|
||||||
|
/* Colorize a source file. NAME is the source file's name, and
|
||||||
|
CONTENTS is the contents of the file. This should either return
|
||||||
|
colorized (using ANSI terminal escapes) version of the contents,
|
||||||
|
or an empty option. */
|
||||||
|
gdb::optional<std::string> (*colorize) (const std::string &name,
|
||||||
|
const std::string &contents);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* State necessary to restore a signal handler to its previous value. */
|
/* State necessary to restore a signal handler to its previous value. */
|
||||||
|
@ -903,6 +903,27 @@ xmethod_worker::get_result_type (value *object, gdb::array_view<value *> args)
|
|||||||
return result_type;
|
return result_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See extension.h. */
|
||||||
|
|
||||||
|
gdb::optional<std::string>
|
||||||
|
ext_lang_colorize (const std::string &filename, const std::string &contents)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const struct extension_language_defn *extlang;
|
||||||
|
gdb::optional<std::string> result;
|
||||||
|
|
||||||
|
ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
|
||||||
|
{
|
||||||
|
if (extlang->ops->colorize == nullptr)
|
||||||
|
continue;
|
||||||
|
result = extlang->ops->colorize (filename, contents);
|
||||||
|
if (result.has_value ())
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Called via an observer before gdb prints its prompt.
|
/* Called via an observer before gdb prints its prompt.
|
||||||
Iterate over the extension languages giving them a chance to
|
Iterate over the extension languages giving them a chance to
|
||||||
change the prompt. The first one to change the prompt wins,
|
change the prompt. The first one to change the prompt wins,
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc. */
|
#include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc. */
|
||||||
#include "gdbsupport/array-view.h"
|
#include "gdbsupport/array-view.h"
|
||||||
|
#include "gdbsupport/gdb_optional.h"
|
||||||
|
|
||||||
struct breakpoint;
|
struct breakpoint;
|
||||||
struct command_line;
|
struct command_line;
|
||||||
@ -309,4 +310,12 @@ extern void get_matching_xmethod_workers
|
|||||||
(struct type *type, const char *method_name,
|
(struct type *type, const char *method_name,
|
||||||
std::vector<xmethod_worker_up> *workers);
|
std::vector<xmethod_worker_up> *workers);
|
||||||
|
|
||||||
|
/* Try to colorize some source code. FILENAME is the name of the file
|
||||||
|
holding the code. CONTENTS is the source code itself. This will
|
||||||
|
either a colorized (using ANSI terminal escapes) version of the
|
||||||
|
source code, or an empty value if colorizing could not be done. */
|
||||||
|
|
||||||
|
extern gdb::optional<std::string> ext_lang_colorize
|
||||||
|
(const std::string &filename, const std::string &contents);
|
||||||
|
|
||||||
#endif /* EXTENSION_H */
|
#endif /* EXTENSION_H */
|
||||||
|
@ -210,3 +210,17 @@ def find_pc_line(pc):
|
|||||||
"""find_pc_line (pc) -> Symtab_and_line.
|
"""find_pc_line (pc) -> Symtab_and_line.
|
||||||
Return the gdb.Symtab_and_line object corresponding to the pc value."""
|
Return the gdb.Symtab_and_line object corresponding to the pc value."""
|
||||||
return current_progspace().find_pc_line(pc)
|
return current_progspace().find_pc_line(pc)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from pygments import formatters, lexers, highlight
|
||||||
|
def colorize(filename, contents):
|
||||||
|
# Don't want any errors.
|
||||||
|
try:
|
||||||
|
lexer = lexers.get_lexer_for_filename(filename)
|
||||||
|
formatter = formatters.TerminalFormatter()
|
||||||
|
return highlight(contents, lexer, formatter)
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
except:
|
||||||
|
def colorize(filename, contents):
|
||||||
|
return None
|
||||||
|
@ -149,6 +149,8 @@ static void gdbpy_set_quit_flag (const struct extension_language_defn *);
|
|||||||
static int gdbpy_check_quit_flag (const struct extension_language_defn *);
|
static int gdbpy_check_quit_flag (const struct extension_language_defn *);
|
||||||
static enum ext_lang_rc gdbpy_before_prompt_hook
|
static enum ext_lang_rc gdbpy_before_prompt_hook
|
||||||
(const struct extension_language_defn *, const char *current_gdb_prompt);
|
(const struct extension_language_defn *, const char *current_gdb_prompt);
|
||||||
|
static gdb::optional<std::string> gdbpy_colorize
|
||||||
|
(const std::string &filename, const std::string &contents);
|
||||||
|
|
||||||
/* The interface between gdb proper and loading of python scripts. */
|
/* The interface between gdb proper and loading of python scripts. */
|
||||||
|
|
||||||
@ -188,6 +190,8 @@ const struct extension_language_ops python_extension_ops =
|
|||||||
gdbpy_before_prompt_hook,
|
gdbpy_before_prompt_hook,
|
||||||
|
|
||||||
gdbpy_get_matching_xmethod_workers,
|
gdbpy_get_matching_xmethod_workers,
|
||||||
|
|
||||||
|
gdbpy_colorize,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Architecture and language to be used in callbacks from
|
/* Architecture and language to be used in callbacks from
|
||||||
@ -1104,6 +1108,74 @@ gdbpy_before_prompt_hook (const struct extension_language_defn *extlang,
|
|||||||
return EXT_LANG_RC_NOP;
|
return EXT_LANG_RC_NOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is the extension_language_ops.colorize "method". */
|
||||||
|
|
||||||
|
static gdb::optional<std::string>
|
||||||
|
gdbpy_colorize (const std::string &filename, const std::string &contents)
|
||||||
|
{
|
||||||
|
if (!gdb_python_initialized)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
gdbpy_enter enter_py (get_current_arch (), current_language);
|
||||||
|
|
||||||
|
if (gdb_python_module == nullptr
|
||||||
|
|| !PyObject_HasAttrString (gdb_python_module, "colorize"))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
gdbpy_ref<> hook (PyObject_GetAttrString (gdb_python_module, "colorize"));
|
||||||
|
if (hook == nullptr)
|
||||||
|
{
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyCallable_Check (hook.get ()))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
gdbpy_ref<> fname_arg (PyString_FromString (filename.c_str ()));
|
||||||
|
if (fname_arg == nullptr)
|
||||||
|
{
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
gdbpy_ref<> contents_arg (PyString_FromString (contents.c_str ()));
|
||||||
|
if (contents_arg == nullptr)
|
||||||
|
{
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
gdbpy_ref<> result (PyObject_CallFunctionObjArgs (hook.get (),
|
||||||
|
fname_arg.get (),
|
||||||
|
contents_arg.get (),
|
||||||
|
nullptr));
|
||||||
|
if (result == nullptr)
|
||||||
|
{
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gdbpy_is_string (result.get ()))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
gdbpy_ref<> unic = python_string_to_unicode (result.get ());
|
||||||
|
if (unic == nullptr)
|
||||||
|
{
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
gdbpy_ref<> host_str (PyUnicode_AsEncodedString (unic.get (),
|
||||||
|
host_charset (),
|
||||||
|
nullptr));
|
||||||
|
if (host_str == nullptr)
|
||||||
|
{
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string (PyBytes_AsString (host_str.get ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Printing. */
|
/* Printing. */
|
||||||
|
@ -178,9 +178,10 @@ source_cache::ensure (struct symtab *s)
|
|||||||
|
|
||||||
std::string contents = get_plain_source_lines (s, fullname);
|
std::string contents = get_plain_source_lines (s, fullname);
|
||||||
|
|
||||||
#ifdef HAVE_SOURCE_HIGHLIGHT
|
|
||||||
if (source_styling && gdb_stdout->can_emit_style_escape ())
|
if (source_styling && gdb_stdout->can_emit_style_escape ())
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_SOURCE_HIGHLIGHT
|
||||||
|
bool already_styled = false;
|
||||||
const char *lang_name = get_language_name (SYMTAB_LANGUAGE (s));
|
const char *lang_name = get_language_name (SYMTAB_LANGUAGE (s));
|
||||||
if (lang_name != nullptr)
|
if (lang_name != nullptr)
|
||||||
{
|
{
|
||||||
@ -202,6 +203,7 @@ source_cache::ensure (struct symtab *s)
|
|||||||
std::ostringstream output;
|
std::ostringstream output;
|
||||||
highlighter->highlight (input, output, lang_name, fullname);
|
highlighter->highlight (input, output, lang_name, fullname);
|
||||||
contents = output.str ();
|
contents = output.str ();
|
||||||
|
already_styled = true;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -213,8 +215,16 @@ source_cache::ensure (struct symtab *s)
|
|||||||
un-highlighted text. */
|
un-highlighted text. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (!already_styled)
|
||||||
#endif /* HAVE_SOURCE_HIGHLIGHT */
|
#endif /* HAVE_SOURCE_HIGHLIGHT */
|
||||||
|
{
|
||||||
|
gdb::optional<std::string> ext_contents;
|
||||||
|
ext_contents = ext_lang_colorize (fullname, contents);
|
||||||
|
if (ext_contents.has_value ())
|
||||||
|
contents = std::move (*ext_contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
source_text result = { std::move (fullname), std::move (contents) };
|
source_text result = { std::move (fullname), std::move (contents) };
|
||||||
m_source_map.push_back (std::move (result));
|
m_source_map.push_back (std::move (result));
|
||||||
|
Loading…
Reference in New Issue
Block a user