diff --git a/src/document/variable.rs b/src/document/variable.rs
index 1158fd1..4a08766 100644
--- a/src/document/variable.rs
+++ b/src/document/variable.rs
@@ -12,8 +12,6 @@ pub trait Variable {
 	fn location(&self) -> &Token;
 
 	fn name(&self) -> &str;
-	/// Parse variable from string, returns an error message on failure
-	fn from_string(&mut self, str: &str) -> Option<String>;
 
 	/// Converts variable to a string
 	fn to_string(&self) -> String;
@@ -49,11 +47,6 @@ impl Variable for BaseVariable {
 
 	fn name(&self) -> &str { self.name.as_str() }
 
-	fn from_string(&mut self, str: &str) -> Option<String> {
-		self.value = str.to_string();
-		None
-	}
-
 	fn to_string(&self) -> String { self.value.clone() }
 
 	fn parse<'a>(&self, state: &ParserState, _location: Token, document: &'a dyn Document<'a>) {
@@ -91,11 +84,6 @@ impl Variable for PathVariable {
 
 	fn name(&self) -> &str { self.name.as_str() }
 
-	fn from_string(&mut self, str: &str) -> Option<String> {
-		self.path = std::fs::canonicalize(str).unwrap();
-		None
-	}
-
 	fn to_string(&self) -> String { self.path.to_str().unwrap().to_string() }
 
 	fn parse(&self, state: &ParserState, location: Token, document: &dyn Document) {
diff --git a/src/elements/import.rs b/src/elements/import.rs
index 3143379..e469f2a 100644
--- a/src/elements/import.rs
+++ b/src/elements/import.rs
@@ -14,7 +14,6 @@ use ariadne::Report;
 use ariadne::ReportKind;
 use regex::Captures;
 use regex::Regex;
-use std::cell::RefMut;
 use std::ops::Range;
 use std::rc::Rc;
 
diff --git a/src/elements/layout.rs b/src/elements/layout.rs
index 1db16be..5907755 100644
--- a/src/elements/layout.rs
+++ b/src/elements/layout.rs
@@ -3,6 +3,7 @@ use crate::compiler::compiler::Target;
 use crate::document::document::Document;
 use crate::document::element::ElemKind;
 use crate::document::element::Element;
+use crate::lsp::semantic::Semantics;
 use crate::lua::kernel::CTX;
 use crate::parser::layout::LayoutHolder;
 use crate::parser::layout::LayoutType;
@@ -516,6 +517,25 @@ impl RegexRule for LayoutRule {
 							|| panic!("Invalid state at: `{STATE_NAME}`"),
 							|s| s.stack.push((vec![token.clone()], layout_type.clone())),
 						);
+
+					if let Some((sems, tokens)) =
+						Semantics::from_source(token.source(), &state.shared.semantics)
+					{
+						let start = matches.get(0).map(|m| {
+							m.start() + token.source().content()[m.start()..].find('#').unwrap()
+						}).unwrap();
+						sems.add(start..start + 2, tokens.layout_sep);
+						sems.add(
+							start + 2..start + 2 + "LAYOUT_BEGIN".len(),
+							tokens.layout_token,
+						);
+						if let Some(props) = matches.get(1).map(|m| m.range()) {
+							sems.add(props.start - 1..props.start, tokens.layout_props_sep);
+							sems.add(props.clone(), tokens.layout_props);
+							sems.add(props.end..props.end + 1, tokens.layout_props_sep);
+						}
+						sems.add(matches.get(2).unwrap().range(), tokens.layout_type);
+					}
 				}
 			};
 			return reports;
@@ -578,6 +598,24 @@ impl RegexRule for LayoutRule {
 				}
 			};
 
+			if let Some((sems, tokens)) =
+				Semantics::from_source(token.source(), &state.shared.semantics)
+			{
+				let start = matches.get(0).map(|m| {
+					m.start() + token.source().content()[m.start()..].find('#').unwrap()
+				}).unwrap();
+				sems.add(start..start + 2, tokens.layout_sep);
+				sems.add(
+					start + 2..start + 2 + "LAYOUT_NEXT".len(),
+					tokens.layout_token,
+				);
+				if let Some(props) = matches.get(1).map(|m| m.range()) {
+					sems.add(props.start - 1..props.start, tokens.layout_props_sep);
+					sems.add(props.clone(), tokens.layout_props);
+					sems.add(props.end..props.end + 1, tokens.layout_props_sep);
+				}
+			}
+
 			tokens.push(token.clone());
 			(
 				tokens.len() - 1,
@@ -585,6 +623,7 @@ impl RegexRule for LayoutRule {
 				layout_type.clone(),
 				properties,
 			)
+
 		} else {
 			// LAYOUT_END
 			let mut rule_state_borrow = rule_state.as_ref().borrow_mut();
@@ -644,6 +683,25 @@ impl RegexRule for LayoutRule {
 			let layout_type = layout_type.clone();
 			let id = tokens.len();
 			layout_state.stack.pop();
+
+			if let Some((sems, tokens)) =
+				Semantics::from_source(token.source(), &state.shared.semantics)
+			{
+				let start = matches.get(0).map(|m| {
+					m.start() + token.source().content()[m.start()..].find('#').unwrap()
+				}).unwrap();
+				sems.add(start..start + 2, tokens.layout_sep);
+				sems.add(
+					start + 2..start + 2 + "LAYOUT_END".len(),
+					tokens.layout_token,
+				);
+				if let Some(props) = matches.get(1).map(|m| m.range()) {
+					sems.add(props.start - 1..props.start, tokens.layout_props_sep);
+					sems.add(props.clone(), tokens.layout_props);
+					sems.add(props.end..props.end + 1, tokens.layout_props_sep);
+				}
+			}
+
 			(id, LayoutToken::End, layout_type, properties)
 		};
 
@@ -879,7 +937,7 @@ mod tests {
 	use crate::parser::langparser::LangParser;
 	use crate::parser::parser::Parser;
 	use crate::parser::source::SourceFile;
-	use crate::validate_document;
+	use crate::{validate_document, validate_semantics};
 
 	use super::*;
 
@@ -996,4 +1054,37 @@ mod tests {
 			Layout { token == LayoutToken::End, id == 2 };
 		);
 	}
+
+	#[test]
+	fn semantic() {
+		let source = Rc::new(SourceFile::with_content(
+			"".to_string(),
+			r#"
+#+LAYOUT_BEGIN Split
+	#+LAYOUT_NEXT[style=aa]
+#+LAYOUT_END
+		"#
+			.to_string(),
+			None,
+		));
+		let parser = LangParser::default();
+		let (_, state) = parser.parse(
+			ParserState::new_with_semantics(&parser, None),
+			source.clone(),
+			None,
+			ParseMode::default(),
+		);
+		validate_semantics!(state, source.clone(), 0,
+			layout_sep { delta_line == 1, delta_start == 0, length == 2 };
+			layout_token { delta_line == 0, delta_start == 2, length == 12 };
+			layout_type { delta_line == 0, delta_start == 12, length == 6 };
+			layout_sep { delta_line == 1, delta_start == 1, length == 2 };
+			layout_token { delta_line == 0, delta_start == 2, length == 11 };
+			layout_props_sep { delta_line == 0, delta_start == 11, length == 1 };
+			layout_props { delta_line == 0, delta_start == 1, length == 8 };
+			layout_props_sep { delta_line == 0, delta_start == 8, length == 1 };
+			layout_sep { delta_line == 1, delta_start == 0, length == 2 };
+			layout_token { delta_line == 0, delta_start == 2, length == 10 };
+		);
+	}
 }
diff --git a/src/elements/link.rs b/src/elements/link.rs
index 7a69834..0214da6 100644
--- a/src/elements/link.rs
+++ b/src/elements/link.rs
@@ -127,8 +127,8 @@ impl RegexRule for LinkRule {
 					);
 					return reports;
 				}
