coreutils
[Top][All Lists]
Advanced

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

[PATCH RFC] expand: add support for incremental tab stops


From: Jacob Keller
Subject: [PATCH RFC] expand: add support for incremental tab stops
Date: Tue, 28 Mar 2017 15:49:50 -0700

When viewing output of a diff program in unified format, the output
comes prefixed by a single column to show which lines are removed,
added, or just context. This single column can impact the display of tab
characters compared to how they would display if the lines were not
prefixed. For example, diff might show

 a context line
 another context line
+a new line
-an old line

But if there were tabs, it could incorrectly display these due to the
change in the column widths. Add a new option to the expand tab list
which will allow us to specify how to expand tabs in this scenario.

Currently, expand has the option of specifying hard coded tab stop
lists, as well as extending this with a '/' notation which indicates to
continue with tab stops at that multiple when the hard coded list is
used up.

Add a new variant, '+' prefix to the last tab, which indicates to keep
adding tabs at that increment after the last hard coded tab stop.

Thus, --tabs="1,+8" is equivalent to --tabs="1,9,17,25,33,41,49,57,..."

This is useful because we can now pipe the output of a diff command and
properly expand the tabs as the user would expect, keeping all tabs
properly aligned so that the output does not appear munged.

It may be worth adding a separate switch for this mode "--diff" or
similar so that users are more likely to discover the capability, but
this patch does not implement such an option at this time.
---
 src/expand-common.c  | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/expand.c         |  5 +++++
 tests/misc/expand.pl | 14 ++++++++++++
 3 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/src/expand-common.c b/src/expand-common.c
index e1b549fab101..7b7902284e33 100644
--- a/src/expand-common.c
+++ b/src/expand-common.c
@@ -38,6 +38,9 @@ static uintmax_t tab_size = 0;
 /* If nonzero, the size of all tab stops after the last specifed.  */
 static uintmax_t extend_size = 0;
 
+/* If nonzero, an increment for additional tab stops after the last specified. 
*/
+static uintmax_t increment_size = 0;
+
 /* The maximum distance between tab stops.  */
 size_t max_column_width;
 
@@ -94,7 +97,7 @@ set_extend_size (uintmax_t tabval)
 {
   bool ok = true;
 
-  if (extend_size)
+  if (extend_size || increment_size)
     {
       error (0, 0,
              _("'/' specifier only allowed"
@@ -106,6 +109,23 @@ set_extend_size (uintmax_t tabval)
   return ok;
 }
 
+static bool
+set_increment_size(uintmax_t tabval)
+{
+  bool ok = true;
+
+  if (extend_size || increment_size)
+    {
+      error (0,0,
+             _("'+' specifier only allowed"
+               " with the last value"));
+      ok = false;
+    }
+  increment_size = tabval;
+
+  return ok;
+}
+
 /* Add the comma or blank separated list of tab stops STOPS
    to the list of tab stops.  */
 extern void
@@ -114,6 +134,7 @@ parse_tab_stops (char const *stops)
   bool have_tabval = false;
   uintmax_t tabval = 0;
   bool extend_tabval = false;
+  bool increment_tabval = false;
   char const *num_start = NULL;
   bool ok = true;
 
@@ -131,6 +152,14 @@ parse_tab_stops (char const *stops)
                       break;
                     }
                 }
+              else if (increment_tabval)
+                {
+                  if (! set_increment_size (tabval))
+                    {
+                      ok = false;
+                      break;
+                    }
+                }
               else
                 add_tab_stop (tabval);
             }
@@ -144,8 +173,28 @@ parse_tab_stops (char const *stops)
                      quote (stops));
               ok = false;
             }
+          else if (increment_tabval)
+            {
+              error (0, 0, _("'/' specifier mutually exclusive with '+'"));
+              ok = false;
+            }
           extend_tabval = true;
         }
