@@ -1325,14 +1325,14 @@ impl Parser {
1325 let var_name = var_names[0].clone();
1325 let var_name = var_names[0].clone();
1326 let index_var = var_names.get(1).cloned();
1326 let index_var = var_names.get(1).cloned();
1328− // Strip a trailing `[page N]` pagination suffix so it doesn't end
1328+ if list_str.trim_end().ends_with(']') && list_str.contains("[page ") {
1329− // up in the last item; it's parsed from the raw line below.
1329+ return Err(ParseError {
1330− let list_str = match list_str.rfind("[page ") {
1330+ line: line_num,
1331− Some(pos) if list_str.trim_end().ends_with(']') => {
1331+ message: "@each pagination (`[page N]`) was removed: split the list or \
1332+ filter it with @if"
1332− list_str[..pos].trim_end().to_string()
1333+ .to_string(),
1336 track_var_refs(&list_str, &mut ctx.used_variables);
1336 track_var_refs(&list_str, &mut ctx.used_variables);
1337 let list_str = substitute_vars(&list_str, &ctx.variables);
1337 let list_str = substitute_vars(&list_str, &ctx.variables);
1338 // Support range syntax: @each $i in 1..5 or @each $i in 0..100 step 10
1338 // Support range syntax: @each $i in 1..5 or @each $i in 0..100 step 10
@@ -1360,50 +1360,6 @@ impl Parser {
1360 .collect()
1360 .collect()
1363− // Pagination: check for [page N] or [page N per P] suffix
1364− // Parse from the original rest before substitution
1365− let (items, pagination_info) = {
1366− // Check if list_str ended with a page directive (already consumed in items)
1367− // Instead, check the raw rest for [page ...] syntax
1368− let raw_rest = rest;
1369− let page_size = if let Some(page_pos) = raw_rest.find("[page ") {
1370− let after = &raw_rest[page_pos + 6..];
1371− if let Some(close) = after.find(']') {
1372− let page_spec = after[..close].trim();
1373− page_spec.parse::<usize>().ok()
1381− if let Some(size) = page_size {
1382− let current_page: usize = ctx
1385− .and_then(|v| v.parse().ok())
1388− let size = size.max(1);
1389− let total_items = items.len();
1390− let total_pages = total_items.div_ceil(size);
1391− let start = (current_page - 1).saturating_mul(size);
1392− let end = start.saturating_add(size).min(total_items);
1393− let page_items: Vec<String> = if start < total_items {
1394− items[start..end].to_vec()
1400− Some((current_page, total_pages, size, total_items)),
1407 // Collect body lines
1363 // Collect body lines
1408 let mut body_lines = Vec::new();
1364 let mut body_lines = Vec::new();
1409 while self.pos < self.lines.len() && self.lines[self.pos].indent > current_indent {
1365 while self.pos < self.lines.len() && self.lines[self.pos].indent > current_indent {
@@ -1466,17 +1422,6 @@ impl Parser {
1466 let saved_vars = ctx.variables.clone();
1422 let saved_vars = ctx.variables.clone();
1467 let mut all_nodes = Vec::new();
1423 let mut all_nodes = Vec::new();
1469− // Inject pagination variables if pagination is active
1470− if let Some((page, total_pages, page_size, total_items)) = pagination_info {
1471− ctx.variables.insert("_page".to_string(), page.to_string());
1473− .insert("_total_pages".to_string(), total_pages.to_string());
1475− .insert("_page_size".to_string(), page_size.to_string());
1477− .insert("_total_items".to_string(), total_items.to_string());
1480 let has_extra_vars = var_names.len() > 2
1425 let has_extra_vars = var_names.len() > 2
1481 || (var_names.len() == 2 && items.first().is_some_and(|it| it.contains(' ')));
1426 || (var_names.len() == 2 && items.first().is_some_and(|it| it.contains(' ')));