#lang racket
(require srfi/13)


This script indents elements as in a left-aligned table.
Left indentation is preserved.
The column separator is the double-space (in fact a space longer than 1).
All lines must have the same number of separators (columns).

For example (note the double-spaces):

  (let ([some-value  '(some list of things)]
        [some-othe-value  2]
        [finally-some-value-again  '(a list of items)])

Select the 3 lines, and apply the script.
This will reformat as follows:

  (let ([some-value                '(some list of things)]
        [some-othe-value           2]
        [finally-some-value-again  '(a list of items)])

In case the number of columns does not match on each line,
empty columns are added at the end of the shortest rows.


(provide item-callback)
(define (item-callback str) 
  ; split in lines:
  (define lines 
    (port->lines (open-input-string str)))
  ;(pretty-write lines)
  ; split in columns, after removing all leading and trailing spaces:
  (define llines2 
    (for/list ([l lines])
      (regexp-split #px"\\s\\s+" (string-trim-both l))))
  ; pad too short lists with empty columns:
  (define llines3
    (let ([lmax (apply max (map length llines2))])
      (map (λ(ll)(append ll (build-list (- lmax (length ll)) (λ _ ""))))
  ; re-prepend the leading spaces to preserve indentation:
  (define llines
    (map (λ(ll l)(cons (string-append (first (regexp-match #px"^\\s*" l)) (first ll))
                       (rest ll)))
         llines3 lines))
  ;(pretty-write llines)
  ; pad each item in each column to the length of the longest item in the column:
  (define lcols (apply map (λ items (let ([lmax (apply max (map string-length items))])
                                      (map (λ(s)(string-pad-right s (+ 2 lmax))) items)))
  ;(pretty-write lcols)
  ; make the string for each line, and remove trailing spaces (last column has also been resized):
  (define indented-lines 
    (apply map (λ items (string-trim-right (apply string-append items)))
  ; append all the lines:
  (define str-new
    (apply string-append (add-between indented-lines "\n")))
  ; append a newline if there was one in the input string (may have been lost at the first step):
  (if (string=? (string-take-right str 1) "\n")
      (string-append str-new "\n")

 (item-callback "a  b  c    
   aa  bb  cc  dd  ee
aaaa  bbb    ccccc  dddd
x    y  z  

 (item-callback "(let ([xxx  1]
      [yy  2]
      [zzzzz  43])

 (item-callback "(define something      5)
(define some-other-thing  '(let me know))