aboutsummaryrefslogtreecommitdiff

tt ('tangle to')

Synopsis
Syntax
Example 1
Example 2

Synopsis

tt [-cCODE_PREFIX] [-dDOC_PREFIX] [-oOUT_PREFIX] destinations [...]

tt is a tool for source code organization and/or literate programming, which takes source code organized in a human-friendly manner and 'tangles' it into source code organized in a computer-friendly manner.

It takes any number of destination files as command-line arguments and source input on the standard input -- for example:

$ tt computerfriendly.c < humanfriendly.c
  • Destination files are templates for the 'tangled' (computer-friendly) source code. They contain special sequences marking destinations: for example, <<top>>, <<middle>> and <<bottom>>.
  • Source input, in turn, contains special sequences referencing these destinations: -> top, -> middle and -> bottom. For instance, all code following -> top will be inserted at any location marked by <<top>> in the destination files.

Syntax

Source input

Source files contain code lines and documentation lines, formatted accordingly:
code line ::= CODE_PREFIX anything
documentation line ::= DOC_PREFIX anything [reference]

reference ::= "->" [whitespace] identifier [whitespace]
identifier ::= not whitespace

The default value of CODE_PREFIX is '    ' (four spaces), while DOC_PREFIX, by default, is empty.

Documentation lines containing references cause all subsequent code lines to be tangled to the corresponding identifier(s) in destination files (until the next documentation line containing a reference).

Destination files

The files given as command-line arguments to tt, in this case scripts.ahk, contain destination lines and plain text lines.
destination line ::= [indentation] "<<" identifier ">>"
plain text line ::= anything

indentation ::= " " [indentation]

Any indentation preceding an identifier will be preserved when the code lines from the source input are inserted.

Example 1: Pulling separate modules into a single file

Assuming the files

plugins/nerdtree.vim
plugins/vimtex.vim
vimrc
" -> plugins
Plug 'scrooloose/nerdtree'
let g:NERDTreeWinSize = 30
" -> plugins
Plug 'lervag/vimtex'
let g:tex_flavor = 'latex'
call plug#begin('~/.vim/plug')
<<plugins>>
call plug#end()

then the shell command

$ tt -d\" -c -o$HOME/. vimrc < plugins/nerdtree.vim < plugins/vimtex.vim

would create the file $HOME/.vimrc with the following contents:

$HOME/.vimrc
call plug#begin('~/.vim/plug')
Plug 'scrooloose/nerdtree'
let g:NERDTreeWinSize = 30
Plug 'lervag/vimtex'
let g:tex_flavor = 'latex'
call plug#end()

Example 2: Creating source code from literate program

tt is also well-suited for more traditional literate programming, and its default options work especially well with Markdown syntax.

It differs, however, from most other literate programming tools in that it doesn't resolve references within the same file. If this is desired, then multiple passes are required.

Assuming the files

program.markdown
program.c
# My program -> program.c

<<declarations>>
<<main>>

## Main function -> main

Here is the main function:

int main(int argc, char *argv[]) {
int i;
<<main.options>>
...
}

### Command-line options -> main.options

for (i = 1; i < argc; i++)
...

### Declarations -> declarations

So far, we have used the following global variables:

char *line;
int line_length;
int line_size;
<<program.c>>

then the shell commands

$ mkdir 1 2 out
$ tt -d"#" -o1/ program.markdown < program.markdown
$ tt -d"#" -o2/ program.markdown < 1/program.markdown
$ tt -d"#" -oout/ program.c < 2/program.markdown

would create the file out/program.c with the following contents:

out/program.c
char *line;
int line_length;
int line_size;
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i++)
...
...
}

Three separate passes are required, because there are, in total, three re-locations of source code:

  1. → main.options
  2. → main, declarations
  3. program.c

This could conceivably be automated with a simple shell script:

#!/bin/sh
mkdir tmp out
file=program.markdown
i=0
cp $file tmp/$i$file
while grep '^ *<<[^\s]>>$' tmp/$i$file > /dev/null; do
tt -d"#" -otmp/$((++i)) $file < tmp/$((i-1))$file
done
tt -d"#" -oout/ program.c < $i$file