coreutils
[Top][All Lists]
Advanced

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

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


From: Keller, Jacob E
Subject: RE: [PATCH RFC] expand: add support for incremental tab stops
Date: Wed, 29 Mar 2017 22:12:30 +0000


> -----Original Message-----
> From: Pádraig Brady [mailto:address@hidden]
> Sent: Tuesday, March 28, 2017 7:44 PM
> To: Keller, Jacob E <address@hidden>; address@hidden
> Subject: Re: [PATCH RFC] expand: add support for incremental tab stops
> 
> On 28/03/17 15:49, Jacob Keller wrote:
> > 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"}],
> >
> 
> 
> I like this a lot.
> I'll document the `diff one two | expand --tabs=1,+8` example.
> 
> thanks!
> Pádraig

It looks like there may need to be some work on this for handling zero-width 
characters (like ASCI color sequences) so that it can work correctly for 
colored output as well. I'm still looking into it. I'm glad you like it.

Thanks,
Jake

reply via email to

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