Show HN: I wrote a program to convert lines of text into trees
<p><pre><code>  $ find &#x2F;etc&#x2F;network | .&#x2F;frangi.tl
  etc:
      network:
          if-post-down.d:
              wireless-tools wpasupplicant avahi-daemon 
          if-down.d:
              resolvconf wpasupplicant avahi-autoipd 
          interfaces.d interfaces if-pre-up.d:
              wireless-tools wpasupplicant ethtool 
          if-up.d:
              ntpdate wpasupplicant 000resolvconf openssh-server ethtool avahi-autoipd slrn avahi-daemon 

  $ find &#x2F;etc&#x2F;network | .&#x2F;frangi-cheat.tl 
  &#x2F;etc&#x2F;network
              &#x2F;if-post-down.d
                             &#x2F;wireless-tools
                             &#x2F;wpasupplicant
                             &#x2F;avahi-daemon
              &#x2F;if-down.d
                        &#x2F;resolvconf
                        &#x2F;wpasupplicant
                        &#x2F;avahi-autoipd
              &#x2F;interfaces.d
              &#x2F;interfaces
              &#x2F;if-pre-up.d
                          &#x2F;wireless-tools
                          &#x2F;wpasupplicant
                          &#x2F;ethtool
              &#x2F;if-up.d
                      &#x2F;ntpdate
                      &#x2F;wpasupplicant
                      &#x2F;000resolvconf
                      &#x2F;openssh-server
                      &#x2F;ethtool
                      &#x2F;avahi-autoipd
                      &#x2F;slrn
                      &#x2F;avahi-daemon

  $ cat frangi-cheat.tl
  #!&#x2F;usr&#x2F;bin&#x2F;env txr
  (let (old-path)
    (whilet ((line (get-line)))
      (whenlet ((path (tok #&#x2F;[^\&#x2F;]*&#x2F; line))
                (canon `@{path &quot;&#x2F;&quot;}`)
                (pos (mismatch path old-path)))
        (let ((cpos (max 0 (+ pos -1 [sum [path 0..pos] len]))))
          (put-line `@{&quot;&quot; cpos}@{canon [cpos..:]}`))
        (set old-path path))))


  $ cat frangi.tl
  #!&#x2F;usr&#x2F;bin&#x2F;env txr

  (defstruct (node name) list-builder
    name

    (:method equal (me) me.name)

    (:method ensure-child (me child-name)
      (let ((children me.(get)))
        (or (find child-name me.(get))
            (let ((new-child (new (node child-name))))
              me.(add new-child)
              new-child))))

    (:method print (me stream : pretty-p)
      (let* ((old-im (set-indent-mode stream indent-code))
             (old-id (get-indent stream))
             (children me.(get))
             (is-bottom (none children .(get))))
        (unwind-protect
          (cond
            (children
              (put-line `@{me.name}:` stream)
              (set-indent stream (+ old-id 4))
              [mapdo (op print @1 stream) children]
              (when is-bottom
                (put-char #\newline stream)))
            (t (put-string `@{me.name} `) stream))
          (set-indent-mode stream old-im)
          (set-indent stream old-id)))))

  (let ((supernode (new (node :root))))
    (whilet ((line (get-line)))
      (let ((path (tok #&#x2F;[^\&#x2F;]+&#x2F; line))
            (node supernode))
        (each ((comp path))
          (set node node.(ensure-child comp)))))
    (each ((top-child supernode.(get)))
      (pprinl top-child)))</code></pre>