fix render error position in templates
diff --git a/include/inja/node.hpp b/include/inja/node.hpp
index 8a1102f..83a3ca6 100644
--- a/include/inja/node.hpp
+++ b/include/inja/node.hpp
@@ -119,11 +119,11 @@
 
   json value;
   std::string str;
-  nonstd::string_view view;
+  size_t pos;
 
-  explicit Node(Op op, unsigned int args = 0) : op(op), args(args), flags(0) {}
-  explicit Node(Op op, nonstd::string_view str, unsigned int flags) : op(op), args(0), flags(flags), str(str), view(str) {}
-  explicit Node(Op op, json &&value, unsigned int flags) : op(op), args(0), flags(flags), value(std::move(value)) {}
+  explicit Node(Op op, unsigned int args, size_t pos) : op(op), args(args), flags(0), pos(pos) {}
+  explicit Node(Op op, nonstd::string_view str, unsigned int flags, size_t pos) : op(op), args(0), flags(flags), str(str), pos(pos) {}
+  explicit Node(Op op, json &&value, unsigned int flags, size_t pos) : op(op), args(0), flags(flags), value(std::move(value)), pos(pos) {}
 };
 
 } // namespace inja
diff --git a/include/inja/parser.hpp b/include/inja/parser.hpp
index d2cb76f..56a6484 100644
--- a/include/inja/parser.hpp
+++ b/include/inja/parser.hpp
@@ -273,7 +273,7 @@
           // normal literal (json read)
 
           auto flag = config.notation == ElementNotation::Pointer ? Node::Flag::ValueLookupPointer : Node::Flag::ValueLookupDot;
-          tmpl.nodes.emplace_back(Node::Op::Push, tok.text, flag);
+          tmpl.nodes.emplace_back(Node::Op::Push, tok.text, flag, tok.text.data() - tmpl.content.c_str());
           get_next_token();
           return true;
         }
@@ -337,7 +337,7 @@
   returnJson:
     // bridge across all intermediate tokens
     nonstd::string_view json_text(json_first.data(), tok.text.data() - json_first.data() + tok.text.size());
-    tmpl.nodes.emplace_back(Node::Op::Push, json::parse(json_text), Node::Flag::ValueImmediate);
+    tmpl.nodes.emplace_back(Node::Op::Push, json::parse(json_text), Node::Flag::ValueImmediate, tok.text.data() - tmpl.content.c_str());
     get_next_token();
     return true;
   }
@@ -359,7 +359,7 @@
       if_stack.emplace_back(static_cast<decltype(if_stack)::value_type::jump_t>(tmpl.nodes.size()));
 
       // conditional jump; destination will be filled in by else or endif
