This commit is contained in:
Josh Thomas 2025-01-06 09:32:54 -06:00
parent c559baea1f
commit 725a603483
2 changed files with 24 additions and 7 deletions

View file

@ -47,14 +47,19 @@ impl LineOffsets {
pub fn position_to_line_col(&self, position: usize) -> (usize, usize) { pub fn position_to_line_col(&self, position: usize) -> (usize, usize) {
let position = position as u32; let position = position as u32;
let line = match self.0.binary_search(&position) { let line = match self.0.binary_search(&position) {
Ok(_) => self.0.partition_point(|&x| x <= position), Ok(exact_line) => exact_line, // Position is at start of this line
Err(i) => i, Err(0) => 0, // Before first line start
Err(next_line) => next_line - 1, // We're on the previous line
}; };
// Calculate column as offset from line start
let col = if line == 0 { let col = if line == 0 {
position as usize position as usize
} else { } else {
(position - self.0[line - 1]) as usize (position - self.0[line]) as usize
}; };
// Convert to 1-based line number
(line + 1, col) (line + 1, col)
} }
@ -348,7 +353,7 @@ mod tests {
eprintln!("Line offsets: {:?}", ast.line_offsets()); eprintln!("Line offsets: {:?}", ast.line_offsets());
eprintln!("Span: {:?}", span); eprintln!("Span: {:?}", span);
let (line, col) = ast.line_offsets().position_to_line_col(span.start as usize); let (line, col) = ast.line_offsets().position_to_line_col(span.start as usize);
assert_eq!((line, col), (1, 0), "Content should be on line 1, col 0"); assert_eq!((line, col), (2, 0), "Content should be on line 2, col 0");
// Check closing tag // Check closing tag
if let Block::Closing { tag } = if let Block::Closing { tag } =

View file

@ -23,10 +23,13 @@ impl Parser {
let mut line_offsets = LineOffsets::new(); let mut line_offsets = LineOffsets::new();
// First pass: collect line offsets // First pass: collect line offsets
let mut current_line_start = 0;
for token in self.tokens.tokens() { for token in self.tokens.tokens() {
if let TokenType::Newline = token.token_type() { if let TokenType::Newline = token.token_type() {
if let Some(start) = token.start() { if let Some(start) = token.start() {
line_offsets.add_line(start + 1); // Add offset for next line
current_line_start = start + 1;
line_offsets.add_line(current_line_start);
} }
} }
} }
@ -157,9 +160,11 @@ impl Parser {
if !found_closing { if !found_closing {
// Push the last branch if we didn't find a closing tag // Push the last branch if we didn't find a closing tag
nodes.push(Node::Block(Block::Branch { nodes.push(Node::Block(Block::Branch {
tag: branch_tag, tag: branch_tag.clone(),
nodes: branch_nodes, nodes: branch_nodes.clone(),
})); }));
// Add error for unclosed tag
self.errors.push(ParserError::Ast(AstError::UnclosedTag(tag_name.clone())));
} }
if found_closing { if found_closing {
break; break;
@ -192,6 +197,13 @@ impl Parser {
} }
}; };
// Add error if we didn't find a closing tag for a block
if let Block::Block { closing: None, tag: tag_ref, .. } = &block {
if let Some(expected_closing) = &spec.closing {
self.errors.push(ParserError::Ast(AstError::UnclosedTag(tag_ref.name.clone())));
}
}
Ok(Node::Block(block)) Ok(Node::Block(block))
} }