screwing around with the exception formatting a bit
diff --git a/lib/mako/exceptions.py b/lib/mako/exceptions.py
index 78c5730..ff53ba8 100644
--- a/lib/mako/exceptions.py
+++ b/lib/mako/exceptions.py
@@ -49,6 +49,7 @@
     # rawrecords = traceback.extract_stack() + rawrecords 
     new_trcback = []
     for filename, lineno, function, line in rawrecords:
+        #print "TB", filename, lineno, function, line
         try:
             (line_map, template_lines) = mods[filename]
         except KeyError:
@@ -56,9 +57,9 @@
                 info = mako.template._get_module_info(filename)
                 module_source = info.code
                 template_source = info.source
-                template_filename = info.template_filename
+                template_filename = info.template_filename or filename
             except KeyError:
-                new_trcback.append((filename, lineno, function, line, None, None, None))
+                new_trcback.append((filename, lineno, function, line, None, None, None, None))
                 continue
 
             template_ln = module_ln = 1
@@ -79,19 +80,16 @@
             template_line = template_lines[template_ln - 1]
         else:
             template_line = None
-        new_trcback.append((filename, lineno, function, line, template_filename, template_ln, template_line))
+        new_trcback.append((filename, lineno, function, line, template_filename, template_ln, template_line, template_source))
     return (type, value, new_trcback)
-    
-# TODO: this is scratch, make a module for exception reporting templates
-def get_error_template():
+
+def text_error_template():
     import mako.template
