aboutsummaryrefslogtreecommitdiff
path: root/gdb/source-cache.c
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2018-10-09 22:21:05 -0600
committerTom Tromey <tom@tromey.com>2018-12-28 12:49:54 -0700
commit62f29fda90cf1d5a1899f57ef78452471c707fd6 (patch)
tree4d2e519c41de4248f7b4f169f8f379f73f3f0a51 /gdb/source-cache.c
parent4a3045920bbe4e50a0f4920b0fdc4e88ef23015c (diff)
downloadgdb-62f29fda90cf1d5a1899f57ef78452471c707fd6.zip
gdb-62f29fda90cf1d5a1899f57ef78452471c707fd6.tar.gz
gdb-62f29fda90cf1d5a1899f57ef78452471c707fd6.tar.bz2
Highlight source code using GNU Source Highlight
This changes gdb to highlight source using GNU Source Highlight, if it is available. This affects the output of the "list" command and also the TUI source window. No new test because I didn't see a way to make it work when Source Highlight is not found. gdb/ChangeLog 2018-12-28 Tom Tromey <tom@tromey.com> * utils.h (can_emit_style_escape): Declare. * utils.c (can_emit_style_escape): No longer static. * cli/cli-style.c (set_style_enabled): New function. (_initialize_cli_style): Use it. * tui/tui-winsource.c (tui_show_source_line): Use tui_puts. (tui_alloc_source_buffer): Change how source lines are allocated. * tui/tui-source.c (copy_source_line): New function. (tui_set_source_content): Use source cache. * tui/tui-io.h (tui_puts): Update. * tui/tui-io.c (tui_puts_internal): Add window parameter. (tui_puts): Likewise. (tui_redisplay_readline): Update. * tui/tui-data.c (free_content_elements): Change how source window contents are freed. * source.c (forget_cached_source_info): Clear the source cache. (print_source_lines_base): Use the source cache. * source-cache.h: New file. * source-cache.c: New file. * configure.ac: Check for GNU Source Highlight library. * configure: Update. * config.in: Update. * Makefile.in (SRCHIGH_LIBS, SRCHIGH_CFLAGS): New variables. (INTERNAL_CFLAGS_BASE): Add SRCHIGH_CFLAGS. (CLIBS): Add SRCHIGH_LIBS. (COMMON_SFILES): Add source-cache.c. (HFILES_NO_SRCDIR): Add source-cache.h.
Diffstat (limited to 'gdb/source-cache.c')
-rw-r--r--gdb/source-cache.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/gdb/source-cache.c b/gdb/source-cache.c
new file mode 100644
index 0000000..5685180
--- /dev/null
+++ b/gdb/source-cache.c
@@ -0,0 +1,209 @@
+/* Cache of styled source file text
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "source-cache.h"
+#include "common/scoped_fd.h"
+#include "source.h"
+#include "cli/cli-style.h"
+
+#ifdef HAVE_SOURCE_HIGHLIGHT
+#include <fstream>
+#include <sstream>
+#include <srchilite/sourcehighlight.h>
+#include <srchilite/langmap.h>
+#endif
+
+/* The number of source files we'll cache. */
+
+#define MAX_ENTRIES 5
+
+/* See source-cache.h. */
+
+source_cache g_source_cache;
+
+/* See source-cache.h. */
+
+bool
+source_cache::get_plain_source_lines (struct symtab *s, int first_line,
+ int last_line, std::string *lines)
+{
+ scoped_fd desc (open_source_file (s));
+ if (desc.get () < 0)
+ return false;
+
+ if (s->line_charpos == 0)
+ find_source_lines (s, desc.get ());
+
+ if (first_line < 1 || first_line > s->nlines || last_line < 1)
+ return false;
+
+ if (lseek (desc.get (), s->line_charpos[first_line - 1], SEEK_SET) < 0)
+ perror_with_name (symtab_to_filename_for_display (s));
+
+ int last_charpos;
+ if (last_line >= s->nlines)
+ {
+ struct stat st;
+
+ if (fstat (desc.get (), &st) < 0)
+ perror_with_name (symtab_to_filename_for_display (s));
+ /* We could cache this in line_charpos... */
+ last_charpos = st.st_size;
+ }
+ else
+ last_charpos = s->line_charpos[last_line];
+
+ lines->resize (last_charpos - s->line_charpos[first_line - 1]);
+ if (myread (desc.get (), &(*lines)[0], lines->size ()) < 0)
+ perror_with_name (symtab_to_filename_for_display (s));
+
+ return true;
+}
+
+/* See source-cache.h. */
+
+bool
+source_cache::extract_lines (const struct source_text &text, int first_line,
+ int last_line, std::string *lines)
+{
+ int lineno = 1;
+ std::string::size_type pos = 0;
+ std::string::size_type first_pos = std::string::npos;
+
+ while (pos != std::string::npos && lineno <= last_line)
+ {
+ std::string::size_type new_pos = text.contents.find ('\n', pos);
+
+ if (lineno == first_line)
+ first_pos = pos;
+
+ pos = new_pos;
+ if (lineno == last_line || pos == std::string::npos)
+ {
+ if (pos == std::string::npos)
+ pos = text.contents.size ();
+ *lines = text.contents.substr (first_pos, pos - first_pos);
+ return true;
+ }
+ ++lineno;
+ ++pos;
+ }
+
+ return false;
+}
+
+/* Return the Source Highlight language name, given a gdb language
+ LANG. Returns NULL if the language is not known. */
+
+static const char *
+get_language_name (enum language lang)
+{
+ switch (lang)
+ {
+ case language_c:
+ case language_objc:
+ return "c.lang";
+
+ case language_cplus:
+ return "cpp.lang";
+
+ case language_d:
+ return "d.lang";
+
+ case language_go:
+ return "go.lang";
+
+ case language_fortran:
+ return "fortran.lang";
+
+ case language_m2:
+ /* Not handled by Source Highlight. */
+ break;
+
+ case language_asm:
+ return "asm.lang";
+
+ case language_pascal:
+ return "pascal.lang";
+
+ case language_opencl:
+ /* Not handled by Source Highlight. */
+ break;
+
+ case language_rust:
+ /* Not handled by Source Highlight. */
+ break;
+
+ case language_ada:
+ return "ada.lang";
+
+ default:
+ break;
+ }
+
+ return nullptr;
+}
+
+/* See source-cache.h. */
+
+bool
+source_cache::get_source_lines (struct symtab *s, int first_line,
+ int last_line, std::string *lines)
+{
+ if (first_line < 1 || last_line < 1 || first_line > last_line)
+ return false;
+
+#ifdef HAVE_SOURCE_HIGHLIGHT
+ if (can_emit_style_escape (gdb_stdout))
+ {
+ const char *fullname = symtab_to_fullname (s);
+
+ for (const auto &item : m_source_map)
+ {
+ if (item.fullname == fullname)
+ return extract_lines (item, first_line, last_line, lines);
+ }
+
+ const char *lang_name = get_language_name (SYMTAB_LANGUAGE (s));
+ if (lang_name != nullptr)
+ {
+ std::ifstream input (fullname);
+ if (input.is_open ())
+ {
+ srchilite::SourceHighlight highlighter ("esc.outlang");
+ highlighter.setStyleFile("esc.style");
+
+ std::ostringstream output;
+ highlighter.highlight (input, output, lang_name, fullname);
+
+ source_text result = { fullname, output.str () };
+ m_source_map.push_back (std::move (result));
+
+ if (m_source_map.size () > MAX_ENTRIES)
+ m_source_map.erase (m_source_map.begin ());
+
+ return extract_lines (m_source_map.back (), first_line,
+ last_line, lines);
+ }
+ }
+ }
+#endif /* HAVE_SOURCE_HIGHLIGHT */
+
+ return get_plain_source_lines (s, first_line, last_line, lines);
+}