-      tmpl.nodes.emplace_back(Node::Op::ConditionalJump);
+      tmpl.nodes.emplace_back(Node::Op::ConditionalJump, 0, tok.text.data() - tmpl.content.c_str());
     } else if (tok.text == static_cast<decltype(tok.text)>("endif")) {
       if (if_stack.empty()) {
         throw_parser_error("endif without matching if");
@@ -389,7 +389,7 @@
       // end previous block with unconditional jump to endif; destination will be
       // filled in by endif
       if_data.uncond_jumps.push_back(tmpl.nodes.size());
-      tmpl.nodes.emplace_back(Node::Op::Jump);
+      tmpl.nodes.emplace_back(Node::Op::Jump, 0, tok.text.data() - tmpl.content.c_str());
 
       // previous conditional jump jumps here
       tmpl.nodes[if_data.prev_cond_jump].args = tmpl.nodes.size();
@@ -408,7 +408,7 @@
         if_data.prev_cond_jump = tmpl.nodes.size();
 
         // conditional jump; destination will be filled in by else or endif
-        tmpl.nodes.emplace_back(Node::Op::ConditionalJump);
+        tmpl.nodes.emplace_back(Node::Op::ConditionalJump, 0, tok.text.data() - tmpl.content.c_str());
       }
     } else if (tok.text == static_cast<decltype(tok.text)>("for")) {
       get_next_token();
@@ -442,12 +442,11 @@
 
       loop_stack.push_back(tmpl.nodes.size());
 
-      tmpl.nodes.emplace_back(Node::Op::StartLoop);
+      tmpl.nodes.emplace_back(Node::Op::StartLoop, 0, tok.text.data() - tmpl.content.c_str());
       if (!key_token.text.empty()) {
         tmpl.nodes.back().value = key_token.text;
       }
       tmpl.nodes.back().str = static_cast<std::string>(value_token.text);
-      tmpl.nodes.back().view = value_token.text;
     } else if (tok.text == static_cast<decltype(tok.text)>("endfor")) {
       get_next_token();
       if (loop_stack.empty()) {
@@ -457,7 +456,7 @@
       // update loop with EndLoop index (for empty case)
       tmpl.nodes[loop_stack.back()].args = tmpl.nodes.size();
 
-      tmpl.nodes.emplace_back(Node::Op::EndLoop);
+      tmpl.nodes.emplace_back(Node::Op::EndLoop, 0, tok.text.data() - tmpl.content.c_str());
       tmpl.nodes.back().args = loop_stack.back() + 1; // loop body
       loop_stack.pop_back();
     } else if (tok.text == static_cast<decltype(tok.text)>("include")) {
@@ -483,7 +482,7 @@
       }
 
       // generate a reference node
-      tmpl.nodes.emplace_back(Node::Op::Include, json(pathname), Node::Flag::ValueImmediate);
+      tmpl.nodes.emplace_back(Node::Op::Include, json(pathname), Node::Flag::ValueImmediate, tok.text.data() - tmpl.content.c_str());
 
       get_next_token();
     } else {
@@ -504,7 +503,7 @@
     }
 
     // otherwise just add it to the end
-    tmpl.nodes.emplace_back(op, num_args);
+    tmpl.nodes.emplace_back(op, num_args, tok.text.data() - tmpl.content.c_str());
   }
 
   void append_callback(Template &tmpl, nonstd::string_view name, unsigned int num_args) {
@@ -515,15 +514,14 @@
         last.op = Node::Op::Callback;
         last.args = num_args;
         last.str = static_cast<std::string>(name);
-        last.view = name;
+        last.pos = name.data() - tmpl.content.c_str();
         return;
       }
     }
 
     // otherwise just add it to the end
-    tmpl.nodes.emplace_back(Node::Op::Callback, num_args);
+    tmpl.nodes.emplace_back(Node::Op::Callback, num_args, tok.text.data() - tmpl.content.c_str());
     tmpl.nodes.back().str = static_cast<std::string>(name);
-    tmpl.nodes.back().view = name;
   }
 
   void parse_into(Template &tmpl, nonstd::string_view path) {
@@ -541,7 +539,7 @@
         }
         return;
       case Token::Kind::Text:
-        tmpl.nodes.emplace_back(Node::Op::PrintText, tok.text, 0u);
+        tmpl.nodes.emplace_back(Node::Op::PrintText, tok.text, 0u, tok.text.data() - tmpl.content.c_str());
         break;
       case Token::Kind::StatementOpen:
         get_next_token();
diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp
index 44519f2..729c9bb 100644
--- a/include/inja/renderer.hpp
+++ b/include/inja/renderer.hpp
@@ -139,8 +139,7 @@
   }
 
   void throw_renderer_error(const std::string &message, const Node& node) {
-    size_t pos = node.view.data() - current_template->content.c_str();
-    SourceLocation loc = get_source_location(current_template->content, pos);
+    SourceLocation loc = get_source_location(current_template->content, node.pos);
     throw RenderError(message, loc);
   }
 
diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp
index 43691ca..814a7f3 100644
--- a/single_include/inja/inja.hpp
+++ b/single_include/inja/inja.hpp
@@ -1642,11 +1642,11 @@
 
   json value;
   std::string str;
