Merge branch 'error_handler' of https://bitbucket.org/designst/mako/overview into t
diff --git a/mako/codegen.py b/mako/codegen.py
index 63e76a7..679acf8 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -276,6 +276,7 @@
                 self.printer.writeline(
                                 "@runtime._decorate_toplevel(%s)" % decorator)
 
+        self.printer.start_source(node.lineno)
         self.printer.writelines(
             "def %s(%s):" % (name, ','.join(args)),
                 # push new frame, assign current frame to __M_caller
diff --git a/mako/exceptions.py b/mako/exceptions.py
index 20b4dce..028ae75 100644
--- a/mako/exceptions.py
+++ b/mako/exceptions.py
@@ -176,7 +176,8 @@
                                     template_source.split("\n")]
                 mods[filename] = (line_map, template_lines)
 
-            template_ln = line_map[lineno]
+            template_ln = line_map[lineno - 1]
+
             if template_ln <= len(template_lines):
                 template_line = template_lines[template_ln - 1]
             else:
diff --git a/mako/pygen.py b/mako/pygen.py
index dfd83d3..0ee19f0 100644
--- a/mako/pygen.py
+++ b/mako/pygen.py
@@ -27,7 +27,7 @@
         self.stream = stream
 
         # current line number
-        self.lineno = 0
+        self.lineno = 1
 
         # a list of lines that represents a buffered "block" of code,
         # which can be later printed relative to an indent level
@@ -39,9 +39,9 @@
 
         # marker for template source lines; this
         # is part of source/template line mapping
-        self.last_source_line = -1
+        self.last_source_line = 0
 
-        self.last_boilerplate_line = -1
+        self.last_boilerplate_line = 0
 
         # mapping of generated python lines to template
         # source lines
diff --git a/mako/template.py b/mako/template.py
index 39ff8bd..a747feb 100644
--- a/mako/template.py
+++ b/mako/template.py
@@ -605,17 +605,14 @@
         source_map['line_map'] = dict((int(k), int(v))
                                     for k, v in source_map['line_map'].items())
         if full_line_map:
-            line_map = source_map['full_line_map'] = dict(
-                (k, v) for k, v in source_map['line_map'].items()
-            )
+            f_line_map = source_map['full_line_map'] = []
+            line_map = source_map['line_map']
 
-            for mod_line in reversed(sorted(line_map)):
-                tmpl_line = line_map[mod_line]
-                while mod_line > 0:
-                    mod_line -= 1
-                    if mod_line in line_map:
-                        break
-                    line_map[mod_line] = tmpl_line
+            curr_templ_line = 1
+            for mod_line in range(1, max(line_map)):
+                if mod_line in line_map:
+                    curr_templ_line = line_map[mod_line]
+                f_line_map.append(curr_templ_line)
         return source_map
 
     @property
diff --git a/test/test_template.py b/test/test_template.py
index 6c30c8a..3dd42be 100644
--- a/test/test_template.py
+++ b/test/test_template.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-from mako.template import Template, ModuleTemplate
+from mako.template import Template, ModuleTemplate, ModuleInfo
 from mako.lookup import TemplateLookup
 from mako.ext.preprocessors import convert_comments
 from mako import exceptions, runtime
@@ -12,6 +12,7 @@
 from test import TemplateTest, eq_, template_base, module_base, \
     requires_python_26_or_greater, assert_raises, assert_raises_message, \
     requires_python_2
+import unittest
 
 class ctx(object):
     def __init__(self, a, b):
@@ -1235,6 +1236,31 @@
             "This is base.", "0", "1", "2", "3", "4"
         ]
 
+class TestTemplateAPI(unittest.TestCase):
+    def test_metadata(self):
+        t = Template("""
+Text
+Text
+% if bar:
+    ${expression}
+% endif
+
+<%include file='bar'/>
+
+""", uri="/some/template")
+        eq_(
+            ModuleInfo.get_module_source_metadata(t.code, full_line_map=True),
+            {
+                'source_encoding': 'ascii',
+                'uri': '/some/template',
+                'filename': None,
+                'boilerplate_lines': [1, 21],
+                'full_line_map': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                                1, 1, 1, 1, 1, 1, 1, 4, 5, 5, 5, 7, 8, 8,
+                                8, 8, 8, 8, 8],
+                'line_map': {34: 8, 21: 1, 22: 4, 23: 5, 26: 7, 27: 8}
+            }
+        )
 
 class PreprocessTest(TemplateTest):
     def test_old_comments(self):