Wrap and indent text using coreutils

coreutilsfoldmaketext formattingtext processing

Short version

I would like to create a tabular display of multiline text, similar to the following:

all       Build all targets
document  Create documentation of source files in the subfolders
          `src` and `script`, and write it to `man`
test      Run unit tests

At the moment, my input for this looks as follows, but this can of course be changed:

all---Build all targets
document---Create documentation of source files in the subfolders `src` and `script`, and write it to `man`
test---Run unit tests

I’ve tried achieving this with a combination of awk and wrap/pr but while the line wrapping works, the indentation doesn’t. Here’s my current approach:

…
| awk -F '---' "{ printf '%-10s %s\n', $1, $2 }" \
| fold -w $(($COLUMNS - 1)) -s

It generates the output

all       Build all targets
document  Create documentation of source files in the subfolders
`src` and `script`, and write it to `man`
test      Run unit tests

… in other words, the third line isn’t indented as intended.

How can I format the text with a given wrap length and a given hanging indent width? — Without changing anything else about the text. Bonus: this should work with UTF-8 and escape/control characters.


Background info

The goal is to create self-documenting Makefiles. As a consequence, the logic to format and display the code should be small, self-contained, and not rely on separately installed software; ideally, it should work on any system that can execute Makefiles, hence my restriction to (something close to) coreutils.

That said, I briefly tried solving the problem using groff but this became too complex very quickly (and OS X groff is and old version that doesn’t seem to support UTF-8).

The original string that I’m trying to parse and format therefore looks rather as follows:

## Build all targets
all: test document

## Run unit tests
test:
    ./run-tests .

## create documentation of source files in the subfolders `src` and `script`,
## and write it to `man`
document:
    ${MAKE} -C src document
    ${MAKE} -C script document

At the moment, this is parsed using a sed script (see link for details) that ignores multiline comments, before being fed to the formatting code posted above.

Best Answer

With gnu awk you can do something simple like this:

awk -F '---' '
{ gsub(/.{50,60} /,"&\n           ",$2)
  printf "%-10s %s\n", $1, $2 }'

For a more accurate long-winded version handling long words:

awk -F '---' '
{ printf "%-10s ", $1
  n = split($2,x," ")
  len = 11
  for(i=1;i<=n;i++){
   if(len+length(x[i])>=80){printf "\n           "; len = 11}
   printf "%s ",x[i]
   len += 1+length(x[i])
  }
  printf "\n"
}'
Related Question