[MC]: The various [TeX] variants are very powerful ways to typeset documents. (My favorites are http://wiki.contextgarden.net/XeTeX%|%ConTeXt & XeTeX%|%.) Most of my projects involve typesetting data that is retrieved out of a database, so Tcl is my go to language. I can write a script that reads the data and marks it up, then render it to PDF, see if I like it, and tweak as necessary until I have something I'm happy with. Since TeX commands look like `\command[[argument]][[arg2...]]` the backslash and brackets would need to be escaped for the Tcl interpreter, and that gets tiresome rather quickly. Hence the following small package that allows me to write TeX in a Tcl-ish way: `@ command `. ====== namespace eval TeXutil { variable buf "" variable map {@ \\ & & < < > > &at; @ < \[ > \] ( \{ ) \}} proc @ {cmd args} { >> @$cmd[join $args ""]\n } proc %@ {cmd args} { % @$cmd {*}$args } proc >> {args} { variable buf variable map append buf [string map -nocase $map [join $args ""]] } proc << {} { variable buf set out $buf set buf "" return $out } proc % {args} { >> %[join [split [join $args " "] \n] \n%]\n } namespace export << %@ @ % >> namespace ensemble create } package provide TeXutil 1.0 ====== So the script: ====== namespace import TeXutil::* @ setuppapersize @ starttext >> "Hello world" \n @ stoptext puts [<<] ====== Would produce: ======none \setuppapersize[A6] \starttext Hello world \stoptext ====== [AMG]: I added () -> {} mapping for the sake of [LaTeX]. ---- [AMG]: Here's an incompatible, bare-bones version: ====== proc >> {varName args} { upvar 1 $varName var append var \n[string map\ {`` ` `< < `> > `( ( `) ) ` \\ < \[ > \] ( \{ ) \}} [join $args]] } ====== The idea here is that the backtick is a stand-in for backslash. It's used to "quote" a limited number of special characters, those being angle brackets, parentheses, and backtick. A backtick not followed by one such special is replaced with a \\backslash. are replaced with [[square brackets]], and (parentheses) are replaced with {squirrely braces}. Single-argument [[[join]]] is used because LaTeX doesn't care about extra whitespace in the places where I'd expect to see separate arguments. Also I put an extra newline at the beginning because I'm lazy and LaTeX doesn't mind. The name of the buffer variable is explicitly specified as the first argument. To get the contents of the buffer, just read the variable. Real-life example snippet: ======none >> latex % Define page layout. >> latex `documentclass(report) >> latex `usepackage\ (geometry) >> latex % Customize section headers. >> latex `usepackage(titlesec) >> latex `titleformat(`section)()()(4pt)(`Large`bfseries) >> latex `newcommand`sectionbreak(`ifnum`value(section)`>1`clearpage`fi) >> latex % Define \"d\" tabular column type for decimal alignment. >> latex `usepackage(dcolumn) >> latex `newcolumntype(d)(D(.)(.)(-1)) >> latex % Remove standard header and footer. >> latex `pagestyle(empty) >> latex `begin(document) set latex ====== Produces (with a blank line at the beginning): ======none % Define page layout. \documentclass[letterpaper]{report} \usepackage[landscape,left=1cm,top=1cm,right=1cm,bottom=1cm] {geometry} % Customize section headers. \usepackage{titlesec} \titleformat{\section}[frame]{}{}{4pt}{\Large\bfseries} \newcommand\sectionbreak{\ifnum\value{section}>1\clearpage\fi} % Define "d" tabular column type for decimal alignment. \usepackage{dcolumn} \newcolumntype{d}{D{.}{.}{-1}} % Remove standard header and footer. \pagestyle{empty} \begin{document} ====== Notice the need to quote the greater-than sign with a leading backtick. Oh yeah, here's the matching quote utility: ====== proc >>quote {str} { string map {` `` < `< > `> ( `( ) `)} $str } ====== <> Word and Text Processing