How can a space-delimited list of words be folded into tabular columns that fit in the terminal's width

It looks like you'd need to get the total width in all possible number of columns (from 2 to COLUMNS/2) to determine the width of each column and which is the maximum number of columns where that can fit.

With perl:

#! /usr/bin/perl
use List::Util qw(sum);

$/ = undef;
@word = <> =~ /\S+/g;
$max = $ENV{COLUMNS}/2;
for ($i = 0; $i <= $#word; $i++) {
  $l = length $word[$i];
  for ($c = 2; $c <= $max; $c++) {
    if ($l > $w[$c][$i%$c]) {
      $w[$c][$i%$c] = $l
    }
  }
}
for ($c = $max; $c > 1; $c--) {
  last if $c + sum(@{$w[$c]}) - 1 <= $ENV{COLUMNS}
}
if($c > 1) {
  @w = @{$w[$c]};
  for ($i = 0; $i <= $#word; $i++) {
    if (($i+1)%$c && $i < $#word) {
      printf "%-*s ", $w[$i%$c], $word[$i]
    } else {
      print "$word[$i]\n"
    }
  }
} else {
  print "$_\n" for @word
}

Example:

$ lorem -w 50 | COLUMNS=60 that-script
minima   aut     veritatis laudantium qui      voluptatem
est      nostrum quis      enim       placeat  hic
voluptas ab      ratione   sit        hic      sit
pariatur et      provident voluptas   aut      odio
aut      vero    atque     voluptatem amet     voluptatem
ipsum    iusto   omnis     tenetur    ratione  ratione
illo     ea      odit      excepturi  quisquam aut
nobis    porro   incidunt  corrupti   maxime   ad
est      sunt

For non-ASCII text, see Get the display width of a string of characters to determine the display width of a string. Something like:

#! /usr/bin/perl
use Text::CharWidth qw(mbswidth);
use List::Util qw(sum);

$/ = undef;
@word = <> =~ /\S+/g;
$max = $ENV{COLUMNS}/2;
for ($i = 0; $i <= $#word; $i++) {
  $l = mbswidth $word[$i];
  for ($c = 2; $c <= $max; $c++) {
    if ($l > $w[$c][$i%$c]) {
      $w[$c][$i%$c] = $l
    }
  }
}
for ($c = $max; $c > 1; $c--) {
  last if $c + sum(@{$w[$c]}) - 1 <= $ENV{COLUMNS}
}
if($c > 1) {
  @w = @{$w[$c]};
  for ($i = 0; $i <= $#word; $i++) {
    if (($i+1)%$c && $i < $#word) {
      printf $word[$i] . " " x ($w[$i%$c]+1-mbswidth($word[$i]))
    } else {
      print "$word[$i]\n"
    }
  }
} else {
  print "$_\n" for @word
}

To produce equally spaced columns, you could use BSD rs (also ported to Debian and derivatives (at least) and available as a package there) or BSD column (in the bsdmainutils package on Debian):

tr -s '[:space:]' '[ *]' | rs -w "$COLUMNS"
tr -s '[:space:]' '[\n*]' | column -xc "$COLUMNS"

Example (the vertical line is to show the edge of that 60 column wide screen, it is not part of the output):

$ lorem -w 30 | tr -s '[:space:]' '[ *]' | rs -w60
earum          aspernatur     ipsa           sed            ┃
quod           sit            esse           quisquam       ┃
animi          reprehenderit  porro          et             ┃
delectus       neque          esse           quia           ┃
pariatur       amet           iste           voluptatem     ┃
provident      praesentium    et             sint           ┃
quo            animi          doloribus      veritatis      ┃
iusto          alias                                        ┃

With rs, You can add the -z option to reduce the space between the columns, but that does not optimise the number of columns accordingly. For instance, on the above, it gives (with rs -zw60):

earum      aspernatur     ipsa       sed                    ┃
quod       sit            esse       quisquam               ┃
animi      reprehenderit  porro      et                     ┃
delectus   neque          esse       quia                   ┃
pariatur   amet           iste       voluptatem             ┃
provident  praesentium    et         sint                   ┃
quo        animi          doloribus  veritatis              ┃
iusto      alias                                            ┃

Instead of:

earum      aspernatur   ipsa       sed    quod              ┃
sit        esse         quisquam   animi  reprehenderit     ┃
porro      et           delectus   neque  esse              ┃
quia       pariatur     amet       iste   voluptatem        ┃
provident  praesentium  et         sint   quo               ┃
animi      doloribus    veritatis  iusto  alias             ┃

It also doesn't work with multi-byte characters or 0-width or double-width characters.

By default, it leaves at least 2 spaces between the columns. You can change it to 1 with -g 1.