-				let processed = util::process_escaped('\\', "]", display.as_str());
-				if processed.is_empty() {
+				let display_source = util::escape_source(token.source(), display.range(), "Link Display".into(), '\\', "](");
+				if display_source.content().is_empty() {
 					reports.push(
 						Report::build(ReportKind::Error, token.source(), display.start())
 							.with_message("Empty link name")
@@ -137,7 +137,7 @@ impl RegexRule for LinkRule {
 									.with_message(format!(
 										"Link name is empty. Once processed, `{}` yields `{}`",
 										display.as_str().fg(state.parser.colors().highlight),
-										processed.fg(state.parser.colors().highlight),
+										display_source.fg(state.parser.colors().highlight),
 									))
 									.with_color(state.parser.colors().error),
 							)
@@ -154,12 +154,7 @@ impl RegexRule for LinkRule {
 						tokens.link_display_sep,
 					);
 				}
-				let source = Rc::new(VirtualSource::new(
-					Token::new(display.range(), token.source()),
-					"Link Display".to_string(),
-					processed,
-				));
-				match util::parse_paragraph(state, source, document) {
+				match util::parse_paragraph(state, display_source, document) {
 					Err(err) => {
 						reports.push(
 							Report::build(ReportKind::Error, token.source(), display.start())
@@ -376,6 +371,22 @@ nml.link.push("**BOLD link**", "another url")
 
 	#[test]
 	fn semantics() {
+		let source = Rc::new(SourceFile::with_content(
+			"".to_string(),
+			r#" - [la(*testi*nk](url)
+		"#
+			.to_string(),
+			None,
+		));
+		let parser = LangParser::default();
+		let (_, state) = parser.parse(
+			ParserState::new_with_semantics(&parser, None),
+			source.clone(),
+			None,
+			ParseMode::default(),
+		);
+		println!("{:#?}", state.shared.semantics);
+		return;
 		let source = Rc::new(SourceFile::with_content(
 			"".to_string(),
 			r#"
diff --git a/src/elements/list.rs b/src/elements/list.rs
index 6aafbab..42eb166 100644
--- a/src/elements/list.rs
+++ b/src/elements/list.rs
@@ -359,7 +359,6 @@ impl Rule for ListRule {
 				// Content
 				let entry_start = captures.get(3).unwrap().start();
 				let mut entry_content = captures.get(3).unwrap().as_str().to_string();
-				let mut spacing: Option<(Range<usize>, &str)> = None;
 				while let Some(captures) = self.continue_re.captures_at(content, end_cursor.pos) {
 					// Break if next element is another entry
 					if captures.get(0).unwrap().start() != end_cursor.pos
@@ -379,44 +378,12 @@ impl Rule for ListRule {
 					// Advance cursor
 					end_cursor = end_cursor.at(captures.get(0).unwrap().end());
 
-					// Spacing
-					let current_spacing = captures.get(1).unwrap().as_str();
-					if let Some(spacing) = &spacing {
-						if spacing.1 != current_spacing {
-							reports.push(
-								Report::build(
-									ReportKind::Warning,
-									cursor.source.clone(),
-									captures.get(1).unwrap().start(),
-								)
-								.with_message("Invalid list entry spacing")
-								.with_label(
-									Label::new((
-										cursor.source.clone(),
-										captures.get(1).unwrap().range(),
-									))
-									.with_message("Spacing for list entries do not match")
-									.with_color(state.parser.colors().warning),
-								)
-								.with_label(
-									Label::new((cursor.source.clone(), spacing.0.clone()))
-										.with_message("Previous spacing")
-										.with_color(state.parser.colors().warning),
-								)
-								.finish(),
-							);
-						}
-					} else {
-						spacing = Some((captures.get(1).unwrap().range(), current_spacing));
-					}
-
 					entry_content += "\n";
 					entry_content += captures.get(1).unwrap().as_str();
 				}
 
 				// Parse entry content
 				let token = Token::new(entry_start..end_cursor.pos, end_cursor.source.clone());
-				//println!("content={}", entry_content);
 				let entry_src = Rc::new(VirtualSource::new(
 					token.clone(),
 					"List Entry".to_string(),
@@ -561,8 +528,6 @@ mod tests {
  *[offset=5] First **bold**
 	Second line
  *- Another
-
-
 		"#
 			.to_string(),
 			None,
diff --git a/src/elements/paragraph.rs b/src/elements/paragraph.rs
index c6b5aa2..de34324 100644
--- a/src/elements/paragraph.rs
+++ b/src/elements/paragraph.rs
@@ -32,8 +32,6 @@ pub struct Paragraph {
 }
 
 impl Paragraph {
-	pub fn is_empty(&self) -> bool { self.content.is_empty() }
-
 	pub fn find_back<P: FnMut(&&Box<dyn Element + 'static>) -> bool>(
 		&self,
 		predicate: P,
diff --git a/src/elements/raw.rs b/src/elements/raw.rs
index e1d3474..f35efcf 100644
--- a/src/elements/raw.rs
+++ b/src/elements/raw.rs
@@ -2,6 +2,7 @@ use crate::compiler::compiler::Compiler;
 use crate::document::document::Document;
 use crate::document::element::ElemKind;
 use crate::document::element::Element;
+use crate::lsp::semantic::Semantics;
 use crate::lua::kernel::CTX;
 use crate::parser::parser::ParseMode;
 use crate::parser::parser::ParserState;
@@ -227,6 +228,21 @@ impl RegexRule for RawRule {
 			}),
 		);
 
+		if let Some((sems, tokens)) =
+			Semantics::from_source(token.source(), &state.shared.semantics)
+		{
+			let range = matches.get(0).unwrap().range();
+			sems.add(range.start..range.start+2, tokens.raw_sep);
+			if let Some(props) = matches.get(1).map(|m| m.range())
+			{
+				sems.add(props.start - 1..props.start, tokens.raw_props_sep);
+				sems.add(props.clone(), tokens.raw_props);
+				sems.add(props.end..props.end + 1, tokens.raw_props_sep);
+			}
+			sems.add(matches.get(2).unwrap().range(), tokens.raw_content);
+			sems.add(range.end-2..range.end, tokens.raw_sep);
+		}
+
 		reports
 	}
 
@@ -281,7 +297,7 @@ mod tests {
 	use crate::parser::langparser::LangParser;
 	use crate::parser::parser::Parser;
 	use crate::parser::source::SourceFile;
-	use crate::validate_document;
+	use crate::{validate_document, validate_semantics};
 
 	#[test]
 	fn parser() {
@@ -338,4 +354,35 @@ Break%<nml.raw.push("block", "Raw")>%NewParagraph%<nml.raw.push("inline", "<b>")
 		};
 		);
 	}
+
+	#[test]
+	fn semantic() {
+		let source = Rc::new(SourceFile::with_content(
+			"".to_string(),
+			r#"
+{?[kind=block] Raw?}
+{?<b>?}
+		"#
+			.to_string(),
+			None,
+		));
+		let parser = LangParser::default();
+		let (_, state) = parser.parse(
+			ParserState::new_with_semantics(&parser, None),
+			source.clone(),
+			None,
+			ParseMode::default(),
+		);
+		validate_semantics!(state, source.clone(), 0,
+			raw_sep { delta_line == 1, delta_start == 0, length == 2 };
+			raw_props_sep { delta_line == 0, delta_start == 2, length == 1 };
+			raw_props { delta_line == 0, delta_start == 1, length == 10 };
+			raw_props_sep { delta_line == 0, delta_start == 10, length == 1 };
+			raw_content { delta_line == 0, delta_start == 1, length == 4 };
+			raw_sep { delta_line == 0, delta_start == 4, length == 2 };
+			raw_sep { delta_line == 1, delta_start == 0, length == 2 };
+			raw_content { delta_line == 0, delta_start == 2, length == 3 };
+			raw_sep { delta_line == 0, delta_start == 3, length == 2 };
+		);
+	}
 }
diff --git a/src/elements/reference.rs b/src/elements/reference.rs
index ef7e455..caff5ee 100644
--- a/src/elements/reference.rs
+++ b/src/elements/reference.rs
@@ -1,4 +1,3 @@
-use std::cell::RefMut;
 use std::collections::HashMap;
 use std::ops::Range;
 use std::rc::Rc;
diff --git a/src/elements/style.rs b/src/elements/style.rs
index 6bf7ebd..9ed3a71 100644
--- a/src/elements/style.rs
+++ b/src/elements/style.rs
@@ -9,6 +9,7 @@ use crate::lua::kernel::CTX;
 use crate::parser::parser::ParseMode;
 use crate::parser::parser::ParserState;
 use crate::parser::rule::RegexRule;
+use crate::parser::source::original_range;
 use crate::parser::source::Source;
 use crate::parser::source::Token;
 use crate::parser::state::RuleState;
diff --git a/src/elements/tex.rs b/src/elements/tex.rs
index 2619440..a00e249 100644
--- a/src/elements/tex.rs
+++ b/src/elements/tex.rs
@@ -28,6 +28,7 @@ use crate::compiler::compiler::Target;
 use crate::document::document::Document;
 use crate::document::element::ElemKind;
 use crate::document::element::Element;
+use crate::lsp::semantic::Semantics;
 use crate::lua::kernel::CTX;
 use crate::parser::parser::ParseMode;
 use crate::parser::parser::ParserState;
@@ -429,7 +430,7 @@ impl RegexRule for TexRule {
 			document,
 			Box::new(Tex {
 				mathmode: index == 1,
-				location: token,
+				location: token.clone(),
 				kind: tex_kind,
 				env: tex_env.to_string(),
 				tex: tex_content,
@@ -437,6 +438,19 @@ impl RegexRule for TexRule {
 			}),
 		);
 
+		if let Some((sems, tokens)) =
+			Semantics::from_source(token.source(), &state.shared.semantics)
+		{
+			let range = token.range;
+			sems.add(range.start..range.start + if index == 0 { 2 } else { 1 }, tokens.tex_sep);
+			if let Some(props) = matches.get(1).map(|m| m.range()) {
+				sems.add(props.start - 1..props.start, tokens.tex_props_sep);
+				sems.add(props.clone(), tokens.tex_props);
+				sems.add(props.end..props.end + 1, tokens.tex_props_sep);
+			}
+			sems.add(matches.get(2).unwrap().range(), tokens.tex_content);
+			sems.add(range.end - if index == 0 { 2 } else { 1 }..range.end, tokens.tex_sep);
+		}
 		reports
 	}
 
@@ -536,7 +550,7 @@ mod tests {
 	use crate::parser::langparser::LangParser;
 	use crate::parser::parser::Parser;
 	use crate::parser::source::SourceFile;
-	use crate::validate_document;
+	use crate::{validate_document, validate_semantics};
 
 	use super::*;
 
@@ -607,4 +621,32 @@ $[env=another] e^{i\pi}=-1$
 			};
 		);
 	}
+
+	#[test]
+	fn semantic() {
+		let source = Rc::new(SourceFile::with_content(
+			"".to_string(),
+			r#"
+$[kind=inline]\LaTeX$
+		"#
+			.to_string(),
+			None,
+		));
+		let parser = LangParser::default();
+		let (_, state) = parser.parse(
+			ParserState::new_with_semantics(&parser, None),
+			source.clone(),
+			None,
+			ParseMode::default(),
+		);
+		validate_semantics!(state, source.clone(), 0,
+			tex_sep { delta_line == 1, delta_start == 0, length == 1 };
+			tex_props_sep { delta_line == 0, delta_start == 1, length == 1 };
+			tex_props { delta_line == 0, delta_start == 1, length == 11 };
+			tex_props_sep { delta_line == 0, delta_start == 11, length == 1 };
+			tex_content { delta_line == 0, delta_start == 1, length == 6 };
+			tex_sep { delta_line == 0, delta_start == 6, length == 1 };
+		);
+	}
+
 }
diff --git a/src/lsp/semantic.rs b/src/lsp/semantic.rs
index 5244a49..5e6ee59 100644
--- a/src/lsp/semantic.rs
+++ b/src/lsp/semantic.rs
@@ -8,6 +8,7 @@ use tower_lsp::lsp_types::SemanticToken;
 use tower_lsp::lsp_types::SemanticTokenModifier;
 use tower_lsp::lsp_types::SemanticTokenType;
 
+use crate::parser::source::original_range;
 use crate::parser::source::LineCursor;
 use crate::parser::source::Source;
 use crate::parser::source::SourceFile;
@@ -139,6 +140,22 @@ pub struct Tokens {
 	pub list_bullet: (u32, u32),
 	pub list_props_sep: (u32, u32),
 	pub list_props: (u32, u32),
+
+	pub raw_sep: (u32, u32),
+	pub raw_props_sep: (u32, u32),
+	pub raw_props: (u32, u32),
+	pub raw_content: (u32, u32),
+
+	pub tex_sep: (u32, u32),
+	pub tex_props_sep: (u32, u32),
+	pub tex_props: (u32, u32),
+	pub tex_content: (u32, u32),
+
+	pub layout_sep: (u32, u32),
+	pub layout_token: (u32, u32),
+	pub layout_props_sep: (u32, u32),
+	pub layout_props: (u32, u32),
+	pub layout_type: (u32, u32),
 }
 
 impl Tokens {
@@ -160,7 +177,7 @@ impl Tokens {
 			import_import: token!("macro"),
 			import_as_sep: token!("operator"),
 			import_as: token!("operator"),
-			import_path: token!("function"),
+			import_path: token!("parameter"),
 
 			reference_operator: token!("operator"),
 			reference_link_sep: token!("operator"),
@@ -174,7 +191,7 @@ impl Tokens {
 			variable_kind: token!("operator"),
 			variable_name: token!("macro"),
 			variable_sep: token!("operator"),
-			variable_value: token!("function"),
+			variable_value: token!("parameter"),
 
 			variable_sub_sep: token!("operator"),
 			variable_sub_name: token!("macro"),
@@ -195,6 +212,22 @@ impl Tokens {
 			list_bullet: token!("macro"),
 			list_props_sep: token!("operator"),
 			list_props: token!("enum"),
+
+			raw_sep: token!("operator"),
+			raw_props_sep: token!("operator"),
+			raw_props: token!("enum"),
+			raw_content: token!("string"),
+
+			tex_sep: token!("modifier"),
+			tex_props_sep: token!("operator"),
+			tex_props: token!("enum"),
+			tex_content: token!("string"),
+
+			layout_sep: token!("number"),
+			layout_token: token!("number"),
+			layout_props_sep: token!("operator"),
+			layout_props: token!("enum"),
+			layout_type: token!("function"),
 		}
 	}
 }
@@ -221,15 +254,17 @@ impl SemanticsData {
 #[derive(Debug)]
 pub struct Semantics<'a> {
 	pub(self) sems: Ref<'a, SemanticsData>,
+	// TODO
+	pub(self) original_source: Rc<dyn Source>,
+	/// The resolved parent source
 	pub(self) source: Rc<dyn Source>,
-	pub(self) range: Range<usize>,
 }
 
 impl<'a> Semantics<'a> {
 	fn from_source_impl(
 		source: Rc<dyn Source>,
 		semantics: &'a Option<RefCell<SemanticsHolder>>,
-		range: Range<usize>,
+		original_source: Rc<dyn Source>,
 	) -> Option<(Self, Ref<'a, Tokens>)> {
 		if source.name().starts_with(":LUA:") && source.downcast_ref::<VirtualSource>().is_some() {
 			return None;
@@ -243,7 +278,8 @@ impl<'a> Semantics<'a> {
 			.map(|parent| parent.location())
 			.unwrap_or(None)
 		{
-			return Self::from_source_impl(location.source(), semantics, range);
+			//let range = location.range.start+range.start..location.range.start+range.end;
+			return Self::from_source_impl(location.source(), semantics, original_source);
 		} else if let Some(source) = source.clone().downcast_rc::<SourceFile>().ok() {
 			return Ref::filter_map(
 				semantics.as_ref().unwrap().borrow(),
@@ -257,7 +293,7 @@ impl<'a> Semantics<'a> {
 					Self {
 						sems,
 						source,
-						range,
+						original_source,
 					},
 					Ref::map(
 						semantics.as_ref().unwrap().borrow(),
@@ -276,18 +312,15 @@ impl<'a> Semantics<'a> {
 		if semantics.is_none() {
 			return None;
 		}
-		let range = source.location().map_or_else(
-			|| 0..source.content().len(),
-			|location| location.range.clone(),
-		);
-		return Self::from_source_impl(source, semantics, range);
+		return Self::from_source_impl(source.clone(), semantics, source);
 	}
 
 	pub fn add(&self, range: Range<usize>, token: (u32, u32)) {
-		let range = self.range.start + range.start..self.range.start + range.end;
+		let range = original_range(self.original_source.clone(), range).1;
 		let mut tokens = self.sems.tokens.borrow_mut();
 		let mut cursor = self.sems.cursor.borrow_mut();
 		let mut current = cursor.clone();
+		println!("range={range:#?}");
 		cursor.move_to(range.start);
 
 		while cursor.pos != range.end {
diff --git a/src/parser/parser.rs b/src/parser/parser.rs
index d95f13a..7cb3cf3 100644
--- a/src/parser/parser.rs
+++ b/src/parser/parser.rs
@@ -2,7 +2,6 @@ use ariadne::Label;
 use ariadne::Report;
 use std::any::Any;
 use std::cell::RefCell;
-use std::collections::HashMap;
 use std::collections::HashSet;
 use std::ops::Range;
 use std::rc::Rc;
diff --git a/src/parser/source.rs b/src/parser/source.rs
index 262c5f8..4afaaaa 100644
--- a/src/parser/source.rs
+++ b/src/parser/source.rs
@@ -70,11 +70,48 @@ impl Source for SourceFile {
 	fn content(&self) -> &String { &self.content }
 }
 
+/// Stores the offsets in a virtual source
+///
+/// # Example
+///
+/// Let's say you make a virtual source from the following: "Con\]tent" -> "Con]tent"
+/// Then at position 3, an offset of 1 will be created to account for the removed '\'
+#[derive(Debug)]
+struct SourceOffset
+{
+	/// Stores the total offsets
+	offsets: Vec<(usize, isize)>,
+}
+
+impl SourceOffset
+{
+	/// Get the offset position
+	pub fn position(&self, pos: usize) -> usize
+	{
+		match self.offsets.binary_search_by_key(&pos, |&(orig, _)| orig)
+		{
+			Ok(idx) => (pos as isize + self.offsets[idx].1) as usize,
+			Err(idx) => {
+				if idx == 0
+				{
+					pos
+				}
+				else
+				{
+					(pos as isize + self.offsets[idx - 1].1) as usize
+				}
+			},
+		}
+	}
+}
+
 #[derive(Debug)]
 pub struct VirtualSource {
 	location: Token,
 	name: String,
 	content: String,
+	/// Offset relative to the [`location`]'s source
+	offsets: Option<SourceOffset>,
 }
 
 impl VirtualSource {
@@ -83,6 +120,16 @@ impl VirtualSource {
 			location,
 			name,
 			content,
+			offsets: None,
+		}
+	}
+
+	pub fn new_offsets(location: Token, name: String, content: String, offsets: Vec<(usize, isize)>) -> Self {
+		Self {
+			location,
+			name,
+			content,
+			offsets: Some(SourceOffset { offsets }),
 		}
 	}
 }
@@ -93,6 +140,49 @@ impl Source for VirtualSource {
 	fn content(&self) -> &String { &self.content }
 }
 
+/// Transforms a position to it's position in the oldest parent source
+pub fn original_position(source: Rc<dyn Source>, mut pos: usize) -> (Rc<dyn Source>, usize)
+{
+	// Apply offsets
+	if let Some(offsets) =
+		source.downcast_ref::<VirtualSource>()
+		.and_then(|source| source.offsets.as_ref())
+	{
+		pos = offsets.position(pos);
+	}
+
+	// Recurse to parent
+	if let Some(parent) = source.location()
+	{
+		return original_position(parent.source.clone(), parent.range.start + pos);
+	}
+
+	return (source, pos);
+}
+
+/// Transforms a range to the oldest parent source
+///
+/// This function takes a range from a source and attempts to get the range's position in the oldest parent
+pub fn original_range(source: Rc<dyn Source>, mut range: Range<usize>) -> (Rc<dyn Source>, Range<usize>)
+{
+	// Apply offsets
+	if let Some(offsets) =
+		source.downcast_ref::<VirtualSource>()
+		.and_then(|source| source.offsets.as_ref())
+	{
+		range = offsets.position(range.start) .. offsets.position(range.end);
+	}
+
+	// Recurse to parent
+	if let Some(parent) = source.location()
+	{
+		//println!("FOUND PARENT={}", parent.source().name());
+		return original_range(parent.source.clone(), parent.range.start + range.start..parent.range.start + range.end);
+	}
+
+	return (source, range);
+}
+
 #[derive(Debug)]
 pub struct Cursor {
 	pub pos: usize,
@@ -151,6 +241,7 @@ impl LineCursor {
 	/// # Error
 	/// This function will panic if [`pos`] is not utf8 aligned
 	pub fn move_to(&mut self, pos: usize) {
+		println!("pos={pos}");
 		if self.pos < pos {
 			let start = self.pos;
 			let mut it = self.source.content().as_str()[start..].chars().peekable();
@@ -173,29 +264,6 @@ impl LineCursor {
 			}
 		} else if self.pos > pos {
 			panic!();
-			let start = self.pos;
-			let mut it = self.source.content().as_str()[..start]
-				.chars()
-				.rev()
-				.peekable();
-
-			let mut prev = self.source.content().as_str()[start..].chars().next();
-			while self.pos > pos {
-				let c = it.next().unwrap();
-				let len = c.len_utf8();
-
-				if self.pos != start && prev == Some('\n') {
-					self.line -= 1;
-					self.line_pos = 0;
-				}
-				self.line_pos -= c.len_utf16();
-				self.pos -= c.len_utf8();
-				prev = Some(c);
-			}
-			if self.pos != start && prev == Some('\n') {
-				self.line -= 1;
-				self.line_pos = 0;
-			}
 		}
 
 		// May fail if pos is not utf8-aligned
diff --git a/src/parser/util.rs b/src/parser/util.rs
index ff612d2..3630dd6 100644
--- a/src/parser/util.rs
+++ b/src/parser/util.rs
@@ -1,4 +1,6 @@
 use std::collections::HashMap;
+use std::iter::Peekable;
+use std::ops::Range;
 use std::rc::Rc;
 
 use unicode_segmentation::UnicodeSegmentation;
@@ -7,10 +9,14 @@ use crate::document::document::Document;
 use crate::document::document::DocumentAccessors;
 use crate::document::element::ElemKind;
 use crate::elements::paragraph::Paragraph;
+use crate::parser::source::original_range;
 
 use super::parser::ParseMode;
 use super::parser::ParserState;
 use super::source::Source;
+use super::source::SourceFile;
+use super::source::Token;
+use super::source::VirtualSource;
 
 /// Processes text for escape characters and paragraphing
 pub fn process_text(document: &dyn Document, content: &str) -> String {
@@ -88,6 +94,73 @@ pub fn process_text(document: &dyn Document, content: &str) -> String {
 	processed
 }
 
+/// Transforms source into a new [`VirtualSource`]. Transforms range from source by
+/// detecting escaped tokens.
+///
+pub fn escape_source(source: Rc<dyn Source>, range: Range<usize>, name: String, escape: char, token: &'static str) -> Rc<dyn Source>
+{
+	let content = &source.content()[range.clone()];
+
+	let mut processed = String::new();
+	let mut escaped = 0;
+	let mut token_it = token.chars().peekable();
+	let mut offset = 0isize;
+	let mut offsets : Vec<(usize, isize)> = vec!();
+	for (pos, c) in content.chars().enumerate()
+	{
+		if c == escape {
+			escaped += 1;
+		} else if escaped % 2 == 1 && token_it.peek().map_or(false, |p| *p == c) {
+			let _ = token_it.next();
+			if token_it.peek().is_none() {
+				(0..(escaped / 2)).for_each(|_| processed.push(escape));
+				if ( escaped + 1) / 2 != 0
+				{
+					offset += (escaped + 1) / 2;
+					offsets.push((pos - token.len() - escaped as usize / 2, offset));
+				}
+				escaped = 0;
+				token_it = token.chars().peekable();
+				processed.push_str(token);
+			}
+		} else {
+			if escaped != 0 {
+				// Add escapes
+				(0..escaped).for_each(|_| processed.push('\\'));
+				token_it = token.chars().peekable();
+				escaped = 0;
+			}
+			processed.push(c);
+		}
+	}
+	// Add trailing escapes
+	(0..escaped).for_each(|_| processed.push('\\'));
+
+	Rc::new(VirtualSource::new_offsets(
+		Token::new(range, source),
+		name,
+		processed,
+		offsets
+	))
+}
+
+pub fn app()
+{
+	let mut s = String::new();
+
+	let source = Rc::new(SourceFile::with_content(
+		"test".to_string(),
+		"a\\\\\\```b".into(),
+		None,
+	));
+	let src = escape_source(source.clone(), 0..source.content().len(), "sub".to_string(), '\\', "```");
+	println!("{}", src.content());
+	let range = 0..src.content().len();
+	println!("{:#?}", range);
+	let orange = original_range(src.clone(), range);
+	println!("{:#?}", orange);
+}
+
 /// Processed a string and escapes a single token out of it
 /// Escaped characters other than the [`token`] will be not be treated as escaped
 ///
@@ -96,6 +169,8 @@ pub fn process_text(document: &dyn Document, content: &str) -> String {
 /// assert_eq!(process_escaped('\\', "%", "escaped: \\%, also escaped: \\\\\\%, untouched: \\a"),
 /// "escaped: %, also escaped: \\%, untouched: \\a");
 /// ```
+/// TODO: Make this function return a delta to pass to the semantics, maybe store it in the virtualsource, so this function should return a source...
+#[deprecated]
 pub fn process_escaped<S: AsRef<str>>(escape: char, token: &'static str, content: S) -> String {
 	let mut processed = String::new();
 	let mut escaped = 0;
diff --git a/src/server.rs b/src/server.rs
index 5eca473..a47e5d7 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -65,7 +65,7 @@ impl Backend {
 
 #[tower_lsp::async_trait]
 impl LanguageServer for Backend {
-	async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
+	async fn initialize(&self, _params: InitializeParams) -> Result<InitializeResult> {
 		Ok(InitializeResult {
 			capabilities: ServerCapabilities {
 				text_document_sync: Some(TextDocumentSyncCapability::Kind(
@@ -139,9 +139,9 @@ impl LanguageServer for Backend {
 		.await
 	}
 
-	async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
-		let uri = params.text_document_position.text_document.uri;
-		let position = params.text_document_position.position;
+	async fn completion(&self, _params: CompletionParams) -> Result<Option<CompletionResponse>> {
+		//let uri = params.text_document_position.text_document.uri;
+		//let position = params.text_document_position.position;
 		let completions = || -> Option<Vec<CompletionItem>> {
 			let mut ret = Vec::with_capacity(0);