Version 3 of Trimming indentation

Updated 2014-06-14 13:35:13 by pooryorick

dbohdan 2014-06-14: I wanted to have a multiline string help message indented to the level of the rest of the code. The following procedure unindents it appropriately but keeps the relative indentation.

# Trim indentation in multiline quoted text based on the first line's.
proc trim-indentation {msg} {
    set msgLines [split $msg \n]
    if {[lindex $msgLines 0] eq {}} {
        shift msgLines
    }

    set firstLine [lindex $msgLines 0]

    set indent [
        expr {
            [string length $firstLine] -
            [string length [string trimleft $firstLine]]
        }
    ]

    return [
        join [
            struct::list mapfor x $msgLines {string range $x $indent end}
        ] \n
    ]
}

Use example

[...]
    if {[llength $args] == 0} {
        # Print help
        puts -nonewline [
            trim-indentation {
                Command pipelines for interactive programming.

                usage:
                    |> cmd1 |> cmd2 _ |> cmd3 #0 ?-debug?
                or
                    |> { cmd1 |> cmd2 $_ |> cmd3 $pipe(0) } ?-debug?

                See http://wiki.tcl.tk/17419 for more.
            }
            return
        ]
        # End help
    }
[...]

Output

Command pipelines for interactive programming.

usage:
    |> cmd1 |> cmd2 _ |> cmd3 #0 ?-debug?
or
    |> { cmd1 |> cmd2 $_ |> cmd3 $pipe(0) } ?-debug?

See http://wiki.tcl.tk/17419 for more.

PYK 2014-06-14: What does shift do? This implementation uses the simplistic method of counting the number of characters trimmed from the first line, and fails for cases where the first line is more indented than other lines. To do the job right, see textutil::undent. Also, as of 8.6, lmap is the built-in replacement for struct::list mapfor.