Browse the user guide

Performance and recovery

Capture local performance measurements and investigate editor failures.

Recover unsaved work

Recovery is enabled by default. Canopus periodically saves eligible unsaved drafts under the project’s .canopus/recovery directory. After an interrupted session, reopen the same project and choose Restore in the recovery prompt, then review and save the recovered files. Discard removes that recovery snapshot.

Drafts larger than 10 MiB and snapshots above the 64 MiB storage budget are skipped. Recovery messages report skipped data; keep saving regularly when working with large files. You can change the interval in milliseconds with recovery.interval or disable recovery with recovery.enabled: false in Settings and themes.

Use --session .canopus/session.json to keep tabs, pane layout, and cursor positions across normal launches; see Editing and navigation. Recovery and sessions are local files, separate from crash reports.

Record performance and failures

Profiling and crash reports are opt-in:

ruby --yjit exe/canopus --profile /tmp/canopus-profile.json example.rb
ruby --yjit exe/canopus --profile /tmp/canopus-allocations.json \
  --trace-allocations example.rb
ruby exe/canopus --crash-report /tmp/canopus-crash.json example.rb

--profile records bounded frame timings, Ruby allocation counts, stack samples, runtime details, and native draw counts when available. --trace-allocations also summarizes locations of live traced objects, but can substantially increase memory use and frame time. Missing native counters are reported as null.

--crash-report writes only after a handled Ruby exception. It includes a bounded message, backtrace, cause chain, and runtime/rendering context. It does not include environment variables, command-line arguments, buffers, project files, screenshots, or arbitrary object values, and nothing is uploaded. Messages and backtraces can still contain local paths or sensitive text, so review reports before sharing them. Native crashes and process termination cannot reliably be captured by this hook.

Use an existing private directory and a distinct filename for each report. Symlinks and paths overlapping selected input or configuration files are rejected. On macOS and Linux reports request mode 0600; Windows users should choose a private directory with appropriate ACLs.

Developers can produce current, reproducible measurements with:

BUDGET=1 ruby bench/require.rb

The require-only budget is 300 ms in a fresh Ruby process. It covers the library load, not window creation or the first rendered frame; those remain measured by the startup benchmark below.

ruby --yjit bench/frame_profile.rb --frames 120 --output /tmp/frames.json
ruby --yjit bench/minimap.rb
ruby bench/startup.rb --runs 3
ruby --yjit tools/native_check.rb --idle /tmp/native-check.png

Compare results only when the platform, renderer, viewport, Ruby/JIT mode, warmup, and diagnostic options match. Headless software rendering is a regression check, not a hardware-GPU performance result.

Bracket colors and indentation guides are requested and cached by visible source rows. Structural analysis stays in the bounded language worker; files on the large read-only path skip these decorations instead of scanning on the UI thread.

bench/minimap.rb renders a 10,000-line file through the real headless renderer. It asserts the per-frame cold-generation bound, texture reuse while scrolling, one-row regeneration after an edit, and warm p95 against a same-run minimap-off baseline. Compare raw timings only on the same Ruby, font, scale factor, and renderer.