Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## unrelease

### Added

- `auto-continue` attribute to automatically continue to the next action (#240)

## [v0.11.0] Brazlip (Sunday, the 24th of May, 2026)

### Added
Expand Down
28 changes: 28 additions & 0 deletions docs/actions-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,34 @@ It is possible to have multiple actions in a single attribute. They will be exec
{#three .unrevealed}
Some more content.

Actions are executed in "reading order", from top left to bottom right. The
presenter needs to press the "next" key to trigger the next action.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
.. code-block::

{#one}
Some content.

{center="~duration:2 ~margin:10 one" reveal="two three"}
The action above is executed first.

{#two .unrevealed unreveal="three"}
The action above is executed second.

{#three .unrevealed}
Some more content.

When the ``auto-continue`` attribute is included in the attribute set, the next
action is executed without requiring the user pressing the "next" key.

.. code-block::

{reveal="two" auto-continue}
The action above is executed first.

{#two .unrevealed center}
The action above is executed directly after the first one.

.. contents:: Actions table of content
:local:

Expand Down
4 changes: 3 additions & 1 deletion src/compiler/special_attrs.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ let svg = "svg"
let pdf_resolution = "pdf-resolution"
let pause_block = "pause-block"
let as_html = "as-html"
let auto_continue = "auto-continue"

let all_attrs =
[
Expand All @@ -28,5 +29,6 @@ let all_attrs =
svg;
pdf_resolution;
pause_block;
as_html
as_html;
auto_continue
]
10 changes: 8 additions & 2 deletions src/engine/runtime/step/action_scheduler.ml
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,19 @@ let setup_actions window () =
in
()

let next ~mode window () =
let ( !! ) = Jstr.v

let rec next ~mode window () =
match find_next_pause_or_step () with
| None -> None
| Some pause ->
let res =
let> () = Actions.exit ~mode window pause in
let> () = AttributeActions.do_ ~mode window pause in
Undoable.return ()
match Brr.El.at !!"auto-continue" pause with
| None -> Undoable.return ()
| Some _ ->
let n = next ~mode window () in
Option.value ~default:(Undoable.return ()) n
in
Some res
20 changes: 13 additions & 7 deletions src/engine/runtime/table_of_content/table_of_content.ml
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ let generate window root =
[]
|> List.rev |> List.concat
in
let rec loop undo entries step categorized_els =
let rec loop ~auto_continue undo entries step categorized_els =
match categorized_els with
| `Title t :: res ->
let entries = entry_title t :: entries in
loop undo entries step res
loop ~auto_continue undo entries step res
| `Action a :: res ->
if Step.Action_scheduler.is_action a then
let* res =
Expand All @@ -74,13 +74,19 @@ let generate window root =
let> () = undo in
Fut.return res
in
let step = step + 1 in
let entries = entry_action window step :: entries in
loop undo entries step categorized_els
else loop undo entries step res
let step = if auto_continue then step else step + 1 in
let entries =
if auto_continue then entries
else entry_action window step :: entries
in
let auto_continue = Brr.El.at !!"auto-continue" a |> Option.is_some in
loop ~auto_continue undo entries step categorized_els
Comment on lines +82 to +83
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Advance the recursion with res, not categorized_els.

Line 83 re-enters loop with the original list, so the same action is processed forever and TOC generation never progresses past the first action node.

Suggested fix
-          loop ~auto_continue undo entries step categorized_els
+          loop ~auto_continue undo entries step res
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let auto_continue = Brr.El.at !!"auto-continue" a |> Option.is_some in
loop ~auto_continue undo entries step categorized_els
let auto_continue = Brr.El.at !!"auto-continue" a |> Option.is_some in
loop ~auto_continue undo entries step res
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/engine/runtime/table_of_content/table_of_content.ml` around lines 82 -
83, The recursion in function loop is advancing with the original
categorized_els, causing an infinite re-processing of the same action; change
the recursive call to pass the updated list (res) instead of categorized_els so
the next step processes the remaining entries. Locate the call loop
~auto_continue undo entries step categorized_els and replace the last argument
with res, ensuring variable res (the result of advancing the sequence) is
threaded into subsequent loop invocations.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, Step.Action_scheduler.AttributeActions.do_ has some side-effect and Step.Action_scheduler.is_action a will inevitably become false.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@panglesd, you’re right — I missed that Step.Action_scheduler.AttributeActions.do_ mutates the action state before the recursive call. With that side effect, re-entering with categorized_els re-checks the same element once, Step.Action_scheduler.is_action a becomes false, and the recursion then advances via the else ... res branch. So this is not an infinite loop, and my suggested change would be inappropriate here.

I’ll keep this behavior in mind for future reviews.

🐇💭


✏️ Learnings added
Learnt from: panglesd
Repo: panglesd/slipshow PR: 240
File: src/engine/runtime/table_of_content/table_of_content.ml:82-83
Timestamp: 2026-05-29T22:24:41.640Z
Learning: In `src/engine/runtime/table_of_content/table_of_content.ml` in the `generate` function's recursive `loop`, `Step.Action_scheduler.AttributeActions.do_ ~mode window a` has side effects that update the action state of element `a`. After it runs, `Step.Action_scheduler.is_action a` will become false, so recursively calling `loop` with the original `categorized_els` list is intentional: the same `Action a` is re-checked and then consumed through the `else ... res` branch. Do not flag this pattern as an infinite loop without accounting for the side effect.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: panglesd
Repo: panglesd/slipshow PR: 228
File: vendor/github.com/panglesd/cmarkit/src/cmarkit.ml:3824-3838
Timestamp: 2026-05-04T21:14:22.518Z
Learning: In OCaml, record field punning is valid syntax in both record construction and record update expressions. In record construction, `{ field }` expands to `{ field = field }` when the variable name matches the field name. In record update expressions, `{ r with field }` is shorthand for `{ r with field = field }` as long as a variable named `field` is in scope. This also works for qualified field names (e.g., `{ r with Module.Type.field = value }` as appropriate). When reviewing OCaml code, do not flag these forms as syntax errors.

Learnt from: panglesd
Repo: panglesd/slipshow PR: 228
File: vendor/github.com/panglesd/cmarkit/src/cmarkit.ml:3793-3810
Timestamp: 2026-05-04T21:14:50.423Z
Learning: In OCaml, record update field punning is legal in the `{ expr with field }` / `{ expr with Qualified.field }` forms. If a variable named `field` (or `rows` in the qualified example) is in scope, then `{ r with field }` is shorthand for `{ r with field = field }`. Likewise, `{ t with Block.Table.rows }` is shorthand for `{ t with Block.Table.rows = rows }` when `rows` is in scope. When reviewing, don’t flag `{ r with field }` as invalid syntax; only consider it an error if the corresponding pun variable (e.g., `field` / `rows`) is not in scope and thus cannot bind the right-hand side.

Learnt from: panglesd
Repo: panglesd/slipshow PR: 228
File: vendor/github.com/panglesd/cmarkit/src/cmarkit.ml:3793-3810
Timestamp: 2026-05-04T21:14:50.423Z
Learning: In OCaml, field punning also applies to record update (`with`) expressions. If a variable `x` is in scope, `{ r with x }` is valid shorthand for `{ r with x = x }` (not missing syntax). This also works for qualified field names: `{ t with Block.Table.rows }` is shorthand for `{ t with Block.Table.rows = Block.Table.rows }`. When reviewing OCaml code, do not flag these forms as invalid syntax.

else loop ~auto_continue undo entries step res
| [] -> Fut.return (undo, List.rev entries)
in
let* undo, entries = loop (Undoable.return ()) [] 0 categorized_els in
let* undo, entries =
loop ~auto_continue:false (Undoable.return ()) [] 0 categorized_els
in
let* (), undo = undo in
let+ () = undo () in
let els = entry_action window 0 :: entries in
Expand Down
13 changes: 13 additions & 0 deletions test/compiler/auto-next.t/auto-next.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
a

{pause}

b

{pause auto-continue}

c

{pause}

d
9 changes: 9 additions & 0 deletions test/compiler/auto-next.t/run.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Testing auto-next

$ slipshow compile auto-next.md

There should be 3 steps: a, then b appears, then c and d appears.

Also, check the toc!

$ cp auto-next.html /tmp/
Loading