-  nonstd::string_view view;
+  size_t pos;
 
-  explicit Node(Op op, unsigned int args = 0) : op(op), args(args), flags(0) {}
-  explicit Node(Op op, nonstd::string_view str, unsigned int flags) : op(op), args(0), flags(flags), str(str), view(str) {}
-  explicit Node(Op op, json &&value, unsigned int flags) : op(op), args(0), flags(flags), value(std::move(value)) {}
+  explicit Node(Op op, unsigned int args, size_t pos) : op(op), args(args), flags(0), pos(pos) {}
+  explicit Node(Op op, nonstd::string_view str, unsigned int flags, size_t pos) : op(op), args(0), flags(flags), str(str), pos(pos) {}
+  explicit Node(Op op, json &&value, unsigned int flags, size_t pos) : op(op), args(0), flags(flags), value(std::move(value)), pos(pos) {}
 };
 
 } // namespace inja
@@ -2622,7 +2622,7 @@
           // normal literal (json read)
 
           auto flag = config.notation == ElementNotation::Pointer ? Node::Flag::ValueLookupPointer : Node::Flag::ValueLookupDot;
-          tmpl.nodes.emplace_back(Node::Op::Push, tok.text, flag);
+          tmpl.nodes.emplace_back(Node::Op::Push, tok.text, flag, tok.text.data() - tmpl.content.c_str());
           get_next_token();
           return true;
         }
@@ -2686,7 +2686,7 @@
   returnJson:
     // bridge across all intermediate tokens
     nonstd::string_view json_text(json_first.data(), tok.text.data() - json_first.data() + tok.text.size());
-    tmpl.nodes.emplace_back(Node::Op::Push, json::parse(json_text), Node::Flag::ValueImmediate);
+    tmpl.nodes.emplace_back(Node::Op::Push, json::parse(json_text), Node::Flag::ValueImmediate, tok.text.data() - tmpl.content.c_str());
     get_next_token();
     return true;
   }
@@ -2708,7 +2708,7 @@
       if_stack.emplace_back(static_cast<decltype(if_stack)::value_type::jump_t>(tmpl.nodes.size()));
 
       // conditional jump; destination will be filled in by else or endif
-      tmpl.nodes.emplace_back(Node::Op::ConditionalJump);
+      tmpl.nodes.emplace_back(Node::Op::ConditionalJump, 0, tok.text.data() - tmpl.content.c_str());
     } else if (tok.text == static_cast<decltype(tok.text)>("endif")) {
       if (if_stack.empty()) {
         throw_parser_error("endif without matching if");
@@ -2738,7 +2738,7 @@
       // end previous block with unconditional jump to endif; destination will be
       // filled in by endif
       if_data.uncond_jumps.push_back(tmpl.nodes.size());
-      tmpl.nodes.emplace_back(Node::Op::Jump);
+      tmpl.nodes.emplace_back(Node::Op::Jump, 0, tok.text.data() - tmpl.content.c_str());
 
       // previous conditional jump jumps here
       tmpl.nodes[if_data.prev_cond_jump].args = tmpl.nodes.size();
@@ -2757,7 +2757,7 @@
         if_data.prev_cond_jump = tmpl.nodes.size();
 
         // conditional jump; destination will be filled in by else or endif
-        tmpl.nodes.emplace_back(Node::Op::ConditionalJump);
+        tmpl.nodes.emplace_back(Node::Op::ConditionalJump, 0, tok.text.data() - tmpl.content.c_str());
       }
     } else if (tok.text == static_cast<decltype(tok.text)>("for")) {
       get_next_token();
@@ -2791,12 +2791,11 @@
 
       loop_stack.push_back(tmpl.nodes.size());
 
-      tmpl.nodes.emplace_back(Node::Op::StartLoop);
+      tmpl.nodes.emplace_back(Node::Op::StartLoop, 0, tok.text.data() - tmpl.content.c_str());
       if (!key_token.text.empty()) {
         tmpl.nodes.back().value = key_token.text;
       }
       tmpl.nodes.back().str = static_cast<std::string>(value_token.text);
-      tmpl.nodes.back().view = value_token.text;
     } else if (tok.text == static_cast<decltype(tok.text)>("endfor")) {
       get_next_token();
       if (loop_stack.empty()) {
@@ -2806,7 +2805,7 @@
       // update loop with EndLoop index (for empty case)
       tmpl.nodes[loop_stack.back()].args = tmpl.nodes.size();
 
-      tmpl.nodes.emplace_back(Node::Op::EndLoop);
+      tmpl.nodes.emplace_back(Node::Op::EndLoop, 0, tok.text.data() - tmpl.content.c_str());
       tmpl.nodes.back().args = loop_stack.back() + 1; // loop body
       loop_stack.pop_back();
     } else if (tok.text == static_cast<decltype(tok.text)>("include")) {
@@ -2832,7 +2831,7 @@
       }
 
       // generate a reference node
-      tmpl.nodes.emplace_back(Node::Op::Include, json(pathname), Node::Flag::ValueImmediate);
+      tmpl.nodes.emplace_back(Node::Op::Include, json(pathname), Node::Flag::ValueImmediate, tok.text.data() - tmpl.content.c_str());
 
       get_next_token();
     } else {
@@ -2853,7 +2852,7 @@
     }
 
     // otherwise just add it to the end
