diff --git a/main.py b/main.py
index 2ac5c79fe756701d7d61f62b6750ef5f71976c81..1cf91c2fcd13a70888f5e45184f9988ad0895c1c 100644
--- a/main.py
+++ b/main.py
@@ -110,10 +110,6 @@ def print_var(x: str, dollar: bool = True) -> None:
 
 # TODO strip leading colons when looking up documentation
 
-# TODO context
-# - in heredoc (for strings)
-# - if variable is in string
-
 
 symbols: dict[str, str] = {
     '=>': '⇒',
@@ -269,7 +265,7 @@ def parse(form: Any, indent: int, context: list[str]) -> None:
                     case ['str', thingy]:
                         print('<span class="str-var">${', end='')
                         # print_var(x, dollar=False)
-                        parse(thingy, indent, context)
+                        parse(thingy, indent, ['str'] + context)
                         print('}</span>', end='')
                     case s:
                         # print(s, file=sys.stderr)
@@ -365,9 +361,18 @@ def parse(form: Any, indent: int, context: list[str]) -> None:
                 print('}', end='')
 
         case ['heredoc', {'text': text}]:
+            # TODO Should variables be interploated?
+            # TODO a safe string to use?
+            # TODO extra options?
+            # Are all these already removed by the parser, requiring
+            # us to reverse parse the text?
+            #
+            # NOTE text can be a number of types
+            # It can be an explicit "concat",
+            # it can be an untagged string
             print('@("EOF")')
-            parse(text, indent, context)
-            print(' '*indent*2 + '|')
+            parse(text, indent + 1, ['heredoc'] + context)
+            print(' '*(indent+1)*2 + '| EOF', end='')
 
         case ['if', {'test': test,
                      **rest}]:
@@ -612,7 +617,9 @@ def parse(form: Any, indent: int, context: list[str]) -> None:
             print(' '*indent*2 + '}', end='')
 
         case ['var', x]:
-            print_var(x)
+            # TODO how does this work with deeply nested expressions
+            # in strings?
+            print_var(x, context[0] != 'str')
 
         case ['virtual-query', q]:
             print('<| ', end='')
@@ -744,8 +751,21 @@ def parse(form: Any, indent: int, context: list[str]) -> None:
 
         case form:
             if type(form) == str:
-                s = form.replace('\n', r'\n')
-                print(f"<span class=\"string\">'{s}'</span>", end='')
+                print('<span class="string">', end='')
+                if context[0] == 'heredoc':
+                    ind = ' '*indent*2
+                    lines: list[str]
+                    match form.split('\n'):
+                        case [*_lines, '']:
+                            lines = _lines
+                        case _lines:
+                            lines = _lines
+                    for line in lines:
+                        print(ind + line)
+                else:
+                    s = form.replace('\n', r'\n')
+                    print(f"'{s}'", end='')
+                print('</span>', end='')
             elif type(form) == int or type(form) == float:
                 print(f'<span class="number">{form}</span>', end='')
             else:
@@ -816,7 +836,7 @@ for d_type in data['puppet_classes']:
     print('<pre><code class="puppet">')
     tree = parse_puppet(d_type['source'])
     t = traverse(tree)
-    parse(t, 0, [])
+    parse(t, 0, ['root'])
     print('</code></pre>')
 
     print('<hr/>')
@@ -834,7 +854,7 @@ for d_type in data['data_type_aliases']:
     print('<pre><code class="puppet">')
     tree = parse_puppet(d_type['alias_of'])
     t = traverse(tree)
-    parse(t, 0, [])
+    parse(t, 0, ['root'])
     print('</code></pre>')
 
     print('<hr/>')
@@ -849,7 +869,7 @@ for d_type in data['defined_types']:
     print('<pre><code class="puppet">')
     tree = parse_puppet(d_type['source'])
     t = traverse(tree)
-    parse(t, 0, [])
+    parse(t, 0, ['root'])
     print('</code></pre>')
 
     print('<hr/>')
@@ -898,7 +918,7 @@ for function in data['puppet_functions']:
         try:
             tree = parse_puppet(function['source'])
             t = traverse(tree)
-            parse(t, 0, [])
+            parse(t, 0, ['root'])
         except CalledProcessError as e:
             print(e)
         print('</code></pre>')