#!/usr/bin/env perl

use strict;
use warnings;

use App::ansicolumn qw(ansicolumn);
exit ansicolumn(@ARGV);

__END__

=encoding utf-8

=head1 NAME

ansicolumn - ANSI terminal sequence aware column command

=head1 SYNOPSIS

ansicolumn [options] [file ...]

    -w#, -c#             output width
    -s#                  separator string
    -l#                  maximum number of table columns
    -x                   exchange rows and columns
    -o#                  output separator

    -P[#], --page=#      page mode, with optional page length
           --no-page     disable page mode
    -U[#], --up=#        show in N-up format (-WC# --linestyle=wrap)
    --2up .. --9up       same as -U2 .. -U9
    -D,  --document      document mode
    -V,  --parallel      parallel view mode
    -H,  --filename      print filename header in parallel view mode
    -I,  --ignore-empty  ignore empty files
    -X#, --cell=#        set text width for files in parallel view mode
    -C#, --pane=#        number of panes
    -S#, --pane-width=#  pane width
    -W,  --widen         widen to terminal width
    -p,  --paragraph     paragraph mode
    -r,  --regex-sep     treat separator string as regex

    -B,  --border[=#]    print border with optional style
    -F,  --fillup[=#]    fill-up unit (pane|page|none)

    --height=#           page height
    --column-unit=#      column unit (default 8)
    --margin=#           column margin width (default 1)
    --linestyle=#        folding style (none|truncate|wrap|wordwrap)
    --boundary=#         line-end boundary
    --linebreak=#        line-break mode (none|all|runin|runout)
    --runin=#            run-in width
    --runout=#           run-out width
    --runlen=#           set both run-in and run-out width
    --[no-]pagebreak     allow page break
    --border-style=#     border style
    --label POS=TEXT         pane border label
    --page-label POS=TEXT    page border label
    --[no-]ignore-space  ignore space in table output
    --[no-]white-space   allow white spaces at the top of each pane
    --[no-]isolation     page-end isolated line
    --tabstop=#          set tab width
    --tabhead=#          tab-head character
    --tabspace=#         tab-space character
    --tabstyle=#         tab style
    --ambiguous=#        ambiguous character width (narrow|wide)
    --pages              split file by formfeed
    --colormap=#         color mapping (LABEL=COLOR)

Table style options:

    -t,  --table           table style output
    -A,  --table-align     align table output to column unit
    -T,  --table-tabs      align items by tabs
    -TT                    reformat tab aligned text
    -R#, --table-right=#   right adjust table columns
         --table-center=#  center table columns
    -K#, --table-remove=#  discard specified columns
         --item-format=#   apply sprintf format to each cell
         --table-squeeze   remove all-empty columns
         --padding         pad last column to full width

Default alias options:

    --board-color FG BG    board style pages with FG and BG colors
    --white-board          black on white board
    --black-board          white on black board
    --green-board          white on green board
    --slate-board          white on dark slategray board

=head1 VERSION

Version 1.5702

=head1 DESCRIPTION

B<ansicolumn> is a L<column(1)> command clone that can handle ANSI
terminal sequences, backspaces, and Asian wide characters.  It
supports traditional options, some of the Linux extended options, and
many of its own original options.

=begin html

<p><img width="750" src="https://raw.githubusercontent.com/tecolicom/App-ansicolumn/master/images/ac-grep.png">

=end html

In addition to normal operation, table style output (C<-t>) is
supported as well.

=begin html

<p><img width="750" src="https://raw.githubusercontent.com/tecolicom/App-ansicolumn/master/images/ac-table.png">

=end html

In contrast to the original L<column(1)> command which handles mainly
short item lists, and the Linux variant which has been expanded to have
rich table style output, B<ansicolumn(1)> has been expanded to show
text files in a multi-column view.  Combined with pagination and a
document-friendly folding mechanism, it can be used as a document
viewing preprocessor for a pager program.

=begin html

<p><img width="750" src="https://raw.githubusercontent.com/tecolicom/App-ansicolumn/master/images/ac-man.png">

=end html

To accurately display file contents, blank lines that were ignored by
the original L<column(1)> command are preserved.

When multiple files are given as arguments, it enters parallel
view mode and shows all files in parallel.  This is convenient for viewing
multiple files side-by-side.

=begin html

<p><img width="750" src="https://raw.githubusercontent.com/tecolicom/App-ansicolumn/master/images/ac-cell.png">

=end html

=head2 COMPATIBLE OPTIONS

The column utility formats its input into multiple columns.  Rows are
filled before columns.  Input is taken from I<file> operands, or, by
default, from the standard input.

=over 7

=item B<-w>#, B<-c>#, B<--width>=#, B<--output-width>=#

Output is formatted for a display I<#> columns wide.  See L</CALCULATION>
section.

Accepts C<-c> for compatibility, but C<-w> is more popular.

=item B<-s>#, B<--separator>=#

Specify a set of characters to be used to delimit columns for the C<-t>
option.  When used with the C<--regex-sep> or C<-r> option, it is
treated as a regex rather than a character set.

=item B<-t>, B<--table>

Determine the number of columns the input contains and create a
table.  Columns are delimited with whitespace, by default, or
with the characters supplied using the C<-s> option.  Useful for
pretty-printing displays.

Unlike the original L<column(1)> command, empty fields are not ignored.

=item B<-l>#, B<--table-columns-limit>=#

Specify the maximum number of input columns.  The last column will
contain all remaining line data if the limit is smaller than the
number of columns in the input data.

If the value is negative (default is -1), trailing empty fields are
preserved.  This is useful when processing tables with empty cells
at the end of rows.  Set to 0 to ignore trailing empty fields.

=item B<-x>, B<--fillrows>

Fill columns before filling rows.

=item B<-o>#, B<--output-separator>=#

When the C<--table> or C<-t> option is used, columns are joined by two
space characters (' ') by default.  This option changes the separator.

=item B<-R>#, B<--table-right>=#

Right align text in the specified columns.  Multiple columns are separated by
commas.  Only numbers are supported.

Parameters are parsed by the L<Getopt::EX::Numbers> module, so you can
specify a range of numbers, as in C<-R2:5> which is equivalent to
C<-R2,3,4,5>. Option C<-R:> makes all fields right-aligned.

=item B<--table-center>=#

Center text in the specified columns.  Column specification is the same
as C<--table-right>.  When the remaining space is odd, the extra space
is placed on the right side (i.e., the text is shifted slightly to the
left).

=item B<--item-format>=#

Apply sprintf-style format to each cell content.  For example,
C<--item-format=' %s '> adds a space before and after each cell.
This is applied before column width calculation, so the padding
is included in the column width.

=item B<--table-remove>=#

Discard specified columns.  Column numbers are 1-based, and
negative numbers count from the end (C<-0> is the last column,
C<-1> is the second to last).  Multiple columns are separated by
commas.  Ranges can be specified as C<1:3>.

For example, C<--table-remove=1,-0> removes the first and last
columns.  This is useful when processing pipe-delimited data with
border characters where the leading and trailing delimiters create
extra columns.

Column numbers are parsed by the L<Getopt::EX::Numbers> module.

=item B<--table-squeeze>

Remove columns where all items are empty.  This is useful when
processing pipe-delimited data with border characters (e.g.,
Markdown tables C<| col1 | col2 |>, MySQL output), where the
leading and trailing C<|> create empty columns.

=item B<--padding>

Pad the last column to its full width.  Normally the last column
is not padded to avoid trailing whitespace, but this option forces
all columns including the last to be padded to their calculated
width.

=back

=head2 EXTENDED OPTIONS

=over 7

=item B<-P>[#], B<--page>[=#], B<--no-page>

Enable page mode.  Sets the following options:

    --height=# or 1-
    --linestyle=wrap
    --border
    --fillup

If an optional number is given, it is used as the page height unless
the C<--height> option is also specified.  Otherwise, the page height
is set to the terminal height minus one.

Use C<--no-page> to disable page mode.

=item B<-U>#, B<--up>=#, B<--2up> .. B<--9up>

Show in N-up format.  Almost the same as C<-P> but does not set page
height.  This is convenient when you want multi-column output without
page control.

=item B<-D>, B<-->[B<no->]B<document>

Document mode.  Sets the following options:

    --widen
    --linebreak=all
    --linestyle=wrap
    --boundary=word
    --no-white-space
    --no-isolation

The following command displays DOCX text in 3-up format using
L<App::optex::textconv>.

    optex -Mtextconv ansicolumn -DPC3 foo.docx | less

=item B<-V>, B<-->[B<no->]B<parallel>

Parallel view mode.  Implicitly enabled when multiple files are
specified.  Use C<--no-parallel> to disable.

Sets the following options and cancels all pagination behavior:

    --widen
    --linestyle=wrap
    --border

By default, all files are displayed in parallel.  In other words,
the number of panes is set to the number of files.  You can use the C<-C> option
to specify the number of files displayed simultaneously.

This option can be combined with the C<-D> option to view document files.

If you want to display multiple parts in a single stream in parallel,
use the C<--pages> option. It will split the data by form feed
characters and treat each part as a separate file.

=item B<-H>, B<--filename>

=item B<--filename-format>=I<format> (DEFAULT: C<: %s>)

Print a filename header before contents.  Currently, this option is
effective only in C<--parallel> mode.  Filenames are truncated to fit
within each pane width.

This option is convenient to look over many small files at once.

   ansicolumn -VHC1 *.txt | less

Filenames are printed in the format specified by the C<--filename-format> option.
The default is C<: %s>, which makes it easy to move to the next file using C<^:>
pattern search.

=item B<-I>, B<-->[B<no->]B<ignore-empty>

Ignore empty files.  Default false.

=item B<-X>#, B<--cell>=#

Sets the display width of each file.  This option is only valid in
parallel view mode.  For example, if you are displaying three files
and want the first file to be displayed in 80 columns and the
remaining files in 40 columns, specify it like this:

    --cell 80,40,40

This is the same as

    --cell 80,40

since the last value specified is repeated.

You can also specify values relative to the default width.  For
example, to display the first column 20 columns more and the remaining
columns 10 columns less, use

    --cell +20,-10

To return to the default display width for the fourth and subsequent
files, use

    --cell +20,-10,-10,+0

If C<=> is specified as the value, it is set to the width of the
longest line in the file.

    -X=

Then all specified files will be displayed with the width of the
longest line they contain. C<=> may be followed by a maximum value.

    -X=80

will set the cell width to the length of the longest line if it is less
than 80, or to 80 if it is greater than 80.  C<< < >> may be used instead
of C<=>.

    -X'<80'

The correspondence between file and display width remains the same 
even when the number of columns to be displayed simultaneously is 
specified with the C<-C> option.

=item B<-C>#, B<--pane>=#

Output is formatted in the specified number of panes.  Setting the number
of panes implies the C<--widen> option is enabled.  See L</CALCULATION>
section.

=item B<-S>#, B<--pane-width>=#, B<--pw>=#

Specify the span of each pane.  This includes border spaces.  See
L</CALCULATION> section.

=item B<-W>, B<--widen>

Use the full width of the terminal.  Each pane is expanded to fill the
terminal width, unless C<--pane-width> is specified.

=item B<-p>, B<--paragraph>

Insert an empty line between every pair of successive non-empty lines.

=item B<-B>, B<--border>[=I<style>] (DEFAULT: C<box>)

Print border.  Automatically enabled by the C<--page> option.  If the
optional I<style> is given, it is used as the border style and takes
precedence over the C<--border-style> option.  Use C<--border=none> to
disable it.

The border style is specified by the C<--border-style> option.

=item B<--no-border>

Shortcut for C<--border=none>.

=item B<-F>, B<--fillup>[=C<pane>|C<page>|C<none>]

Fill up the final pane or page with empty lines.  The parameter is optional and
defaults to 'pane'.  Automatically set by the C<--page> option.
Use C<--fillup=none> to explicitly disable it.

Option C<-F> is a shortcut for C<--fillup=pane>.

=item B<--fillup-str>=I<string>

Set the string used for filling up space.  Default is empty.

Use C<--fillup-str='~'> to fill up the area after EOF with the C<~>
character, like L<vi(1)> or L<more(1)>.

=item B<--height>=#

Set page height and enable page mode.  See L</CALCULATION> section.

=item B<--column-unit>=#, B<--cu>=# (DEFAULT: 8)

Each column is placed at a unit of 8 by default.  This option
changes the unit size.

=item B<--margin>=#

Each column has at least a single character margin on the right side so
that they are not placed back-to-back.  This option specifies the
margin width.

=item B<-A>, B<--table-align>

Align each field in the table output to the column unit.  If this option
is specified, the C<--output-separator> option is ignored.
Implicitly enables the C<--table> option.

=item B<-T>, B<-TT>, B<--table-tabs>

This option enables the C<--table> and C<--table-align> options, and
forces the use of tab characters between items.  The tab width uses the
value of C<--column-unit>.  The C<--table-right> and C<--table-center>
options do not take effect.

If the C<-T> option is specified twice, the input separator is set to
repeating tabs (same as C<-rs '\t+'>).  Thus, the C<-TT> option can be
used to reformat tab-aligned text.

=item B<--linestyle>=C<none>|C<truncate>|C<wrap>|C<wordwrap>, B<--ls>=C<...>

Set the style of treatment for longer lines.
Default is C<none>.

Option C<--linestyle=wordwrap> sets C<--linestyle=wrap> and
C<--boundary=word> at once.

=item B<--boundary>=C<none>|C<word>|C<space>

Set text wrap boundary.  If set to C<word> or C<space>, text is not
wrapped in the middle of an alphanumeric word or non-space sequence.
The C<--document> option sets this to C<word>.  See L<Text::ANSI::Fold> for
details.

=item B<--linebreak>=C<none>|C<all>|C<runin>|C<runout>, B<--lb>=...

Set the linebreak mode.

=item B<--runin>=#, B<--runout>=#, B<--runlen>=#

Set the number of runin/runout columns.  C<--runlen> sets both.
The default is 2 for both.

For Japanese text, only one character can be moved with the default
value.  A larger value allows more flexible arrangement but makes the text
area shorter.  The author uses the command with a custom F<~/.ansicolumnrc>
like this:

    option default --runin=4 --runout=4

=item B<-->[B<no->]B<pagebreak>

Move to the next pane when a form feed character is found.
Default is true.

=item B<-r>, B<--regex-sep>

Treat the separator option as a regex pattern.  The following example specifies a
space character just before C<(> as a separator.

    gem list | ansicolumn -trs ' (?=\()'

=item B<--border-style>=I<style>, B<--bs>=...

Set the border style.  The default style is C<box>, which encloses
each pane with box-drawing characters.  The special style C<random>
chooses a random style.

Sample styles:
none,
space,
vbar, heavy-vbar, fat-vbar,
line, heavy-line,
hline, heavy-hline,
bottom-line, heavy-bottom-line,
stick, heavy-stick,
ascii-frame,
ascii-box,
c-box,
box, heavy-box, fat-box, very-fat-box,
dash-box, heavy-dash-box, fat-dash-box,
round-box,
inner-box, outer-box,
frame, heavy-frame, fat-frame, very-fat-frame,
ladder, heavy-ladder,
dash-frame, heavy-dash-frame, fat-dash-frame,
page-frame, heavy-page-frame,
zebra-frame,
checker-box, checker-frame,
shadow, shin-shadow,
shadow-box, shin-shadow-box, heavy-shadow-box,
comb, heavy-comb,
rake, heavy-rake,
mesh, heavy-mesh,
dumbbell, heavy-dumbbell,
ribbon, heavy-ribbon,
round-ribbon,
double-ribbon,
corner, crop, paren,
etc.

These are experimental and subject to change, and this document is not
always up-to-date.  See `perldoc -m App::ansicolumn::Border` for
actual data.

You can define your own style in a module or startup file.  For
example, put the following lines in your C<$HOME/.ansicolumnrc> file.

    option default --border-style myheart
    __PERL__
    App::ansicolumn::Border->add_style(
        myheart  => {
        left   => [ "\N{WHITE HEART SUIT} ", "\N{BLACK HEART SUIT} " ],
    	center => [ "\N{WHITE HEART SUIT} ", "\N{BLACK HEART SUIT} " ],
    	right  => [ "\N{WHITE HEART SUIT}" , "\N{BLACK HEART SUIT}"  ],
    },
    );

=item B<--label> I<position>=I<string>

Place a label string on the border of each pane.  Requires C<--border>
to be active.  The I<position> specifies where on the border the label
appears:

    NW ------ N ------ NE
    |                   |
    SW ------ S ------ SE

Position names are case-insensitive.  This option can be specified
multiple times to set labels at different positions.

    --label NW=Title --label SE=%n

The following placeholders are expanded:

    %n    sequential pane number (1-based, across pages)
    %p    page number (1-based)
    %f    filename (basename only)
    %F    filename (path as given)

By default, left labels (C<NW>, C<SW>) start just inside the fill
region, and right labels (C<NE>, C<SE>) end at the right edge of it.
Append C<@>I<N> to the string to set an explicit offset from the
border corner.  C<@0> places the label directly on the corner
character.

    --label NW='Title@0'    # overwrite corner character
    --label SE='%n@3'       # 3 columns from corner

Example with page mode:

    seq 100 | ansicolumn -P --label SE=%n --2up

Use C<--cm BORDER_LABEL=>I<color> to colorize labels:

    seq 100 | ansicolumn -P --label SE=%n --cm BORDER_LABEL=RD --2up

=item B<--page-label> I<position>=I<string>

Place a label string on the border of the entire page.  Unlike
C<--label> which places labels on individual panes, this option places
a single label spanning the full-width border line.  Positions,
placeholders, and C<@>I<N> offset syntax are the same as C<--label>.

When both C<--label> and C<--page-label> are specified, pane labels
are applied first, then page labels are overlaid on top.

    seq 100 | ansicolumn -P --label NW=Title --page-label SE=%p --2up

=item B<--colormap>=I<spec>, B<--cm>=I<spec>

Specify color mapping.  This option can be used multiple times.
The I<spec> is in the form of C<LABEL=COLOR>.  Available labels are:

    TEXT          text color
    BORDER        border color
    BORDER_LABEL  border label color

For example, to set the border color to red:

    --cm=BORDER=R

To set the border label color:

    --cm=BORDER_LABEL=RD

See L<Getopt::EX::Colormap> for color specification details.

=item B<-->[B<no->]B<ignore-space>, B<-->[B<no->]B<is>

When the C<-t> option is used, leading spaces are ignored by default.  Use the
C<--no-ignore-space> option to disable this.

=item B<-->[B<no->]B<white-space>

Allow white spaces at the top of each pane, or clean them up.  Default
true.  Negated by the C<--document> option.

=item B<-->[B<no->]B<isolation>

Allow a line to be isolated at the bottom of a pane when preceded by
a blank line.  Default true.  If false, move it to the top of the next
pane.  This applies to both single-line paragraphs (such as titles)
and the first line of multi-line paragraphs.  Negated by the
C<--document> option.

=item B<--tabstop>=# (DEFAULT: 8)

Set tab width.

=item B<--tabhead>=#

=item B<--tabspace>=#

Set the head and following space characters.  Both are space by default.
If the option value is longer than a single character, it is evaluated
as a Unicode name.

=item B<--tabstyle>, B<--ts>

=item B<--tabstyle>=I<style>, B<--ts>=...

=item B<--tabstyle>=I<head-style>,I<space-style> B<--ts>=...

Set how tabs are expanded.  Select C<symbol> or C<shade> for
example.  If two style names are combined, like
C<squat-arrow,middle-dot>, use C<squat-arrow> for tabhead and
C<middle-dot> for tabspace.

Shows the available style list if called without a parameter.  Styles
are defined in the L<Text::ANSI::Fold> library.

=item B<--ambiguous>=C<wide>|C<narrow> (DEFAULT: C<narrow>)

Specifies how to treat Unicode ambiguous width characters.  Takes a
value of C<narrow> or C<wide>.  Default is C<narrow>.

=item B<--pages>

Split file content by formfeed characters, and treat each part as an
individual file.  Use with the C<--parallel> option.

=begin comment

=item B<-->[B<no->]B<discard-el>

Discard ANSI Erase Line sequence.  Default true.

=item B<--padchar>=I<char>

Set padding character.

=end comment

=back

=head1 DEFAULT ALIASES

The following options are defined in F<App::ansicolumn::default.pm>.

=over 7

=item B<--board-color> I<fg-color> I<bg-color>

This option is defined as follows:

   option --board-color \
          --bs=inner-box \
          --cm=BORDER=$<2>,TEXT=$<shift>/$<shift>

The resulting text is displayed in an I<fg-color> font on an
I<bg-color> panel.

=item B<--white-board>

=item B<--black-board>

=item B<--green-board>

=item B<--slate-board>

Use the C<--board-color> option to display text on white, black,
green, or dark slate panels.

=back

=head1 CALCULATION

For the C<--height>, C<--width>, C<--pane>, C<--up> and C<--pane-width>
options, besides giving numeric digits, you can calculate the number
using the terminal size.  If the expression contains a non-digit
character, it is evaluated as an RPN (Reverse Polish Notation)
expression with the terminal size pushed on the stack.  The initial
value for C<--height> is the terminal height, and the terminal width
for others.

    OPTION              VALUE
    =================   =========================
    --height 1-         height - 1
    --height 2/         height / 2
    --height 1-2/       (height - 1) / 2
    --height dup2%-2/   (height - height % 2) / 2

Space and comma characters are ignored in the expression.  So C<1-2/>
and C<< S<1 - 2 /> >> and C<1,-,2,/> are all the same.  See C<perldoc
Math::RPN> for details.

The next example selects the number of panes by dividing the terminal
width by 85:

    ansicolumn --pane 85/

If you need to handle the case where the terminal width is less than 85:

    ansicolumn --pane 85/,DUP,1,GE,EXCH,1,IF

This RPN means C<< $width/85 >= 1 ? $width/85 : 1 >>.

=head1 STARTUP

This command is implemented with the L<Getopt::EX> module, so the

    ~/.ansicolumnrc

file is read at startup.  If you always want to use
C<--no-white-space>, put this line in your F<~/.ansicolumnrc>:

    option default --no-white-space

The command can also be extended with custom modules using the C<-M>
option.  See C<perldoc Getopt::EX> for details.

=head1 INSTALL

=head2 CPANMINUS

    $ cpanm App::ansicolumn

To get the latest code, use this:

    $ cpanm https://github.com/tecolicom/App-ansicolumn.git

=head1 EXAMPLES

L<https://github.com/tecolicom/App-ansicolumn/tree/master/images>

=head1 SEE ALSO

L<https://github.com/tecolicom/ANSI-Tools>

L<column(1)>,
L<https://man7.org/linux/man-pages/man1/column.1.html>

L<App::ansicolumn>,
L<https://github.com/tecolicom/App-ansicolumn>

L<Text::ANSI::Printf>,
L<https://github.com/tecolicom/Text-ANSI-Printf>

=head2 Articles (in Japanese)

=over 2

=item *

L<https://qiita.com/kaz-utashiro/items/345cd9abcd8e1f0d81a2>

=item *

L<https://qiita.com/kaz-utashiro/items/1cdd71d44eb11f3fb36e>

=item *

L<https://qiita.com/kaz-utashiro/items/32e1c2d4c42a80c42422>

=item *

L<https://qiita.com/kaz-utashiro/items/a347628da09638e633ed>

=back

=head1 RELATED WORKS

L<https://github.com/LukeSavefrogs/column_ansi>

=head1 AUTHOR

Kazumasa Utashiro

=head1 LICENSE

Copyright © 2020-2026 Kazumasa Utashiro.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

#  LocalWords:  ansicolumn fillrows tabstop columnunit widen DOCX
#  LocalWords:  linestyle linebreak docx runin runout perldoc cpanm
#  LocalWords:  CPANMINUS perl CPAN Kazumasa Utashiro optex wordwrap
#  LocalWords:  Unicode ansicolumnrc
