bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 07/11] diagnostics: truncate quoted sources to fit the screen


From: Akim Demaille
Subject: [PATCH 07/11] diagnostics: truncate quoted sources to fit the screen
Date: Sat, 21 Sep 2019 12:00:00 +0200

* 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.
---
 src/location.c | 96 +++++++++++++++++++++++++++++++++++++++++---------
 src/location.h |  3 +-
 tests/local.at | 29 +++++++++------
 3 files changed, 101 insertions(+), 27 deletions(-)

diff --git a/src/location.c b/src/location.c
index 66361fc0..4e2bfd9b 100644
--- a/src/location.c
+++ b/src/location.c
@@ -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);
diff --git a/src/location.h b/src/location.h
index 995e13a4..5926b069 100644
--- a/src/location.h
+++ b/src/location.h
@@ -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
diff --git a/tests/local.at b/tests/local.at
index de396496..b2b76f2e 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -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.  ##
-- 
2.23.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]