mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-27 05:03:07 +00:00
diagnostics: truncate quoted sources to fit the screen
* src/location.c (min_int, columns): New. (location_caret): Compute the line width. Based on it, compute how many columns must be skipped before the quoted location and truncated after, to fit the sceen width. * tests/local.at (AT_QUELL_VALGRIND): Transform into... (AT_SET_ENV_IF, AT_SET_ENV): these. Define COLUMNS to protect the test suite from the user's environment.
This commit is contained in:
@@ -33,6 +33,26 @@
|
||||
|
||||
location const empty_loc = EMPTY_LOCATION_INIT;
|
||||
|
||||
static int
|
||||
min_int (int a, int b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
/* The terminal width. */
|
||||
static int
|
||||
columns (void)
|
||||
{
|
||||
const char *cp = getenv ("COLUMNS");
|
||||
int res = 80;
|
||||
if (cp && *cp)
|
||||
{
|
||||
unsigned long ul = strtoul (cp, NULL, 10);
|
||||
res = ul < INT_MAX ? ul : INT_MAX;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* If BUF is null, add BUFSIZE (which in this case must be less than
|
||||
INT_MAX) to COLUMN; otherwise, add mbsnwidth (BUF, BUFSIZE, 0) to
|
||||
COLUMN. If an overflow occurs, return INT_MAX. */
|
||||
@@ -179,6 +199,8 @@ static struct
|
||||
} caret_info;
|
||||
|
||||
|
||||
/* Open FILE for quoting, if needed, and if possible. Return whether
|
||||
the file can quoted. */
|
||||
static bool
|
||||
caret_set_file (const char *file)
|
||||
{
|
||||
@@ -276,6 +298,38 @@ location_caret (location loc, const char *style, FILE *out)
|
||||
FIXME: should be done in mbfile. */
|
||||
caret_info.mbfile.eof_seen = 0;
|
||||
|
||||
/* Find the number of columns of this line. */
|
||||
while (true)
|
||||
{
|
||||
mbchar_t c;
|
||||
caret_getc (c);
|
||||
if (mb_iseof (c) || mb_iseq (c, '\n'))
|
||||
break;
|
||||
boundary_compute (&caret_info.pos, mb_ptr (c), mb_len (c));
|
||||
}
|
||||
int line_len = caret_info.pos.column;
|
||||
|
||||
/* Available width. Eight chars are consumed by the left-margin of
|
||||
the quoting lines. */
|
||||
int width = columns () - 8;
|
||||
int skip = 0;
|
||||
if (width < line_len)
|
||||
{
|
||||
/* We cannot quote the whole line. Make sure we can see the
|
||||
beginning of the location. */
|
||||
skip = width < loc.start.column ? loc.start.column - 10 : 0;
|
||||
}
|
||||
/* If we skip the initial part, we insert "..." before. */
|
||||
if (skip)
|
||||
width -= 3;
|
||||
|
||||
/* Go back to the beginning of line. */
|
||||
fseek (caret_info.file, caret_info.offset, SEEK_SET);
|
||||
/* Reset mbf's internal state.
|
||||
FIXME: should be done in mbfile. */
|
||||
caret_info.mbfile.eof_seen = 0;
|
||||
caret_info.pos.column = 1;
|
||||
|
||||
/* Read the actual line. Don't update the offset, so that we keep a pointer
|
||||
to the start of the line. */
|
||||
{
|
||||
@@ -283,15 +337,19 @@ location_caret (location loc, const char *style, FILE *out)
|
||||
caret_getc (c);
|
||||
if (!mb_iseof (c))
|
||||
{
|
||||
bool single_line = loc.start.line == loc.end.line;
|
||||
/* The last column to highlight. Only the first line of
|
||||
multiline locations are quoted, in which case the ending
|
||||
column is the end of line. Single point locations (with
|
||||
equal boundaries) denote the character that they
|
||||
follow. */
|
||||
int col_end
|
||||
= loc.start.line == loc.end.line
|
||||
? loc.end.column + (loc.start.column == loc.end.column)
|
||||
: line_len;
|
||||
/* Quote the file (at most the first line in the case of
|
||||
multiline locations). */
|
||||
{
|
||||
fprintf (out, "%5d | ", loc.start.line);
|
||||
/* Consider that single point location (with equal boundaries)
|
||||
actually denote the character that they follow. */
|
||||
int col_end = loc.end.column +
|
||||
(single_line && loc.start.column == loc.end.column);
|
||||
fprintf (out, "%5d | %s", loc.start.line, skip ? "..." : "");
|
||||
/* Whether we opened the style. If the line is not as
|
||||
expected (maybe the file was changed since the scanner
|
||||
ran), we might reach the end before we actually saw the
|
||||
@@ -304,29 +362,35 @@ location_caret (location loc, const char *style, FILE *out)
|
||||
begin_use_class (style, out);
|
||||
opened = true;
|
||||
}
|
||||
mb_putc (c, out);
|
||||
if (skip < caret_info.pos.column)
|
||||
mb_putc (c, out);
|
||||
boundary_compute (&caret_info.pos, mb_ptr (c), mb_len (c));
|
||||
caret_getc (c);
|
||||
if (opened
|
||||
&& (single_line
|
||||
? caret_info.pos.column == col_end
|
||||
: mb_iseq (c, '\n') || mb_iseof (c)))
|
||||
end_use_class (style, out);
|
||||
&& (caret_info.pos.column == col_end
|
||||
|| width < caret_info.pos.column - skip))
|
||||
{
|
||||
end_use_class (style, out);
|
||||
opened = false;
|
||||
}
|
||||
if (width < caret_info.pos.column - skip)
|
||||
break;
|
||||
}
|
||||
putc ('\n', out);
|
||||
}
|
||||
|
||||
/* Print the carets with the same indentation as above. */
|
||||
{
|
||||
fprintf (out, " | %*s", loc.start.column - 1, "");
|
||||
fprintf (out, " | %s%*s",
|
||||
skip ? "..." : "",
|
||||
loc.start.column - 1 - skip, "");
|
||||
begin_use_class (style, out);
|
||||
putc ('^', out);
|
||||
/* Underlining a multiline location ends with the first
|
||||
line. */
|
||||
int len = single_line
|
||||
? loc.end.column
|
||||
: ftell (caret_info.file) - caret_info.offset;
|
||||
for (int i = loc.start.column + 1; i < len; ++i)
|
||||
for (int i = loc.start.column - 1 - skip + 1,
|
||||
i_end = min_int (col_end - 1 - skip, width);
|
||||
i < i_end; ++i)
|
||||
putc ('~', out);
|
||||
end_use_class (style, out);
|
||||
putc ('\n', out);
|
||||
|
||||
@@ -118,7 +118,8 @@ unsigned location_print (location loc, FILE *out);
|
||||
left-over by the usage of location_caret. */
|
||||
void caret_free (void);
|
||||
|
||||
/* Output to OUT the line and caret corresponding to location LOC. */
|
||||
/* Quote the line containing LOC onto OUT. Highlight the part of LOC
|
||||
with the color STYLE. */
|
||||
void location_caret (location loc, const char* style, FILE *out);
|
||||
|
||||
/* Return -1, 0, 1, depending whether a is before, equal, or
|
||||
|
||||
@@ -828,7 +828,7 @@ AT_BISON_CHECK_NO_XML($@)])
|
||||
# --------------------------------------------------
|
||||
# Low-level macro to run bison once.
|
||||
m4_define([AT_BISON_CHECK_],
|
||||
[AT_CHECK(AT_QUELL_VALGRIND[[ bison --color=no -fno-caret ]]$@)])
|
||||
[AT_CHECK(AT_SET_ENV[[ bison --color=no -fno-caret ]]$@)])
|
||||
|
||||
|
||||
# AT_BISON_CHECK_WARNINGS(BISON_ARGS, [OTHER_AT_CHECK_ARGS])
|
||||
@@ -884,7 +884,7 @@ fi]dnl
|
||||
# when a tortured grammar's XML is known to be too large for xsltproc to
|
||||
# handle.
|
||||
m4_define([AT_BISON_CHECK_NO_XML],
|
||||
[AT_CHECK(m4_null_if([$2], [], [AT_QUELL_VALGRIND ])[[bison --color=no -fno-caret ]]$@)
|
||||
[AT_CHECK(AT_SET_ENV_IF([$2]) [[bison --color=no -fno-caret ]]$@)
|
||||
AT_BISON_CHECK_WARNINGS($@)])
|
||||
|
||||
# AT_BISON_CHECK_XML(BISON_ARGS, [OTHER_AT_CHECK_ARGS])
|
||||
@@ -911,20 +911,24 @@ m4_define([AT_BISON_CHECK_XML],
|
||||
m4_popdef([AT_BISON_ARGS])dnl
|
||||
[cp xml-tests/test.output expout]
|
||||
AT_CHECK([[$XSLTPROC \
|
||||
`]]AT_QUELL_VALGRIND[[ bison --print-datadir`/xslt/xml2text.xsl \
|
||||
`]]AT_SET_ENV[[ bison --print-datadir`/xslt/xml2text.xsl \
|
||||
xml-tests/test.xml]], [[0]], [expout])
|
||||
[sort xml-tests/test.gv > expout]
|
||||
AT_CHECK([[$XSLTPROC \
|
||||
`]]AT_QUELL_VALGRIND[[ bison --print-datadir`/xslt/xml2dot.xsl \
|
||||
`]]AT_SET_ENV[[ bison --print-datadir`/xslt/xml2dot.xsl \
|
||||
xml-tests/test.xml | sort]], [[0]], [expout])
|
||||
[rm -rf xml-tests expout]
|
||||
AT_RESTORE_SPECIAL_FILES
|
||||
[fi]])
|
||||
|
||||
# AT_QUELL_VALGRIND
|
||||
# -----------------
|
||||
# Put this before a Bison invocation to keep Valgrind from complaining about
|
||||
# reachable memory.
|
||||
|
||||
# AT_SET_ENV_IF(EXIT-STATUS)
|
||||
# --------------------------
|
||||
# Put this before a Bison invocation to set the environment to:
|
||||
# - define COLUMNS to make the test suite independant of the user's
|
||||
# environment;
|
||||
# - keep Valgrind from complaining about reachable memory (when
|
||||
# EXIT-STATUS is not 0).
|
||||
#
|
||||
# Do not quote invocations of this macro within the first argument of AT_CHECK.
|
||||
# The triple quoting below will cause test cases to fail if you do. If you do
|
||||
@@ -932,10 +936,15 @@ m4_define([AT_BISON_CHECK_XML],
|
||||
# will then fail to shell-escape its contents when attempting to print them.
|
||||
# The testsuite verbose output, at least, will be incorrect, but nothing may
|
||||
# fail to make sure you notice.
|
||||
m4_define([AT_QUELL_VALGRIND],
|
||||
[[[VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no"; export VALGRIND_OPTS;]]])
|
||||
m4_define([AT_SET_ENV_IF],
|
||||
[[[COLUMNS=1000; export COLUMNS;]] m4_null_if($1, [], [[[VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no"; export VALGRIND_OPTS; ]]])])
|
||||
|
||||
|
||||
# AT_SET_ENV
|
||||
# ----------
|
||||
# See above.
|
||||
m4_define([AT_SET_ENV],
|
||||
[AT_SET_ENV_IF([1])])
|
||||
|
||||
## ------------------------ ##
|
||||
## Compiling C, C++ Files. ##
|
||||
|
||||
Reference in New Issue
Block a user