-    tmpl.nodes.emplace_back(op, num_args);
+    tmpl.nodes.emplace_back(op, num_args, tok.text.data() - tmpl.content.c_str());
   }
 
   void append_callback(Template &tmpl, nonstd::string_view name, unsigned int num_args) {
@@ -2864,15 +2863,14 @@
         last.op = Node::Op::Callback;
         last.args = num_args;
         last.str = static_cast<std::string>(name);
-        last.view = name;
+        last.pos = name.data() - tmpl.content.c_str();
         return;
       }
     }
 
     // otherwise just add it to the end
-    tmpl.nodes.emplace_back(Node::Op::Callback, num_args);
+    tmpl.nodes.emplace_back(Node::Op::Callback, num_args, tok.text.data() - tmpl.content.c_str());
     tmpl.nodes.back().str = static_cast<std::string>(name);
-    tmpl.nodes.back().view = name;
   }
 
   void parse_into(Template &tmpl, nonstd::string_view path) {
@@ -2890,7 +2888,7 @@
         }
         return;
       case Token::Kind::Text:
-        tmpl.nodes.emplace_back(Node::Op::PrintText, tok.text, 0u);
+        tmpl.nodes.emplace_back(Node::Op::PrintText, tok.text, 0u, tok.text.data() - tmpl.content.c_str());
         break;
       case Token::Kind::StatementOpen:
         get_next_token();
@@ -3107,8 +3105,7 @@
   }
 
   void throw_renderer_error(const std::string &message, const Node& node) {
-    size_t pos = node.view.data() - current_template->content.c_str();
-    SourceLocation loc = get_source_location(current_template->content, pos);
+    SourceLocation loc = get_source_location(current_template->content, node.pos);
     throw RenderError(message, loc);
   }
 
diff --git a/test/unit-files.cpp b/test/unit-files.cpp
index e8fa1b0..a619933 100644
--- a/test/unit-files.cpp
+++ b/test/unit-files.cpp
@@ -79,6 +79,6 @@
   env.set_search_included_templates_in_files(false);
 
   SUBCASE("html") {
-    CHECK_THROWS_WITH(env.render_file_with_json_file("html/template.txt", "html/data.json"), "[inja.exception.render_error] (at 21:1) include '../test/data/html/header.txt' not found");
+    CHECK_THROWS_WITH(env.render_file_with_json_file("html/template.txt", "html/data.json"), "[inja.exception.render_error] (at 3:14) include '../test/data/html/header.txt' not found");
   }
 }