-    return mako.template.Template("""
+    return mako.template.Template(r"""
 <%!
     from mako.exceptions import rich_traceback
 %>
-<html>
-<body>
-    Error !
+Error !
 <%
     (type, value, trcback) = rich_traceback()
 %>
@@ -99,10 +97,43 @@
 ${str(type)} - ${value}
 
 % for (filename, lineno, function, line, template_filename, template_ln, template_line) in trcback:
+    % if template_line:
+    ${template_filename} ${template_ln} ${template_line}
+    % else:
+    ${filename} ${lineno} ${line}
+    % endif
+% endfor
+""")
+
+def html_error_template():
+    import mako.template
+    return mako.template.Template(r"""
+<%!
+    from mako.exceptions import rich_traceback
+%>
+<html>
+<body>
+    Error !
+<%
+    (errtype, value, trcback) = rich_traceback()
+    src = trcback[-1][7]
+    line = trcback[-1][5]
+    lines = src.split('\n')
+    trcback.reverse()
+    
+%>
+
+${str(error)}
+
+<div>
+${'\n'.join(lines[line-5:line+5])}
+</div>
+
+% for (filename, lineno, function, line, template_filename, template_ln, template_line, src) in trcback:
         % if template_line:
         ${template_filename} ${template_ln} ${template_line} <br/>
         % else:
-        ${filename} ${lineno} ${line} ${template_filename} ${template_ln}<br/>
+        ${filename} ${lineno} ${line}<br/>
         % endif
 % endfor
 </body>
diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py
index 15b35bb..01a23a9 100644
--- a/lib/mako/runtime.py
+++ b/lib/mako/runtime.py
@@ -6,7 +6,7 @@
 
 """provides the Context class, the runtime namespace for templates."""
 from mako import exceptions, util
-import inspect
+import inspect, sys
         
 class Context(object):
     """provides runtime namespace, output buffer, and various callstacks for templates."""
@@ -179,6 +179,7 @@
     else:
         buf = util.StringIO()
     context = Context(buf, **data)
+    context._with_template = template
     kwargs = {}
     argspec = inspect.getargspec(callable_)
     namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
@@ -186,10 +187,9 @@
         if arg != 'context' and arg in data:
             kwargs[arg] = data[arg]
     _render_context(template, callable_, context, *args, **kwargs)
-    return buf.getvalue()
+    return context.pop_buffer().getvalue()
 
 def _render_context(template, callable_, context, *args, **kwargs):
-    context._with_template = template
     # create polymorphic 'self' namespace for this template with possibly updated context
     (inherit, lclcontext) = _populate_self_namespace(context, template)
     if callable_.__name__ == 'render':
@@ -221,8 +221,9 @@
                 if not result:
                     raise error
             else:
-                # TODO - friendly error formatting
-                source = _get_template_source(callable_)
-                raise error
+                context._buffer_stack = [util.StringIO()]
+                error_template = exceptions.html_error_template()
+                context._with_template = error_template
+                error_template.render_context(context, error=error)
     else:
         callable_(context, *args, **kwargs)
diff --git a/lib/mako/template.py b/lib/mako/template.py
index 4313013..700a022 100644
--- a/lib/mako/template.py
+++ b/lib/mako/template.py
@@ -12,31 +12,7 @@
 from mako import runtime, util, exceptions
 import imp, time, weakref, tempfile, shutil,  os, stat, posixpath, sys, re
 
-_modules = weakref.WeakValueDictionary()
-_inmemory_templates = weakref.WeakValueDictionary()
 
-class _ModuleInfo(object):
-    def __init__(self, module, module_filename, template, template_filename, module_source, template_source):
-        self.module = module
-        self.module_filename = module_filename
-        self.template_filename = template_filename
-        self.module_source = module_source
-        self.template_source = template_source
-        _modules[module.__name__] = template._mmarker = self
-        if module_filename:
-            _modules[module_filename] = self
-    def _get_code(self):
-        if self.module_source is not None:
-            return self.module_source
-        else:
-            return file(self.module_filename).read()
-    code = property(_get_code)
-    def _get_source(self):
-        if self.template_source is not None:
-            return self.template_source
-        else:
-            return file(self.template_filename).read()
-    source = property(_get_source)
     
 class Template(object):
     """a compiled template"""
@@ -61,10 +37,9 @@
             
         if text is not None:
             (code, module) = _compile_text(text, self.identifier, filename)
-            _inmemory_templates[module.__name__] = self
             self._code = code
             self._source = text
-            _ModuleInfo(module, None, self, filename, code, text)
+            ModuleInfo(module, None, self, filename, code, text)
         elif filename is not None:
             if module_directory is not None:
                 path = posixpath.join(module_directory, self.identifier + ".py")
@@ -74,12 +49,12 @@
                     _compile_module_file(file(filename).read(), identifier, filename, path)
                 module = imp.load_source(self.identifier, path, file(path))
                 del sys.modules[self.identifier]
-                _ModuleInfo(module, path, self, filename, None, None)
+                ModuleInfo(module, path, self, filename, None, None)
             else:
                 (code, module) = _compile_text(file(filename).read(), self.identifier, filename)
                 self._source = None
                 self._code = code
-                _ModuleInfo(module, None, self, filename, code, None)
+                ModuleInfo(module, None, self, filename, code, None)
         else:
             raise exceptions.RuntimeException("Template requires text or filename")
 
@@ -92,8 +67,8 @@
         self.lookup = lookup
         self.output_encoding = output_encoding
 
-    source = property(lambda self:_get_template_source(self.callable_), doc="""return the template source code for this Template.""")
-    code = property(lambda self:_get_module_source_from_callable(self.callable_), doc="""return the module source code for this Template""")
+    source = property(lambda self:_get_module_info_from_callable(self.callable_).source, doc="""return the template source code for this Template.""")
+    code = property(lambda self:_get_module_info_from_callable(self.callable_).code, doc="""return the module source code for this Template""")
         
     def render(self, *args, **data):
         """render the output of this template as a string.
@@ -113,6 +88,8 @@
         """render this Template with the given context.  
         
         the data is written to the context's buffer."""
+        if getattr(context, '_with_template', None) is None:
+            context._with_template = self
         runtime._render_context(self, self.callable_, context, *args, **kwargs)
         
     def get_def(self, name):
@@ -126,6 +103,32 @@
         self.callable_ = callable_
     def get_def(self, name):
         return self.parent.get_def(name)
+
+class ModuleInfo(object):
+    """stores information about a module currently loaded into memory."""
+    _modules = weakref.WeakValueDictionary()
+
+    def __init__(self, module, module_filename, template, template_filename, module_source, template_source):
+        self.module = module
+        self.module_filename = module_filename
+        self.template_filename = template_filename
+        self.module_source = module_source
+        self.template_source = template_source
+        self._modules[module.__name__] = template._mmarker = self
+        if module_filename:
+            self._modules[module_filename] = self
+    def _get_code(self):
+        if self.module_source is not None:
+            return self.module_source
+        else:
+            return file(self.module_filename).read()
+    code = property(_get_code)
+    def _get_source(self):
+        if self.template_source is not None:
+            return self.template_source
+        else:
+            return file(self.template_filename).read()
+    source = property(_get_source)
         
 def _compile_text(text, identifier, filename):
     node = Lexer(text, filename).parse()
@@ -148,5 +151,5 @@
     return _get_module_info(callable_.func_globals['__name__'])
     
 def _get_module_info(filename):
-    return _modules[filename]
+    return ModuleInfo._modules[filename]
         
diff --git a/test/lexer.py b/test/lexer.py
index c4fd5f4..8b7fe67 100644
--- a/test/lexer.py
+++ b/test/lexer.py
@@ -208,6 +208,13 @@
         nodes = Lexer(template).parse()
         assert repr(nodes) == r"""TemplateNode({}, [Code("print 'hi %>' \n", False, (1, 1))])"""
         
+        template = r"""
+        <%
+            lines = src.split('\n')
+        %>
+"""
+        nodes = Lexer(template).parse()
+        
     def test_control_lines(self):
         template = """
 text text la la
diff --git a/test/template.py b/test/template.py
index 6e1b48e..6c9c4ef 100644
--- a/test/template.py
+++ b/test/template.py
@@ -1,7 +1,7 @@
 # -*- encoding: utf-8 -*-
 
 from mako.template import Template
-import unittest
+import unittest, re
 from util import flatten_result, result_lines
 
 class EncodingTest(unittest.TestCase):
@@ -41,6 +41,19 @@
         y is ${y}
 """)
         assert t.render().strip() == "y is hi"
+
+class FormatExceptionTest(unittest.TestCase):
+    def test_html(self):
+        t = Template("""
         
+            hi there.
+            <%
+                raise "hello"
+            %>
+        """, format_exceptions=True)
+        res = t.render()
+        print res
+    
+            
 if __name__ == '__main__':
     unittest.main()