Undo/Redo e Casos Avançados
Nesta página
Viagem no tempo: :undo / :redo / :history
Cada swap bem-sucedido grava um checkpoint num ring buffer por módulo
(padrão: 10 entradas). No prompt do zolo dev você pode navegar esse
histórico sem reescrever o código manualmente.
Comandos disponíveis no prompt:
| Comando | Efeito |
|---|---|
:undo |
Reverte o swap mais recente |
:redo |
Reaplicado o último :undo |
:history |
Lista checkpoints e contadores |
:reload <modulo> |
Força o swap de um módulo |
:eval <expr> |
Compila e roda uma expressão na VM viva |
:stats |
Latências p50/p95 e contagem de swaps |
O estado vivo é preservado em ambas as direções: um pub let count = 5
continua 5 após :undo, mesmo que a versão antiga tivesse o literal 0.
O stack de redo é limpo quando um novo swap "fresco" acontece após um :undo.
Edite a fórmula várias vezes; use :undo/:redo para navegar entre as versões.
// Feature: a perfect target to experiment with :undo / :redo
// Syntax: edit the formula multiple times; navigate the history.
// When to use: compare variants of a function without rewriting
// each one by hand. The `ReloadHistory` keeps the source of
// previous versions and re-applies them via swap.
pub fn calc(x: int) -> int {
// Edit this formula several times during the `dev` session.
// Each save adds a checkpoint; :undo rolls back one step.
return x * 2
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
// Feature: time-travel of hot-reloads — :undo / :redo / :history
// Syntax: commands at the `zolo dev` prompt (not Zolo words).
// When to use: experiment with variants of a function and roll
// back to a previous one quickly without editing by hand.
use formula::{calc}
fn main() {
print("ENTER prints calc(10). Use :undo / :redo / :history at the prompt.")
while true {
let line = io::read("*l")
if line is nil || line == "q" {
break
}
print("calc(10) = {calc(10)}")
}
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
Reload em loop fechado sem yield
Código que nunca cede o controle (sem io::read, sem sleep) ainda recebe
swaps: o hook de instrução da VM drena reloads pendentes a cada ~2000
instruções. O módulo worker.zolo pode ser editado enquanto o contador
gira — a próxima chamada a tick já usa a versão nova.
Edite a mensagem em tick() enquanto o loop roda — nenhuma ação manual necessária.
// Edit this while the demo is running. Save with Ctrl+S — the next
// `tick` call uses the new code with no manual intervention.
pub fn tick(i) {
print("tick {i}: still on V1 — edit me!")
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
// Demo 02 — Hot-reload during a TIGHT CPU LOOP.
//
// zolo dev examples/zolo_live/02_tight_loop/main.zolo
//
// This script has NO `io::read` or any other yield point. It just busies
// itself spinning a counter. Yet edits to `worker.zolo` take effect
// within milliseconds — the VM instruction hook drains pending swaps
// every ~2000 instructions, transparently to the user.
//
// While running, edit `worker.zolo` (e.g. change the message format)
// and watch the output update LIVE without any user action.
use worker::{tick}
fn main() {
let i = 0
let last_print = 0
while true {
i = i + 1
if i - last_print > 5_000_000 {
tick(i)
last_print = i
}
}
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
Closures capturadas fora do live-binding
Quando uma referência de função é copiada diretamente para uma lista ou
estrutura de dados (sem passar pelo thunk), o runtime ainda atualiza essa
referência. Ao fazer o swap, o coletor percorre o heap e substitui cada
ponteiro para a função antiga pela nova. O demo 09-closure-escape demonstra
isso com um fn_queue que acumula referências a greeter.greet antes de
qualquer edição:
Referências capturadas diretamente também são atualizadas no swap.
// Edit me — the queued function references in main.zolo update too,
// thanks to closure-correct hot-reload.
pub fn greet(who) {
print("V1: hi {who}")
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
// Demo 04 — Closure-correct hot-reload.
//
// zolo dev examples/zolo_live/04_closure_escape/main.zolo
//
// The script captures a function reference into a queue (`fn_queue`),
// then iterates and calls them. Even though the function value escapes
// the live-binding thunk, edits to greeter.zolo still take effect on
// next call: the closure registry walks the heap and patches every
// reference to the old function value with the new one.
//
// This is the deeper guarantee — works no matter how the function got
// captured.
mod greeter
fn main() {
let fn_queue = []
// Capture the function value DIRECTLY (no live-binding thunk):
fn_queue.push(greeter.greet)
fn_queue.push(greeter.greet)
fn_queue.push(greeter.greet)
print("Press ENTER to flush the queue — or 'q' to quit.")
print("Edit greeter.zolo while waiting; queued fn refs update too.")
while true {
let line = io::read("*l")
if line is nil || line == "q" {
break
}
for f in fn_queue {
f("queued")
}
}
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
Veja também