+      else if (*stops == '+')
+        {
+          if (have_tabval)
+            {
+              error (0, 0, _("'+' specifier not at start of number: %s"),
+                     quote (stops));
+              ok = false;
+            }
+          else if (extend_tabval)
+            {
+              error (0, 0, _("'+' specifier mutually exclusive with '/'"));
+              ok = false;
+            }
+          increment_tabval = true;
+        }
       else if (ISDIGIT (*stops))
         {
           if (!have_tabval)
@@ -179,6 +228,8 @@ parse_tab_stops (char const *stops)
     {
       if (extend_tabval)
         ok &= set_extend_size (tabval);
+      else if (increment_tabval)
+        ok &= set_increment_size (tabval);
       else
         add_tab_stop (tabval);
     }
@@ -221,7 +272,7 @@ finalize_tab_stops (void)
 
   if (first_free_tab == 0)
     tab_size = max_column_width = extend_size ? extend_size : 8;
-  else if (first_free_tab == 1 && ! extend_size)
+  else if (first_free_tab == 1 && ! extend_size && ! increment_size)
     tab_size = tab_list[0];
   else
     tab_size = 0;
@@ -251,6 +302,14 @@ get_next_tab_column (const uintmax_t column, size_t* 
tab_index,
   if (extend_size)
     return column + (extend_size - column % extend_size);
 
+  /* incremental last tab - add increment_size to the previous tab stop */
+  if (increment_size)
+    {
+      uintmax_t final_tab = first_free_tab ? tab_list[first_free_tab - 1] : 0;
+
+      return column + (increment_size - ((column - final_tab) % 
increment_size));
+    }
+
   *last_tab = true;
   return 0;
 }
diff --git a/src/expand.c b/src/expand.c
index 2b7781ca51e2..8067ba237b2c 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -83,6 +83,11 @@ Convert tabs in each FILE to spaces, writing to standard 
output.\n\
 "), stdout);
       fputs (_("\
   -t, --tabs=LIST     use comma separated list of explicit tab positions\n\
+                      the final value can be preceded by either a '/' in\n\
+                      which case it indicates additional tab stops at that\n\
+                      multiple, and it can be preceded by a '+' in which\n\
+                      case it indicates additional tab stops incrementing\n\
+                      by that value.\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
diff --git a/tests/misc/expand.pl b/tests/misc/expand.pl
index b04d2e72db6b..88e4b26a3c81 100755
--- a/tests/misc/expand.pl
+++ b/tests/misc/expand.pl
@@ -151,6 +151,20 @@ my @Tests =
    ['trail8', '--tabs=1 -t/5', {IN=>"\ta\tb\tc"}, {OUT=>" a   b    c"}],
    ['trail9', '--tab=1,2 -t/5',{IN=>"\ta\tb\tc"}, {OUT=>" a   b    c"}],
 
+   # Test incremental trailing '+' feature which specifies that
+   # tab stops should continue every increment
+   ['increment0', '--tab=1,+8',    {IN=>"+\t\tb\tc"}, {OUT=>"                 
b       c"}],
+   ['increment1', '--tabs=1,+5',   {IN=>"\ta\tb\tc"}, {OUT=>" a    b    c"}],
+   ['increment2', '--tabs=2,+5',   {IN=>"\ta\tb\tc"}, {OUT=>"  a    b    c"}],
+   ['increment3', '--tabs=1,2,+5', {IN=>"\ta\tb\tc"}, {OUT=>" a     b    c"}],
+   ['increment4', '--tabs=+5',     {IN=>"\ta\tb"},    {OUT=>"     a    b"}],
+   ['increment5', '--tabs=++5',    {IN=>"\ta\tb"},    {OUT=>"     a    b"}],
+   ['increment6', '--tabs=+,+5',   {IN=>"\ta\tb"},    {OUT=>"     a    b"}],
+   ['increment7', '--tabs=,+5',    {IN=>"\ta\tb"},    {OUT=>"     a    b"}],
+   ['increment8', '--tabs=1 -t+5', {IN=>"\ta\tb\tc"}, {OUT=>" a    b    c"}],
+   ['increment9', '--tab=1,2 -t+5',{IN=>"\ta\tb\tc"}, {OUT=>" a     b    c"}],
+
+
    # Test errors
    ['e1', '--tabs="a"', {IN=>''}, {OUT=>''}, {EXIT=>1},
     {ERR => "$prog: tab size contains invalid character(s): 'a'\n"}],
-- 
2.12.2.650.ga248b8c51283




reply via email to

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