mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat(tui): retire the tui2 experiment (#9640)
## Summary - Retire the experimental TUI2 implementation and its feature flag. - Remove TUI2-only config/schema/docs so the CLI stays on the terminal-native path. - Keep docs aligned with the legacy TUI while we focus on redraw-based improvements. ## Customer impact - Retires the TUI2 experiment and keeps Codex on the proven terminal-native UI while we invest in redraw-based improvements to the existing experience. ## Migration / compatibility - If you previously set tui2-related options in config.toml, they are now ignored and Codex continues using the existing terminal-native TUI (no action required). ## Context - What worked: a transcript-owned viewport delivered excellent resize rewrap and high-fidelity copy (especially for code). - Why stop: making that experience feel fully native across the environment matrix (terminal emulator, OS, input modality, multiplexer, font/theme, alt-screen behavior) creates a combinatorial explosion of edge cases. - What next: we are focusing on redraw-based improvements to the existing terminal-native TUI so scrolling, selection, and copy remain native while resize/redraw correctness improves. ## Testing - just write-config-schema - just fmt - cargo clippy --fix --all-features --tests --allow-dirty --allow-no-vcs -p codex-core - cargo clippy --fix --all-features --tests --allow-dirty --allow-no-vcs -p codex-cli - cargo check - cargo test -p codex-core - cargo test -p codex-cli
This commit is contained in:
committed by
GitHub
Unverified
parent
41e38856f6
commit
a489b64cb5
Generated
-7
@@ -641,7 +641,6 @@
|
||||
"colorchoice_1.0.4": "{\"dependencies\":[],\"features\":{}}",
|
||||
"combine_4.6.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-std\",\"req\":\"^1\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"bytes\",\"req\":\"^1\"},{\"name\":\"bytes_05\",\"optional\":true,\"package\":\"bytes\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"bytes_05\",\"package\":\"bytes\",\"req\":\"^0.5\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"futures-03-dep\",\"package\":\"futures\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"futures-core-03\",\"optional\":true,\"package\":\"futures-core\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"futures-io-03\",\"optional\":true,\"package\":\"futures-io\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2.3\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.0\"},{\"features\":[\"tokio\",\"quickcheck\"],\"kind\":\"dev\",\"name\":\"partial-io\",\"req\":\"^0.3\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"quick-error\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^0.6\"},{\"name\":\"regex\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio-02-dep\",\"optional\":true,\"package\":\"tokio\",\"req\":\"^0.2.3\"},{\"features\":[\"fs\",\"io-driver\",\"io-util\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio-02-dep\",\"package\":\"tokio\",\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"tokio-03-dep\",\"optional\":true,\"package\":\"tokio\",\"req\":\"^0.3\"},{\"features\":[\"fs\",\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio-03-dep\",\"package\":\"tokio\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tokio-dep\",\"optional\":true,\"package\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"fs\",\"macros\",\"rt\",\"rt-multi-thread\",\"io-util\"],\"kind\":\"dev\",\"name\":\"tokio-dep\",\"package\":\"tokio\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"codec\"],\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"futures-03\":[\"pin-project\",\"std\",\"futures-core-03\",\"futures-io-03\",\"pin-project-lite\"],\"mp4\":[],\"pin-project\":[\"pin-project-lite\"],\"std\":[\"memchr/std\",\"bytes\",\"alloc\"],\"tokio\":[\"tokio-dep\",\"tokio-util/io\",\"futures-core-03\",\"pin-project-lite\"],\"tokio-02\":[\"pin-project\",\"std\",\"tokio-02-dep\",\"futures-core-03\",\"pin-project-lite\",\"bytes_05\"],\"tokio-03\":[\"pin-project\",\"std\",\"tokio-03-dep\",\"futures-core-03\",\"pin-project-lite\"]}}",
|
||||
"compact_str_0.8.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"borsh\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"castaway\",\"req\":\"^0.2.3\"},{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"cfg-if\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"diesel\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"itoa\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"markup\",\"optional\":true,\"req\":\"^0.13\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"proptest\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"size_32\"],\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"alloc\",\"size_32\"],\"kind\":\"dev\",\"name\":\"rkyv\",\"req\":\"^0.7\"},{\"name\":\"rustversion\",\"req\":\"^1\"},{\"name\":\"ryu\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\",\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"features\":[\"union\"],\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"sqlx\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"static_assertions\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"test-case\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"test-strategy\",\"req\":\"^0.3\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"borsh\":[\"dep:borsh\"],\"bytes\":[\"dep:bytes\"],\"default\":[\"std\"],\"diesel\":[\"dep:diesel\"],\"markup\":[\"dep:markup\"],\"proptest\":[\"dep:proptest\"],\"quickcheck\":[\"dep:quickcheck\"],\"rkyv\":[\"dep:rkyv\"],\"serde\":[\"dep:serde\"],\"smallvec\":[\"dep:smallvec\"],\"sqlx\":[\"dep:sqlx\",\"std\"],\"sqlx-mysql\":[\"sqlx\",\"sqlx/mysql\"],\"sqlx-postgres\":[\"sqlx\",\"sqlx/postgres\"],\"sqlx-sqlite\":[\"sqlx\",\"sqlx/sqlite\"],\"std\":[]}}",
|
||||
"compact_str_0.9.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"borsh\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"castaway\",\"req\":\"^0.2.3\"},{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"cfg-if\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"diesel\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"itoa\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"markup\",\"optional\":true,\"req\":\"^0.15\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"proptest\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rkyv\",\"req\":\"^0.8.8\"},{\"name\":\"rustversion\",\"req\":\"^1\"},{\"name\":\"ryu\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\",\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"features\":[\"union\"],\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"sqlx\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"static_assertions\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"test-case\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"test-strategy\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"borsh\":[\"dep:borsh\"],\"bytes\":[\"dep:bytes\"],\"default\":[\"std\"],\"diesel\":[\"dep:diesel\"],\"markup\":[\"dep:markup\"],\"proptest\":[\"dep:proptest\"],\"quickcheck\":[\"dep:quickcheck\"],\"rkyv\":[\"dep:rkyv\"],\"serde\":[\"dep:serde\"],\"smallvec\":[\"dep:smallvec\"],\"sqlx\":[\"dep:sqlx\",\"std\"],\"sqlx-mysql\":[\"sqlx\",\"sqlx/mysql\"],\"sqlx-postgres\":[\"sqlx\",\"sqlx/postgres\"],\"sqlx-sqlite\":[\"sqlx\",\"sqlx/sqlite\"],\"std\":[],\"zeroize\":[\"dep:zeroize\"]}}",
|
||||
"concurrent-queue_2.5.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"cargo_bench_support\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"crossbeam-utils\",\"req\":\"^0.8.11\"},{\"kind\":\"dev\",\"name\":\"easy-parallel\",\"req\":\"^3.1.0\"},{\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2.0.0\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}",
|
||||
"console_0.15.11": "{\"dependencies\":[{\"name\":\"encode_unicode\",\"req\":\"^1\",\"target\":\"cfg(windows)\"},{\"name\":\"libc\",\"req\":\"^0.2.99\"},{\"name\":\"once_cell\",\"req\":\"^1.8\"},{\"default_features\":false,\"features\":[\"std\",\"bit-set\",\"break-dead-code\"],\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.4.2\"},{\"name\":\"unicode-width\",\"optional\":true,\"req\":\"^0.2\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Console\",\"Win32_Storage_FileSystem\",\"Win32_UI_Input_KeyboardAndMouse\"],\"name\":\"windows-sys\",\"req\":\"^0.59\",\"target\":\"cfg(windows)\"}],\"features\":{\"ansi-parsing\":[],\"default\":[\"unicode-width\",\"ansi-parsing\"],\"windows-console-colors\":[\"ansi-parsing\"]}}",
|
||||
"const-hex_1.17.0": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"name\":\"cpufeatures\",\"req\":\"^0.2\",\"target\":\"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\"},{\"kind\":\"dev\",\"name\":\"divan\",\"package\":\"codspeed-divan-compat\",\"req\":\"^3\"},{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"faster-hex\",\"req\":\"^0.10.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"~0.4.2\"},{\"default_features\":false,\"name\":\"proptest\",\"optional\":true,\"req\":\"^1.4\"},{\"kind\":\"dev\",\"name\":\"rustc-hex\",\"req\":\"^2.1\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"__fuzzing\":[\"dep:proptest\",\"std\"],\"alloc\":[\"serde_core?/alloc\",\"proptest?/alloc\"],\"core-error\":[],\"default\":[\"std\"],\"force-generic\":[],\"hex\":[],\"nightly\":[],\"portable-simd\":[],\"serde\":[\"dep:serde_core\"],\"std\":[\"serde_core?/std\",\"proptest?/std\",\"alloc\"]}}",
|
||||
@@ -697,7 +696,6 @@
|
||||
"display_container_0.9.0": "{\"dependencies\":[{\"name\":\"either\",\"req\":\"^1.8\"},{\"name\":\"indenter\",\"req\":\"^0.3.3\"}],\"features\":{}}",
|
||||
"displaydoc_0.2.5": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^0.6.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^1.0.24\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}",
|
||||
"doc-comment_0.3.3": "{\"dependencies\":[],\"features\":{\"no_core\":[],\"old_macros\":[]}}",
|
||||
"document-features_0.2.12": "{\"dependencies\":[{\"name\":\"litrs\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[],\"self-test\":[]}}",
|
||||
"dotenvy_0.15.7": "{\"dependencies\":[{\"name\":\"clap\",\"optional\":true,\"req\":\"^3.2\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.16.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.3.0\"}],\"features\":{\"cli\":[\"clap\"]}}",
|
||||
"downcast-rs_1.2.1": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}",
|
||||
"dtor-proc-macro_0.0.6": "{\"dependencies\":[],\"features\":{\"default\":[]}}",
|
||||
@@ -836,7 +834,6 @@
|
||||
"jni_0.21.1": "{\"dependencies\":[{\"name\":\"cesu8\",\"req\":\"^1.1.0\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"combine\",\"req\":\"^4.1.0\"},{\"name\":\"java-locator\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"jni-sys\",\"req\":\"^0.3.0\"},{\"name\":\"libloading\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"name\":\"thiserror\",\"req\":\"^1.0.20\"},{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.5.0\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rusty-fork\",\"req\":\"^0.3.0\"},{\"kind\":\"build\",\"name\":\"walkdir\",\"req\":\"^2\"},{\"features\":[\"Win32_Globalization\"],\"name\":\"windows-sys\",\"req\":\"^0.45.0\",\"target\":\"cfg(windows)\"},{\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.13.0\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[],\"invocation\":[\"java-locator\",\"libloading\"]}}",
|
||||
"jobserver_0.1.34": "{\"dependencies\":[{\"features\":[\"std\"],\"name\":\"getrandom\",\"req\":\"^0.3.2\",\"target\":\"cfg(windows)\"},{\"name\":\"libc\",\"req\":\"^0.2.171\",\"target\":\"cfg(unix)\"},{\"features\":[\"fs\"],\"kind\":\"dev\",\"name\":\"nix\",\"req\":\"^0.28.0\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.10.1\"}],\"features\":{}}",
|
||||
"js-sys_0.3.77": "{\"dependencies\":[{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.100\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"wasm-bindgen/std\"]}}",
|
||||
"kasuari_0.4.11": "{\"dependencies\":[{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"hashbrown\",\"req\":\"^0.16\"},{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1.11\"},{\"features\":[\"alloc\"],\"name\":\"portable-atomic-util\",\"optional\":true,\"req\":\"^0.2.4\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2.0\"}],\"features\":{\"default\":[\"std\"],\"document-features\":[\"dep:document-features\"],\"portable-atomic\":[\"dep:portable-atomic\",\"dep:portable-atomic-util\"],\"std\":[\"thiserror/std\",\"portable-atomic?/std\"]}}",
|
||||
"keyring_3.6.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"byteorder\",\"optional\":true,\"req\":\"^1.2\",\"target\":\"cfg(target_os = \\\"windows\\\")\"},{\"features\":[\"derive\",\"wrap_help\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4\"},{\"name\":\"dbus-secret-service\",\"optional\":true,\"req\":\"^4.0.0-rc.1\",\"target\":\"cfg(target_os = \\\"openbsd\\\")\"},{\"name\":\"dbus-secret-service\",\"optional\":true,\"req\":\"^4.0.0-rc.2\",\"target\":\"cfg(target_os = \\\"linux\\\")\"},{\"name\":\"dbus-secret-service\",\"optional\":true,\"req\":\"^4.0.1\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11.5\"},{\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2\"},{\"features\":[\"std\"],\"name\":\"linux-keyutils\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(target_os = \\\"linux\\\")\"},{\"name\":\"log\",\"req\":\"^0.4.22\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10.66\"},{\"kind\":\"dev\",\"name\":\"rpassword\",\"req\":\"^7\"},{\"kind\":\"dev\",\"name\":\"rprompt\",\"req\":\"^2\"},{\"name\":\"secret-service\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"name\":\"secret-service\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"linux\\\")\"},{\"name\":\"secret-service\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"openbsd\\\")\"},{\"name\":\"security-framework\",\"optional\":true,\"req\":\"^2\",\"target\":\"cfg(target_os = \\\"ios\\\")\"},{\"name\":\"security-framework\",\"optional\":true,\"req\":\"^3\",\"target\":\"cfg(target_os = \\\"macos\\\")\"},{\"kind\":\"dev\",\"name\":\"whoami\",\"req\":\"^1.5\"},{\"features\":[\"Win32_Foundation\",\"Win32_Security_Credentials\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\"^0.60\",\"target\":\"cfg(target_os = \\\"windows\\\")\"},{\"name\":\"zbus\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"name\":\"zbus\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"linux\\\")\"},{\"name\":\"zbus\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"openbsd\\\")\"},{\"name\":\"zeroize\",\"req\":\"^1.8.1\",\"target\":\"cfg(target_os = \\\"windows\\\")\"}],\"features\":{\"apple-native\":[\"dep:security-framework\"],\"async-io\":[\"zbus?/async-io\"],\"async-secret-service\":[\"dep:secret-service\",\"dep:zbus\"],\"crypto-openssl\":[\"dbus-secret-service?/crypto-openssl\",\"secret-service?/crypto-openssl\"],\"crypto-rust\":[\"dbus-secret-service?/crypto-rust\",\"secret-service?/crypto-rust\"],\"linux-native\":[\"dep:linux-keyutils\"],\"linux-native-async-persistent\":[\"linux-native\",\"async-secret-service\"],\"linux-native-sync-persistent\":[\"linux-native\",\"sync-secret-service\"],\"sync-secret-service\":[\"dep:dbus-secret-service\"],\"tokio\":[\"zbus?/tokio\"],\"vendored\":[\"dbus-secret-service?/vendored\",\"openssl?/vendored\"],\"windows-native\":[\"dep:windows-sys\",\"dep:byteorder\"]}}",
|
||||
"kqueue-sys_1.0.4": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^1.2.1\"},{\"name\":\"libc\",\"req\":\"^0.2.74\"}],\"features\":{}}",
|
||||
"kqueue_1.1.1": "{\"dependencies\":[{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"dhat\",\"req\":\"^0.3.2\"},{\"name\":\"kqueue-sys\",\"req\":\"^1.0.4\"},{\"name\":\"libc\",\"req\":\"^0.2.17\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\"}],\"features\":{}}",
|
||||
@@ -852,7 +849,6 @@
|
||||
"linux-raw-sys_0.4.15": "{\"dependencies\":[{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.49\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.100\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"bootparam\":[],\"btrfs\":[],\"default\":[\"std\",\"general\",\"errno\"],\"elf\":[],\"elf_uapi\":[],\"errno\":[],\"general\":[],\"if_arp\":[],\"if_ether\":[],\"if_packet\":[],\"io_uring\":[],\"ioctl\":[],\"landlock\":[],\"loop_device\":[],\"mempolicy\":[],\"net\":[],\"netlink\":[],\"no_std\":[],\"prctl\":[],\"ptrace\":[],\"rustc-dep-of-std\":[\"core\",\"compiler_builtins\",\"no_std\"],\"std\":[],\"system\":[],\"xdp\":[]}}",
|
||||
"linux-raw-sys_0.9.4": "{\"dependencies\":[{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.49\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.100\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"bootparam\":[],\"btrfs\":[],\"default\":[\"std\",\"general\",\"errno\"],\"elf\":[],\"elf_uapi\":[],\"errno\":[],\"general\":[],\"if_arp\":[],\"if_ether\":[],\"if_packet\":[],\"image\":[],\"io_uring\":[],\"ioctl\":[],\"landlock\":[],\"loop_device\":[],\"mempolicy\":[],\"net\":[],\"netlink\":[],\"no_std\":[],\"prctl\":[],\"ptrace\":[],\"rustc-dep-of-std\":[\"core\",\"compiler_builtins\",\"no_std\"],\"std\":[],\"system\":[],\"xdp\":[]}}",
|
||||
"litemap_0.8.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"use-std\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"features\":[\"validation\"],\"kind\":\"dev\",\"name\":\"rkyv\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.110\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.110\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"yoke\",\"optional\":true,\"req\":\"^0.8.0\"}],\"features\":{\"alloc\":[],\"databake\":[\"dep:databake\"],\"default\":[\"alloc\"],\"serde\":[\"dep:serde\",\"alloc\"],\"testing\":[\"alloc\"],\"yoke\":[\"dep:yoke\"]}}",
|
||||
"litrs_1.0.0": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"optional\":true,\"req\":\"^1.0.63\"},{\"name\":\"unicode-xid\",\"optional\":true,\"req\":\"^0.2.4\"}],\"features\":{\"check_suffix\":[\"unicode-xid\"]}}",
|
||||
"local-waker_0.1.4": "{\"dependencies\":[],\"features\":{}}",
|
||||
"lock_api_0.4.13": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"autocfg\",\"req\":\"^1.1.0\"},{\"name\":\"owning_ref\",\"optional\":true,\"req\":\"^0.4.1\"},{\"default_features\":false,\"name\":\"scopeguard\",\"req\":\"^1.1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.126\"}],\"features\":{\"arc_lock\":[],\"atomic_usize\":[],\"default\":[\"atomic_usize\"],\"nightly\":[]}}",
|
||||
"log_0.4.29": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.63\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"sval\",\"optional\":true,\"req\":\"^2.16\"},{\"kind\":\"dev\",\"name\":\"sval\",\"req\":\"^2.16\"},{\"kind\":\"dev\",\"name\":\"sval_derive\",\"req\":\"^2.16\"},{\"default_features\":false,\"name\":\"sval_ref\",\"optional\":true,\"req\":\"^2.16\"},{\"default_features\":false,\"features\":[\"inline-i128\"],\"name\":\"value-bag\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"test\"],\"kind\":\"dev\",\"name\":\"value-bag\",\"req\":\"^1.12\"}],\"features\":{\"kv\":[],\"kv_serde\":[\"kv_std\",\"value-bag/serde\",\"serde\"],\"kv_std\":[\"std\",\"kv\",\"value-bag/error\"],\"kv_sval\":[\"kv\",\"value-bag/sval\",\"sval\",\"sval_ref\"],\"kv_unstable\":[\"kv\",\"value-bag\"],\"kv_unstable_serde\":[\"kv_serde\",\"kv_unstable_std\"],\"kv_unstable_std\":[\"kv_std\",\"kv_unstable\"],\"kv_unstable_sval\":[\"kv_sval\",\"kv_unstable\"],\"max_level_debug\":[],\"max_level_error\":[],\"max_level_info\":[],\"max_level_off\":[],\"max_level_trace\":[],\"max_level_warn\":[],\"release_max_level_debug\":[],\"release_max_level_error\":[],\"release_max_level_info\":[],\"release_max_level_off\":[],\"release_max_level_trace\":[],\"release_max_level_warn\":[],\"serde\":[\"serde_core\"],\"std\":[]}}",
|
||||
@@ -983,7 +979,6 @@
|
||||
"rand_core_0.6.4": "{\"dependencies\":[{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.2\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[],\"serde1\":[\"serde\"],\"std\":[\"alloc\",\"getrandom\",\"getrandom/std\"]}}",
|
||||
"rand_core_0.9.3": "{\"dependencies\":[{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"os_rng\":[\"dep:getrandom\"],\"serde\":[\"dep:serde\"],\"std\":[\"getrandom?/std\"]}}",
|
||||
"rand_xorshift_0.4.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1\"},{\"name\":\"rand_core\",\"req\":\"^0.9.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.118\"}],\"features\":{\"serde\":[\"dep:serde\"]}}",
|
||||
"ratatui-core_0.1.0": "{\"dependencies\":[{\"name\":\"anstyle\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"bitflags\",\"req\":\"^2.10\"},{\"default_features\":false,\"name\":\"compact_str\",\"req\":\"^0.9\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"hashbrown\",\"req\":\"^0.16\"},{\"name\":\"indoc\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"use_alloc\"],\"name\":\"itertools\",\"req\":\"^0.14\"},{\"default_features\":false,\"name\":\"kasuari\",\"req\":\"^0.4\"},{\"name\":\"lru\",\"req\":\"^0.16\"},{\"name\":\"palette\",\"optional\":true,\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"strum\",\"req\":\"^0.27\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"name\":\"unicode-segmentation\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"unicode-truncate\",\"req\":\"^2\"},{\"name\":\"unicode-width\",\"req\":\">=0.2.0, <=0.2.2\"}],\"features\":{\"anstyle\":[\"dep:anstyle\"],\"default\":[],\"layout-cache\":[\"std\"],\"palette\":[\"std\",\"dep:palette\"],\"portable-atomic\":[\"kasuari/portable-atomic\"],\"scrolling-regions\":[],\"serde\":[\"std\",\"dep:serde\",\"bitflags/serde\",\"compact_str/serde\"],\"std\":[\"itertools/use_std\",\"thiserror/std\",\"kasuari/std\",\"compact_str/std\",\"unicode-truncate/std\",\"strum/std\"],\"underline-color\":[]}}",
|
||||
"ratatui-macros_0.6.0": "{\"dependencies\":[{\"features\":[\"user-hooks\"],\"kind\":\"dev\",\"name\":\"cargo-husky\",\"req\":\"^1.5.0\"},{\"name\":\"ratatui\",\"req\":\"^0.29.0\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.101\"}],\"features\":{}}",
|
||||
"redox_syscall_0.5.15": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.4\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7\",\"target\":\"cfg(loom)\"}],\"features\":{\"default\":[\"userspace\"],\"rustc-dep-of-std\":[\"core\",\"bitflags/rustc-dep-of-std\"],\"std\":[],\"userspace\":[]}}",
|
||||
"redox_users_0.4.6": "{\"dependencies\":[{\"features\":[\"std\"],\"name\":\"getrandom\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"std\",\"call\"],\"name\":\"libredox\",\"req\":\"^0.1.3\"},{\"name\":\"rust-argon2\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"thiserror\",\"req\":\"^1.0\"},{\"features\":[\"zeroize_derive\"],\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.4\"}],\"features\":{\"auth\":[\"rust-argon2\",\"zeroize\"],\"default\":[\"auth\"]}}",
|
||||
@@ -1162,7 +1157,6 @@
|
||||
"try-lock_0.2.5": "{\"dependencies\":[],\"features\":{}}",
|
||||
"ts-rs-macros_11.1.0": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2.0.28\"},{\"name\":\"termcolor\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"no-serde-warnings\":[],\"serde-compat\":[\"termcolor\"]}}",
|
||||
"ts-rs_11.1.0": "{\"dependencies\":[{\"features\":[\"serde\"],\"name\":\"bigdecimal\",\"optional\":true,\"req\":\">=0.0.13, <0.5\"},{\"name\":\"bson\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4\"},{\"name\":\"dprint-plugin-typescript\",\"optional\":true,\"req\":\"=0.95\"},{\"name\":\"heapless\",\"optional\":true,\"req\":\">=0.7, <0.9\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"ordered-float\",\"optional\":true,\"req\":\">=3, <6\"},{\"name\":\"semver\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"name\":\"smol_str\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"sync\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.40\"},{\"name\":\"ts-rs-macros\",\"req\":\"=11.1.0\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"uuid\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"bigdecimal-impl\":[\"bigdecimal\"],\"bson-uuid-impl\":[\"bson\"],\"bytes-impl\":[\"bytes\"],\"chrono-impl\":[\"chrono\"],\"default\":[\"serde-compat\"],\"format\":[\"dprint-plugin-typescript\"],\"heapless-impl\":[\"heapless\"],\"import-esm\":[],\"indexmap-impl\":[\"indexmap\"],\"no-serde-warnings\":[\"ts-rs-macros/no-serde-warnings\"],\"ordered-float-impl\":[\"ordered-float\"],\"semver-impl\":[\"semver\"],\"serde-compat\":[\"ts-rs-macros/serde-compat\"],\"serde-json-impl\":[\"serde_json\"],\"smol_str-impl\":[\"smol_str\"],\"tokio-impl\":[\"tokio\"],\"url-impl\":[\"url\"],\"uuid-impl\":[\"uuid\"]}}",
|
||||
"tui-scrollbar_0.2.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"color-eyre\",\"req\":\"^0.6\"},{\"name\":\"crossterm_0_28\",\"optional\":true,\"package\":\"crossterm\",\"req\":\"^0.28\"},{\"name\":\"crossterm_0_29\",\"optional\":true,\"package\":\"crossterm\",\"req\":\"^0.29\"},{\"name\":\"document-features\",\"req\":\"^0.2.11\"},{\"kind\":\"dev\",\"name\":\"ratatui\",\"req\":\"^0.30.0\"},{\"name\":\"ratatui-core\",\"req\":\"^0.1\"}],\"features\":{\"crossterm\":[\"crossterm_0_29\"],\"crossterm_0_28\":[\"dep:crossterm_0_28\"],\"crossterm_0_29\":[\"dep:crossterm_0_29\"],\"default\":[]}}",
|
||||
"typenum_1.18.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"scale-info\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"const-generics\":[],\"force_unix_path_separator\":[],\"i128\":[],\"no_std\":[],\"scale_info\":[\"scale-info/derive\"],\"strict\":[]}}",
|
||||
"uds_windows_1.1.0": "{\"dependencies\":[{\"name\":\"memoffset\",\"req\":\"^0.9.0\"},{\"name\":\"tempfile\",\"req\":\"^3\",\"target\":\"cfg(windows)\"},{\"features\":[\"winsock2\",\"ws2def\",\"minwinbase\",\"ntdef\",\"processthreadsapi\",\"handleapi\",\"ws2tcpip\",\"winbase\"],\"name\":\"winapi\",\"req\":\"^0.3.9\",\"target\":\"cfg(windows)\"}],\"features\":{}}",
|
||||
"uname_0.1.1": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2\"}],\"features\":{}}",
|
||||
@@ -1172,7 +1166,6 @@
|
||||
"unicode-linebreak_0.1.5": "{\"dependencies\":[],\"features\":{}}",
|
||||
"unicode-segmentation_1.12.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^0.7\"}],\"features\":{\"no_std\":[]}}",
|
||||
"unicode-truncate_1.1.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"itertools\",\"req\":\"^0.13\"},{\"default_features\":false,\"name\":\"unicode-segmentation\",\"req\":\"^1\"},{\"name\":\"unicode-width\",\"req\":\"^0.1\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}",
|
||||
"unicode-truncate_2.0.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"itertools\",\"req\":\"^0.13\"},{\"default_features\":false,\"name\":\"unicode-segmentation\",\"req\":\"^1\"},{\"name\":\"unicode-width\",\"req\":\"^0.2\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}",
|
||||
"unicode-width_0.1.14": "{\"dependencies\":[{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"std\",\"optional\":true,\"package\":\"rustc-std-workspace-std\",\"req\":\"^1.0\"}],\"features\":{\"cjk\":[],\"default\":[\"cjk\"],\"no_std\":[],\"rustc-dep-of-std\":[\"std\",\"core\",\"compiler_builtins\"]}}",
|
||||
"unicode-width_0.2.1": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"std\",\"optional\":true,\"package\":\"rustc-std-workspace-std\",\"req\":\"^1.0\"}],\"features\":{\"cjk\":[],\"default\":[\"cjk\"],\"no_std\":[],\"rustc-dep-of-std\":[\"std\",\"core\"]}}",
|
||||
"unicode-xid_0.2.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"}],\"features\":{\"bench\":[],\"default\":[],\"no_std\":[]}}",
|
||||
|
||||
Generated
+2
-162
@@ -1166,8 +1166,6 @@ dependencies = [
|
||||
"codex-rmcp-client",
|
||||
"codex-stdio-to-uds",
|
||||
"codex-tui",
|
||||
"codex-tui2",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-cargo-bin",
|
||||
"codex-windows-sandbox",
|
||||
"libc",
|
||||
@@ -1811,81 +1809,6 @@ dependencies = [
|
||||
"winsplit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-tui2"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arboard",
|
||||
"assert_matches",
|
||||
"async-stream",
|
||||
"base64",
|
||||
"chrono",
|
||||
"clap",
|
||||
"codex-ansi-escape",
|
||||
"codex-app-server-protocol",
|
||||
"codex-arg0",
|
||||
"codex-backend-client",
|
||||
"codex-cli",
|
||||
"codex-common",
|
||||
"codex-core",
|
||||
"codex-feedback",
|
||||
"codex-file-search",
|
||||
"codex-login",
|
||||
"codex-otel",
|
||||
"codex-protocol",
|
||||
"codex-tui",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-cargo-bin",
|
||||
"codex-utils-pty",
|
||||
"codex-windows-sandbox",
|
||||
"color-eyre",
|
||||
"crossterm",
|
||||
"derive_more 2.1.1",
|
||||
"diffy",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"image",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"mcp-types",
|
||||
"pathdiff",
|
||||
"pretty_assertions",
|
||||
"pulldown-cmark",
|
||||
"rand 0.9.2",
|
||||
"ratatui",
|
||||
"ratatui-core",
|
||||
"ratatui-macros",
|
||||
"regex-lite",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
"shlex",
|
||||
"strum 0.27.2",
|
||||
"strum_macros 0.27.2",
|
||||
"supports-color 3.0.2",
|
||||
"tempfile",
|
||||
"textwrap 0.16.2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"toml 0.9.5",
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
"tracing-subscriber",
|
||||
"tree-sitter-bash",
|
||||
"tree-sitter-highlight",
|
||||
"tui-scrollbar",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.2.1",
|
||||
"url",
|
||||
"uuid",
|
||||
"vt100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-utils-absolute-path"
|
||||
version = "0.0.0"
|
||||
@@ -2048,20 +1971,6 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
|
||||
dependencies = [
|
||||
"castaway",
|
||||
"cfg-if",
|
||||
"itoa",
|
||||
"rustversion",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
@@ -2648,15 +2557,6 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "document-features"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
|
||||
dependencies = [
|
||||
"litrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.7"
|
||||
@@ -3988,16 +3888,6 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kasuari"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fe90c1150662e858c7d5f945089b7517b0a80d8bf7ba4b1b5ffc984e7230a5b"
|
||||
dependencies = [
|
||||
"hashbrown 0.16.0",
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keyring"
|
||||
version = "3.6.3"
|
||||
@@ -4143,12 +4033,6 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
|
||||
|
||||
[[package]]
|
||||
name = "local-waker"
|
||||
version = "0.1.4"
|
||||
@@ -5488,7 +5372,7 @@ source = "git+https://github.com/nornagon/ratatui?branch=nornagon-v0.29.0-patch#
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"cassowary",
|
||||
"compact_str 0.8.1",
|
||||
"compact_str",
|
||||
"crossterm",
|
||||
"indoc",
|
||||
"instability",
|
||||
@@ -5497,27 +5381,7 @@ dependencies = [
|
||||
"paste",
|
||||
"strum 0.26.3",
|
||||
"unicode-segmentation",
|
||||
"unicode-truncate 1.1.0",
|
||||
"unicode-width 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ratatui-core"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"compact_str 0.9.0",
|
||||
"hashbrown 0.16.0",
|
||||
"indoc",
|
||||
"itertools 0.14.0",
|
||||
"kasuari",
|
||||
"lru 0.16.3",
|
||||
"strum 0.27.2",
|
||||
"thiserror 2.0.17",
|
||||
"unicode-segmentation",
|
||||
"unicode-truncate 2.0.0",
|
||||
"unicode-truncate",
|
||||
"unicode-width 0.2.1",
|
||||
]
|
||||
|
||||
@@ -6684,9 +6548,6 @@ name = "strum"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||
dependencies = [
|
||||
"strum_macros 0.27.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
@@ -7549,16 +7410,6 @@ dependencies = [
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tui-scrollbar"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4267311b5c7999a996ea94939b6d2b1b44a9e5cc11e76cbbb6dcca4c281df4"
|
||||
dependencies = [
|
||||
"document-features",
|
||||
"ratatui-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.28.0"
|
||||
@@ -7644,17 +7495,6 @@ dependencies = [
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-truncate"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fbf03860ff438702f3910ca5f28f8dac63c1c11e7efb5012b8b175493606330"
|
||||
dependencies = [
|
||||
"itertools 0.13.0",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.14"
|
||||
|
||||
@@ -35,7 +35,6 @@ members = [
|
||||
"stdio-to-uds",
|
||||
"otel",
|
||||
"tui",
|
||||
"tui2",
|
||||
"utils/absolute-path",
|
||||
"utils/cargo-bin",
|
||||
"utils/git",
|
||||
@@ -93,7 +92,6 @@ codex-responses-api-proxy = { path = "responses-api-proxy" }
|
||||
codex-rmcp-client = { path = "rmcp-client" }
|
||||
codex-stdio-to-uds = { path = "stdio-to-uds" }
|
||||
codex-tui = { path = "tui" }
|
||||
codex-tui2 = { path = "tui2" }
|
||||
codex-utils-absolute-path = { path = "utils/absolute-path" }
|
||||
codex-utils-cache = { path = "utils/cache" }
|
||||
codex-utils-cargo-bin = { path = "utils/cargo-bin" }
|
||||
@@ -178,7 +176,6 @@ pretty_assertions = "1.4.1"
|
||||
pulldown-cmark = "0.10"
|
||||
rand = "0.9"
|
||||
ratatui = "0.29.0"
|
||||
ratatui-core = "0.1.0"
|
||||
ratatui-macros = "0.6.0"
|
||||
regex = "1.12.2"
|
||||
regex-lite = "0.1.8"
|
||||
@@ -225,7 +222,6 @@ tree-sitter-bash = "0.25"
|
||||
zstd = "0.13"
|
||||
tree-sitter-highlight = "0.25.10"
|
||||
ts-rs = "11"
|
||||
tui-scrollbar = "0.2.2"
|
||||
uds_windows = "1.1.0"
|
||||
unicode-segmentation = "1.12.0"
|
||||
unicode-width = "0.2"
|
||||
|
||||
@@ -35,8 +35,6 @@ codex-responses-api-proxy = { workspace = true }
|
||||
codex-rmcp-client = { workspace = true }
|
||||
codex-stdio-to-uds = { workspace = true }
|
||||
codex-tui = { workspace = true }
|
||||
codex-tui2 = { workspace = true }
|
||||
codex-utils-absolute-path = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
owo-colors = { workspace = true }
|
||||
regex-lite = { workspace = true }
|
||||
|
||||
@@ -26,7 +26,6 @@ use codex_tui::AppExitInfo;
|
||||
use codex_tui::Cli as TuiCli;
|
||||
use codex_tui::ExitReason;
|
||||
use codex_tui::update_action::UpdateAction;
|
||||
use codex_tui2 as tui2;
|
||||
use owo_colors::OwoColorize;
|
||||
use std::io::IsTerminal;
|
||||
use std::path::PathBuf;
|
||||
@@ -40,14 +39,8 @@ use crate::mcp_cmd::McpCli;
|
||||
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::ConfigOverrides;
|
||||
use codex_core::config::find_codex_home;
|
||||
use codex_core::config::load_config_as_toml_with_cli_overrides;
|
||||
use codex_core::features::Feature;
|
||||
use codex_core::features::FeatureOverrides;
|
||||
use codex_core::features::Features;
|
||||
use codex_core::features::is_known_feature_key;
|
||||
use codex_core::terminal::TerminalName;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
/// Codex CLI
|
||||
///
|
||||
@@ -727,8 +720,6 @@ fn prepend_config_flags(
|
||||
.splice(0..0, cli_config_overrides.raw_overrides);
|
||||
}
|
||||
|
||||
/// Run the interactive Codex TUI, dispatching to either the legacy implementation or the
|
||||
/// experimental TUI v2 shim based on feature flags resolved from config.
|
||||
async fn run_interactive_tui(
|
||||
mut interactive: TuiCli,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
@@ -756,12 +747,7 @@ async fn run_interactive_tui(
|
||||
}
|
||||
}
|
||||
|
||||
if is_tui2_enabled(&interactive).await? {
|
||||
let result = tui2::run_main(interactive.into(), codex_linux_sandbox_exe).await?;
|
||||
Ok(result.into())
|
||||
} else {
|
||||
codex_tui::run_main(interactive, codex_linux_sandbox_exe).await
|
||||
}
|
||||
codex_tui::run_main(interactive, codex_linux_sandbox_exe).await
|
||||
}
|
||||
|
||||
fn confirm(prompt: &str) -> std::io::Result<bool> {
|
||||
@@ -773,32 +759,6 @@ fn confirm(prompt: &str) -> std::io::Result<bool> {
|
||||
Ok(answer.eq_ignore_ascii_case("y") || answer.eq_ignore_ascii_case("yes"))
|
||||
}
|
||||
|
||||
/// Returns `Ok(true)` when the resolved configuration enables the `tui2` feature flag.
|
||||
///
|
||||
/// This performs a lightweight config load (honoring the same precedence as the lower-level TUI
|
||||
/// bootstrap: `$CODEX_HOME`, config.toml, profile, and CLI `-c` overrides) solely to decide which
|
||||
/// TUI frontend to launch. The full configuration is still loaded later by the interactive TUI.
|
||||
async fn is_tui2_enabled(cli: &TuiCli) -> std::io::Result<bool> {
|
||||
let raw_overrides = cli.config_overrides.raw_overrides.clone();
|
||||
let overrides_cli = codex_common::CliConfigOverrides { raw_overrides };
|
||||
let cli_kv_overrides = overrides_cli
|
||||
.parse_overrides()
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
|
||||
|
||||
let codex_home = find_codex_home()?;
|
||||
let cwd = cli.cwd.clone();
|
||||
let config_cwd = match cwd.as_deref() {
|
||||
Some(path) => AbsolutePathBuf::from_absolute_path(path)?,
|
||||
None => AbsolutePathBuf::current_dir()?,
|
||||
};
|
||||
let config_toml =
|
||||
load_config_as_toml_with_cli_overrides(&codex_home, &config_cwd, cli_kv_overrides).await?;
|
||||
let config_profile = config_toml.get_config_profile(cli.config_profile.clone())?;
|
||||
let overrides = FeatureOverrides::default();
|
||||
let features = Features::from_config(&config_toml, &config_profile, overrides);
|
||||
Ok(features.enabled(Feature::Tui2))
|
||||
}
|
||||
|
||||
/// Build the final `TuiCli` for a `codex resume` invocation.
|
||||
fn finalize_resume_interactive(
|
||||
mut interactive: TuiCli,
|
||||
|
||||
@@ -198,9 +198,6 @@
|
||||
"steer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tui2": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"undo": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -826,32 +823,6 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ScrollInputMode": {
|
||||
"description": "How TUI2 should interpret mouse scroll events.\n\nTerminals generally encode both mouse wheels and trackpads as the same \"scroll up/down\" mouse button events, without a magnitude. This setting controls whether Codex uses a heuristic to infer wheel vs trackpad per stream, or forces a specific behavior.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Infer wheel vs trackpad behavior per scroll stream.",
|
||||
"enum": [
|
||||
"auto"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Always treat scroll events as mouse-wheel input (fixed lines per tick).",
|
||||
"enum": [
|
||||
"wheel"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Always treat scroll events as trackpad input (fractional accumulation).",
|
||||
"enum": [
|
||||
"trackpad"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ShellEnvironmentPolicyInherit": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -991,62 +962,6 @@
|
||||
"default": true,
|
||||
"description": "Enable desktop notifications from the TUI when the terminal is unfocused. Defaults to `true`."
|
||||
},
|
||||
"scroll_events_per_tick": {
|
||||
"description": "Override the *wheel* event density used to normalize TUI2 scrolling.\n\nTerminals generally deliver both mouse wheels and trackpads as discrete `scroll up/down` mouse events with direction but no magnitude. Unfortunately, the *number* of raw events per physical wheel notch varies by terminal (commonly 1, 3, or 9+). TUI2 uses this value to normalize that raw event density into consistent \"wheel tick\" behavior.\n\nWheel math (conceptually):\n\n- A single event contributes `1 / scroll_events_per_tick` tick-equivalents. - Wheel-like streams then scale that by `scroll_wheel_lines` so one physical notch scrolls a fixed number of lines.\n\nTrackpad math is intentionally *not* fully tied to this value: in trackpad-like mode, TUI2 uses `min(scroll_events_per_tick, 3)` as the divisor so terminals with dense wheel ticks (e.g. 9 events per notch) do not make trackpads feel artificially slow.\n\nDefaults are derived per terminal from [`crate::terminal::TerminalInfo`] when TUI2 starts. See `codex-rs/tui2/docs/scroll_input_model.md` for the probe data and rationale.",
|
||||
"format": "uint16",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"scroll_invert": {
|
||||
"default": false,
|
||||
"description": "Invert mouse scroll direction in TUI2.\n\nThis flips the scroll sign after terminal detection. It is applied consistently to both wheel and trackpad input.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"scroll_mode": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ScrollInputMode"
|
||||
}
|
||||
],
|
||||
"default": "auto",
|
||||
"description": "Select how TUI2 interprets mouse scroll input.\n\n- `auto` (default): infer wheel vs trackpad per scroll stream. - `wheel`: always use wheel behavior (fixed lines per wheel notch). - `trackpad`: always use trackpad behavior (fractional accumulation; wheel may feel slow)."
|
||||
},
|
||||
"scroll_trackpad_accel_events": {
|
||||
"description": "Trackpad acceleration: approximate number of events required to gain +1x speed in TUI2.\n\nThis keeps small swipes precise while allowing large/faster swipes to cover more content. Defaults are chosen to address terminals where trackpad event density is comparatively low.\n\nConcretely, TUI2 computes an acceleration multiplier for trackpad-like streams:\n\n- `multiplier = clamp(1 + abs(events) / scroll_trackpad_accel_events, 1..scroll_trackpad_accel_max)`\n\nThe multiplier is applied to the stream’s computed line delta (including any carried fractional remainder).",
|
||||
"format": "uint16",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"scroll_trackpad_accel_max": {
|
||||
"description": "Trackpad acceleration: maximum multiplier applied to trackpad-like streams.\n\nSet to 1 to effectively disable trackpad acceleration.\n\nSee [`Tui::scroll_trackpad_accel_events`] for the exact multiplier formula.",
|
||||
"format": "uint16",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"scroll_trackpad_lines": {
|
||||
"description": "Override baseline trackpad scroll sensitivity in TUI2.\n\nTrackpads do not have discrete notches, but terminals still emit discrete `scroll up/down` events. In trackpad-like mode, TUI2 accumulates fractional scroll and only applies whole lines to the viewport.\n\nTrackpad per-event contribution is:\n\n- `scroll_trackpad_lines / min(scroll_events_per_tick, 3)`\n\n(plus optional bounded acceleration; see `scroll_trackpad_accel_*`). The `min(..., 3)` divisor is deliberate: `scroll_events_per_tick` is calibrated from *wheel* behavior and can be much larger than trackpad event density, which would otherwise make trackpads feel too slow in dense-wheel terminals.\n\nDefaults to 1, meaning one tick-equivalent maps to one transcript line.",
|
||||
"format": "uint16",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"scroll_wheel_like_max_duration_ms": {
|
||||
"description": "Auto-mode fallback: maximum duration (ms) that a very small stream is still treated as wheel-like.\n\nThis is only used when `scroll_events_per_tick` is effectively 1 (one event per wheel notch). In that case, we cannot observe a \"tick completion time\", so TUI2 treats a short-lived, small stream (<= 2 events) as wheel-like to preserve classic wheel behavior.",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"scroll_wheel_lines": {
|
||||
"description": "Override how many transcript lines one physical *wheel notch* should scroll in TUI2.\n\nThis is the \"classic feel\" knob. Defaults to 3.\n\nWheel-like per-event contribution is `scroll_wheel_lines / scroll_events_per_tick`. For example, in a terminal that emits 9 events per notch, the default `3 / 9` yields 1/3 of a line per event and totals 3 lines once the full notch burst arrives.\n\nSee `codex-rs/tui2/docs/scroll_input_model.md` for details on the stream model and the wheel/trackpad heuristic.",
|
||||
"format": "uint16",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"scroll_wheel_tick_detect_max_ms": {
|
||||
"description": "Auto-mode threshold: maximum time (ms) for the first tick-worth of events to arrive.\n\nIn `scroll_mode = \"auto\"`, TUI2 starts a stream as trackpad-like (to avoid overshoot) and promotes it to wheel-like if `scroll_events_per_tick` events arrive \"quickly enough\". This threshold controls what \"quickly enough\" means.\n\nMost users should leave this unset; it is primarily for terminals that emit wheel ticks batched over longer time spans.",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"show_tooltips": {
|
||||
"default": true,
|
||||
"description": "Show startup tooltips in the TUI welcome screen. Defaults to `true`.",
|
||||
@@ -1246,9 +1161,6 @@
|
||||
"steer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tui2": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"undo": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -13,7 +13,6 @@ use crate::config::types::OtelConfigToml;
|
||||
use crate::config::types::OtelExporterKind;
|
||||
use crate::config::types::Personality;
|
||||
use crate::config::types::SandboxWorkspaceWrite;
|
||||
use crate::config::types::ScrollInputMode;
|
||||
use crate::config::types::ShellEnvironmentPolicy;
|
||||
use crate::config::types::ShellEnvironmentPolicyToml;
|
||||
use crate::config::types::SkillsConfig;
|
||||
@@ -200,58 +199,6 @@ pub struct Config {
|
||||
/// Show startup tooltips in the TUI welcome screen.
|
||||
pub show_tooltips: bool,
|
||||
|
||||
/// Override the events-per-wheel-tick factor for TUI2 scroll normalization.
|
||||
///
|
||||
/// This is the same `tui.scroll_events_per_tick` value from `config.toml`, plumbed through the
|
||||
/// merged [`Config`] object (see [`Tui`]) so TUI2 can normalize scroll event density per
|
||||
/// terminal.
|
||||
pub tui_scroll_events_per_tick: Option<u16>,
|
||||
|
||||
/// Override the number of lines applied per wheel tick in TUI2.
|
||||
///
|
||||
/// This is the same `tui.scroll_wheel_lines` value from `config.toml` (see [`Tui`]). TUI2
|
||||
/// applies it to wheel-like scroll streams. Trackpad-like scrolling uses a separate
|
||||
/// `tui.scroll_trackpad_lines` setting.
|
||||
pub tui_scroll_wheel_lines: Option<u16>,
|
||||
|
||||
/// Override the number of lines per tick-equivalent used for trackpad scrolling in TUI2.
|
||||
///
|
||||
/// This is the same `tui.scroll_trackpad_lines` value from `config.toml` (see [`Tui`]).
|
||||
pub tui_scroll_trackpad_lines: Option<u16>,
|
||||
|
||||
/// Trackpad acceleration: approximate number of events required to gain +1x speed in TUI2.
|
||||
///
|
||||
/// This is the same `tui.scroll_trackpad_accel_events` value from `config.toml` (see [`Tui`]).
|
||||
pub tui_scroll_trackpad_accel_events: Option<u16>,
|
||||
|
||||
/// Trackpad acceleration: maximum multiplier applied to trackpad-like streams in TUI2.
|
||||
///
|
||||
/// This is the same `tui.scroll_trackpad_accel_max` value from `config.toml` (see [`Tui`]).
|
||||
pub tui_scroll_trackpad_accel_max: Option<u16>,
|
||||
|
||||
/// Control how TUI2 interprets mouse scroll input (wheel vs trackpad).
|
||||
///
|
||||
/// This is the same `tui.scroll_mode` value from `config.toml` (see [`Tui`]).
|
||||
pub tui_scroll_mode: ScrollInputMode,
|
||||
|
||||
/// Override the wheel tick detection threshold (ms) for TUI2 auto scroll mode.
|
||||
///
|
||||
/// This is the same `tui.scroll_wheel_tick_detect_max_ms` value from `config.toml` (see
|
||||
/// [`Tui`]).
|
||||
pub tui_scroll_wheel_tick_detect_max_ms: Option<u64>,
|
||||
|
||||
/// Override the wheel-like end-of-stream threshold (ms) for TUI2 auto scroll mode.
|
||||
///
|
||||
/// This is the same `tui.scroll_wheel_like_max_duration_ms` value from `config.toml` (see
|
||||
/// [`Tui`]).
|
||||
pub tui_scroll_wheel_like_max_duration_ms: Option<u64>,
|
||||
|
||||
/// Invert mouse scroll direction for TUI2.
|
||||
///
|
||||
/// This is the same `tui.scroll_invert` value from `config.toml` (see [`Tui`]) and is applied
|
||||
/// consistently to both mouse wheels and trackpads.
|
||||
pub tui_scroll_invert: bool,
|
||||
|
||||
/// Controls whether the TUI uses the terminal's alternate screen buffer.
|
||||
///
|
||||
/// This is the same `tui.alternate_screen` value from `config.toml` (see [`Tui`]).
|
||||
@@ -1613,27 +1560,6 @@ impl Config {
|
||||
.unwrap_or_default(),
|
||||
animations: cfg.tui.as_ref().map(|t| t.animations).unwrap_or(true),
|
||||
show_tooltips: cfg.tui.as_ref().map(|t| t.show_tooltips).unwrap_or(true),
|
||||
tui_scroll_events_per_tick: cfg.tui.as_ref().and_then(|t| t.scroll_events_per_tick),
|
||||
tui_scroll_wheel_lines: cfg.tui.as_ref().and_then(|t| t.scroll_wheel_lines),
|
||||
tui_scroll_trackpad_lines: cfg.tui.as_ref().and_then(|t| t.scroll_trackpad_lines),
|
||||
tui_scroll_trackpad_accel_events: cfg
|
||||
.tui
|
||||
.as_ref()
|
||||
.and_then(|t| t.scroll_trackpad_accel_events),
|
||||
tui_scroll_trackpad_accel_max: cfg
|
||||
.tui
|
||||
.as_ref()
|
||||
.and_then(|t| t.scroll_trackpad_accel_max),
|
||||
tui_scroll_mode: cfg.tui.as_ref().map(|t| t.scroll_mode).unwrap_or_default(),
|
||||
tui_scroll_wheel_tick_detect_max_ms: cfg
|
||||
.tui
|
||||
.as_ref()
|
||||
.and_then(|t| t.scroll_wheel_tick_detect_max_ms),
|
||||
tui_scroll_wheel_like_max_duration_ms: cfg
|
||||
.tui
|
||||
.as_ref()
|
||||
.and_then(|t| t.scroll_wheel_like_max_duration_ms),
|
||||
tui_scroll_invert: cfg.tui.as_ref().map(|t| t.scroll_invert).unwrap_or(false),
|
||||
tui_alternate_screen: cfg
|
||||
.tui
|
||||
.as_ref()
|
||||
@@ -1886,15 +1812,6 @@ persistence = "none"
|
||||
notifications: Notifications::Enabled(true),
|
||||
animations: true,
|
||||
show_tooltips: true,
|
||||
scroll_events_per_tick: None,
|
||||
scroll_wheel_lines: None,
|
||||
scroll_trackpad_lines: None,
|
||||
scroll_trackpad_accel_events: None,
|
||||
scroll_trackpad_accel_max: None,
|
||||
scroll_mode: ScrollInputMode::Auto,
|
||||
scroll_wheel_tick_detect_max_ms: None,
|
||||
scroll_wheel_like_max_duration_ms: None,
|
||||
scroll_invert: false,
|
||||
alternate_screen: AltScreenMode::Auto,
|
||||
}
|
||||
);
|
||||
@@ -3782,15 +3699,6 @@ model_verbosity = "high"
|
||||
show_tooltips: true,
|
||||
analytics_enabled: Some(true),
|
||||
feedback_enabled: true,
|
||||
tui_scroll_events_per_tick: None,
|
||||
tui_scroll_wheel_lines: None,
|
||||
tui_scroll_trackpad_lines: None,
|
||||
tui_scroll_trackpad_accel_events: None,
|
||||
tui_scroll_trackpad_accel_max: None,
|
||||
tui_scroll_mode: ScrollInputMode::Auto,
|
||||
tui_scroll_wheel_tick_detect_max_ms: None,
|
||||
tui_scroll_wheel_like_max_duration_ms: None,
|
||||
tui_scroll_invert: false,
|
||||
tui_alternate_screen: AltScreenMode::Auto,
|
||||
otel: OtelConfig::default(),
|
||||
},
|
||||
@@ -3871,15 +3779,6 @@ model_verbosity = "high"
|
||||
show_tooltips: true,
|
||||
analytics_enabled: Some(true),
|
||||
feedback_enabled: true,
|
||||
tui_scroll_events_per_tick: None,
|
||||
tui_scroll_wheel_lines: None,
|
||||
tui_scroll_trackpad_lines: None,
|
||||
tui_scroll_trackpad_accel_events: None,
|
||||
tui_scroll_trackpad_accel_max: None,
|
||||
tui_scroll_mode: ScrollInputMode::Auto,
|
||||
tui_scroll_wheel_tick_detect_max_ms: None,
|
||||
tui_scroll_wheel_like_max_duration_ms: None,
|
||||
tui_scroll_invert: false,
|
||||
tui_alternate_screen: AltScreenMode::Auto,
|
||||
otel: OtelConfig::default(),
|
||||
};
|
||||
@@ -3975,15 +3874,6 @@ model_verbosity = "high"
|
||||
show_tooltips: true,
|
||||
analytics_enabled: Some(false),
|
||||
feedback_enabled: true,
|
||||
tui_scroll_events_per_tick: None,
|
||||
tui_scroll_wheel_lines: None,
|
||||
tui_scroll_trackpad_lines: None,
|
||||
tui_scroll_trackpad_accel_events: None,
|
||||
tui_scroll_trackpad_accel_max: None,
|
||||
tui_scroll_mode: ScrollInputMode::Auto,
|
||||
tui_scroll_wheel_tick_detect_max_ms: None,
|
||||
tui_scroll_wheel_like_max_duration_ms: None,
|
||||
tui_scroll_invert: false,
|
||||
tui_alternate_screen: AltScreenMode::Auto,
|
||||
otel: OtelConfig::default(),
|
||||
};
|
||||
@@ -4065,15 +3955,6 @@ model_verbosity = "high"
|
||||
show_tooltips: true,
|
||||
analytics_enabled: Some(true),
|
||||
feedback_enabled: true,
|
||||
tui_scroll_events_per_tick: None,
|
||||
tui_scroll_wheel_lines: None,
|
||||
tui_scroll_trackpad_lines: None,
|
||||
tui_scroll_trackpad_accel_events: None,
|
||||
tui_scroll_trackpad_accel_max: None,
|
||||
tui_scroll_mode: ScrollInputMode::Auto,
|
||||
tui_scroll_wheel_tick_detect_max_ms: None,
|
||||
tui_scroll_wheel_like_max_duration_ms: None,
|
||||
tui_scroll_invert: false,
|
||||
tui_alternate_screen: AltScreenMode::Auto,
|
||||
otel: OtelConfig::default(),
|
||||
};
|
||||
|
||||
@@ -418,23 +418,6 @@ impl Default for Notifications {
|
||||
}
|
||||
}
|
||||
|
||||
/// How TUI2 should interpret mouse scroll events.
|
||||
///
|
||||
/// Terminals generally encode both mouse wheels and trackpads as the same "scroll up/down" mouse
|
||||
/// button events, without a magnitude. This setting controls whether Codex uses a heuristic to
|
||||
/// infer wheel vs trackpad per stream, or forces a specific behavior.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ScrollInputMode {
|
||||
/// Infer wheel vs trackpad behavior per scroll stream.
|
||||
#[default]
|
||||
Auto,
|
||||
/// Always treat scroll events as mouse-wheel input (fixed lines per tick).
|
||||
Wheel,
|
||||
/// Always treat scroll events as trackpad input (fractional accumulation).
|
||||
Trackpad,
|
||||
}
|
||||
|
||||
/// Collection of settings that are specific to the TUI.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema)]
|
||||
#[schemars(deny_unknown_fields)]
|
||||
@@ -454,109 +437,6 @@ pub struct Tui {
|
||||
#[serde(default = "default_true")]
|
||||
pub show_tooltips: bool,
|
||||
|
||||
/// Override the *wheel* event density used to normalize TUI2 scrolling.
|
||||
///
|
||||
/// Terminals generally deliver both mouse wheels and trackpads as discrete `scroll up/down`
|
||||
/// mouse events with direction but no magnitude. Unfortunately, the *number* of raw events
|
||||
/// per physical wheel notch varies by terminal (commonly 1, 3, or 9+). TUI2 uses this value
|
||||
/// to normalize that raw event density into consistent "wheel tick" behavior.
|
||||
///
|
||||
/// Wheel math (conceptually):
|
||||
///
|
||||
/// - A single event contributes `1 / scroll_events_per_tick` tick-equivalents.
|
||||
/// - Wheel-like streams then scale that by `scroll_wheel_lines` so one physical notch scrolls
|
||||
/// a fixed number of lines.
|
||||
///
|
||||
/// Trackpad math is intentionally *not* fully tied to this value: in trackpad-like mode, TUI2
|
||||
/// uses `min(scroll_events_per_tick, 3)` as the divisor so terminals with dense wheel ticks
|
||||
/// (e.g. 9 events per notch) do not make trackpads feel artificially slow.
|
||||
///
|
||||
/// Defaults are derived per terminal from [`crate::terminal::TerminalInfo`] when TUI2 starts.
|
||||
/// See `codex-rs/tui2/docs/scroll_input_model.md` for the probe data and rationale.
|
||||
pub scroll_events_per_tick: Option<u16>,
|
||||
|
||||
/// Override how many transcript lines one physical *wheel notch* should scroll in TUI2.
|
||||
///
|
||||
/// This is the "classic feel" knob. Defaults to 3.
|
||||
///
|
||||
/// Wheel-like per-event contribution is `scroll_wheel_lines / scroll_events_per_tick`. For
|
||||
/// example, in a terminal that emits 9 events per notch, the default `3 / 9` yields 1/3 of a
|
||||
/// line per event and totals 3 lines once the full notch burst arrives.
|
||||
///
|
||||
/// See `codex-rs/tui2/docs/scroll_input_model.md` for details on the stream model and the
|
||||
/// wheel/trackpad heuristic.
|
||||
pub scroll_wheel_lines: Option<u16>,
|
||||
|
||||
/// Override baseline trackpad scroll sensitivity in TUI2.
|
||||
///
|
||||
/// Trackpads do not have discrete notches, but terminals still emit discrete `scroll up/down`
|
||||
/// events. In trackpad-like mode, TUI2 accumulates fractional scroll and only applies whole
|
||||
/// lines to the viewport.
|
||||
///
|
||||
/// Trackpad per-event contribution is:
|
||||
///
|
||||
/// - `scroll_trackpad_lines / min(scroll_events_per_tick, 3)`
|
||||
///
|
||||
/// (plus optional bounded acceleration; see `scroll_trackpad_accel_*`). The `min(..., 3)`
|
||||
/// divisor is deliberate: `scroll_events_per_tick` is calibrated from *wheel* behavior and
|
||||
/// can be much larger than trackpad event density, which would otherwise make trackpads feel
|
||||
/// too slow in dense-wheel terminals.
|
||||
///
|
||||
/// Defaults to 1, meaning one tick-equivalent maps to one transcript line.
|
||||
pub scroll_trackpad_lines: Option<u16>,
|
||||
|
||||
/// Trackpad acceleration: approximate number of events required to gain +1x speed in TUI2.
|
||||
///
|
||||
/// This keeps small swipes precise while allowing large/faster swipes to cover more content.
|
||||
/// Defaults are chosen to address terminals where trackpad event density is comparatively low.
|
||||
///
|
||||
/// Concretely, TUI2 computes an acceleration multiplier for trackpad-like streams:
|
||||
///
|
||||
/// - `multiplier = clamp(1 + abs(events) / scroll_trackpad_accel_events, 1..scroll_trackpad_accel_max)`
|
||||
///
|
||||
/// The multiplier is applied to the stream’s computed line delta (including any carried
|
||||
/// fractional remainder).
|
||||
pub scroll_trackpad_accel_events: Option<u16>,
|
||||
|
||||
/// Trackpad acceleration: maximum multiplier applied to trackpad-like streams.
|
||||
///
|
||||
/// Set to 1 to effectively disable trackpad acceleration.
|
||||
///
|
||||
/// See [`Tui::scroll_trackpad_accel_events`] for the exact multiplier formula.
|
||||
pub scroll_trackpad_accel_max: Option<u16>,
|
||||
|
||||
/// Select how TUI2 interprets mouse scroll input.
|
||||
///
|
||||
/// - `auto` (default): infer wheel vs trackpad per scroll stream.
|
||||
/// - `wheel`: always use wheel behavior (fixed lines per wheel notch).
|
||||
/// - `trackpad`: always use trackpad behavior (fractional accumulation; wheel may feel slow).
|
||||
#[serde(default)]
|
||||
pub scroll_mode: ScrollInputMode,
|
||||
|
||||
/// Auto-mode threshold: maximum time (ms) for the first tick-worth of events to arrive.
|
||||
///
|
||||
/// In `scroll_mode = "auto"`, TUI2 starts a stream as trackpad-like (to avoid overshoot) and
|
||||
/// promotes it to wheel-like if `scroll_events_per_tick` events arrive "quickly enough". This
|
||||
/// threshold controls what "quickly enough" means.
|
||||
///
|
||||
/// Most users should leave this unset; it is primarily for terminals that emit wheel ticks
|
||||
/// batched over longer time spans.
|
||||
pub scroll_wheel_tick_detect_max_ms: Option<u64>,
|
||||
|
||||
/// Auto-mode fallback: maximum duration (ms) that a very small stream is still treated as wheel-like.
|
||||
///
|
||||
/// This is only used when `scroll_events_per_tick` is effectively 1 (one event per wheel
|
||||
/// notch). In that case, we cannot observe a "tick completion time", so TUI2 treats a
|
||||
/// short-lived, small stream (<= 2 events) as wheel-like to preserve classic wheel behavior.
|
||||
pub scroll_wheel_like_max_duration_ms: Option<u64>,
|
||||
|
||||
/// Invert mouse scroll direction in TUI2.
|
||||
///
|
||||
/// This flips the scroll sign after terminal detection. It is applied consistently to both
|
||||
/// wheel and trackpad input.
|
||||
#[serde(default)]
|
||||
pub scroll_invert: bool,
|
||||
|
||||
/// Controls whether the TUI uses the terminal's alternate screen buffer.
|
||||
///
|
||||
/// - `auto` (default): Disable alternate screen in Zellij, enable elsewhere.
|
||||
|
||||
@@ -95,8 +95,6 @@ pub enum Feature {
|
||||
ShellSnapshot,
|
||||
/// Append additional AGENTS.md guidance to user instructions.
|
||||
ChildAgentsMd,
|
||||
/// Experimental TUI v2 (viewport) implementation.
|
||||
Tui2,
|
||||
/// Enforce UTF8 output in Powershell.
|
||||
PowershellUtf8,
|
||||
/// Compress request bodies (zstd) when sending streaming requests to codex-backend.
|
||||
@@ -441,12 +439,6 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
},
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::Tui2,
|
||||
key: "tui2",
|
||||
stage: Stage::Beta,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::Steer,
|
||||
key: "steer",
|
||||
|
||||
@@ -6,8 +6,7 @@ When changing the paste-burst or chat-composer state machines in this folder, ke
|
||||
readable, top-down explanation of the current behavior.
|
||||
- Update the narrative doc `docs/tui-chat-composer.md` whenever behavior/assumptions change (Enter
|
||||
handling, retro-capture, flush/clear rules, `disable_paste_burst`, non-ASCII/IME handling).
|
||||
- Keep `codex-rs/tui` and `codex-rs/tui2` implementations/docstrings aligned unless the divergence
|
||||
is intentional and documented.
|
||||
- Keep implementations/docstrings aligned unless a divergence is intentional and documented.
|
||||
|
||||
Practical check:
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
load("//:defs.bzl", "codex_rust_crate")
|
||||
|
||||
codex_rust_crate(
|
||||
name = "tui2",
|
||||
crate_name = "codex_tui2",
|
||||
compile_data = glob(
|
||||
include = ["**"],
|
||||
exclude = [
|
||||
"**/* *",
|
||||
"BUILD.bazel",
|
||||
"Cargo.toml",
|
||||
],
|
||||
allow_empty = True,
|
||||
),
|
||||
test_data_extra = glob(["src/**/snapshots/**"]),
|
||||
integration_compile_data_extra = ["src/test_backend.rs"],
|
||||
extra_binaries = [
|
||||
"//codex-rs/cli:codex",
|
||||
],
|
||||
)
|
||||
@@ -1,123 +0,0 @@
|
||||
[package]
|
||||
name = "codex-tui2"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "codex-tui2"
|
||||
path = "src/main.rs"
|
||||
|
||||
[lib]
|
||||
name = "codex_tui2"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
# Enable vt100-based tests (emulator) when running with `--features vt100-tests`.
|
||||
vt100-tests = []
|
||||
# Gate verbose debug logging inside the TUI implementation.
|
||||
debug-logs = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
async-stream = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
codex-ansi-escape = { workspace = true }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-arg0 = { workspace = true }
|
||||
codex-backend-client = { workspace = true }
|
||||
codex-common = { workspace = true, features = [
|
||||
"cli",
|
||||
"elapsed",
|
||||
"sandbox_summary",
|
||||
] }
|
||||
codex-core = { workspace = true }
|
||||
codex-feedback = { workspace = true }
|
||||
codex-file-search = { workspace = true }
|
||||
codex-login = { workspace = true }
|
||||
codex-otel = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
codex-utils-absolute-path = { workspace = true }
|
||||
codex-tui = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
crossterm = { workspace = true, features = ["bracketed-paste", "event-stream"] }
|
||||
derive_more = { workspace = true, features = ["is_variant"] }
|
||||
diffy = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
image = { workspace = true, features = ["jpeg", "png"] }
|
||||
itertools = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
mcp-types = { workspace = true }
|
||||
pathdiff = { workspace = true }
|
||||
pulldown-cmark = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
ratatui = { workspace = true, features = [
|
||||
"scrolling-regions",
|
||||
"unstable-backend-writer",
|
||||
"unstable-rendered-line-info",
|
||||
"unstable-widget-ref",
|
||||
] }
|
||||
ratatui-core = { workspace = true }
|
||||
ratatui-macros = { workspace = true }
|
||||
regex-lite = { workspace = true }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||
shlex = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
supports-color = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
textwrap = { workspace = true }
|
||||
tui-scrollbar = { workspace = true }
|
||||
tokio = { workspace = true, features = [
|
||||
"io-std",
|
||||
"macros",
|
||||
"process",
|
||||
"rt-multi-thread",
|
||||
"signal",
|
||||
"test-util",
|
||||
"time",
|
||||
] }
|
||||
tokio-stream = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
tracing = { workspace = true, features = ["log"] }
|
||||
tracing-appender = { workspace = true }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
tree-sitter-bash = { workspace = true }
|
||||
tree-sitter-highlight = { workspace = true }
|
||||
unicode-segmentation = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
codex-windows-sandbox = { workspace = true }
|
||||
tokio-util = { workspace = true, features = ["time"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = { workspace = true }
|
||||
|
||||
# Clipboard support via `arboard` is not available on Android/Termux.
|
||||
# Only include it for non-Android targets so the crate builds on Android.
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
arboard = { workspace = true }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = { workspace = true }
|
||||
codex-cli = { workspace = true }
|
||||
codex-core = { workspace = true, features = ["test-support"] }
|
||||
codex-utils-cargo-bin = { workspace = true }
|
||||
codex-utils-pty = { workspace = true }
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
insta = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
serial_test = { workspace = true }
|
||||
vt100 = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
@@ -1,610 +0,0 @@
|
||||
# TUI2 Scroll Input: Model and Implementation
|
||||
|
||||
This is the single "scrolling doc of record" for TUI2.
|
||||
|
||||
It describes what we implemented, why it works, and what we tried before this approach.
|
||||
It also preserves the scroll-probe findings (see Appendix) that motivated the model.
|
||||
|
||||
Code reference: `codex-rs/tui2/src/tui/scrolling/mouse.rs`.
|
||||
|
||||
## Goals and constraints
|
||||
|
||||
Goals:
|
||||
|
||||
- Mouse wheel: scroll about **3 transcript lines per physical wheel tick** regardless of terminal
|
||||
event density (classic feel).
|
||||
- Trackpad: remain **higher fidelity**, meaning small movements can accumulate fractionally and
|
||||
should not be forced into wheel behavior.
|
||||
- Work across terminals where a single wheel tick may produce 1, 3, 9, or more raw events.
|
||||
|
||||
Constraints:
|
||||
|
||||
- Terminals typically encode both wheels and trackpads as the same "scroll up/down" mouse button
|
||||
events without a magnitude. We cannot reliably observe device type directly.
|
||||
- Timing alone is not a reliable discriminator (wheel and trackpad bursts overlap).
|
||||
|
||||
## Current implementation (stream-based; data-driven)
|
||||
|
||||
TUI2 uses a stream model: scroll events are grouped into short streams separated by silence.
|
||||
Within a stream, we normalize by a per-terminal "events per tick" factor and then apply either
|
||||
wheel-like (fixed lines per tick) or trackpad-like (fractional) semantics.
|
||||
|
||||
### 1. Stream detection
|
||||
|
||||
- A stream begins on the first scroll event.
|
||||
- A stream ends when the gap since the last event exceeds `STREAM_GAP_MS` or when direction flips.
|
||||
- Direction flips always close the current stream and start a new one, so we never blend "up" and
|
||||
"down" into a single accumulator.
|
||||
|
||||
This makes behavior stable across:
|
||||
|
||||
- Dense bursts (Warp/Ghostty-style sub-ms intervals).
|
||||
- Sparse bursts (single events separated by tens or hundreds of ms).
|
||||
- Mixed wheel + trackpad input where direction changes quickly.
|
||||
|
||||
### 2. Normalization: events-per-tick
|
||||
|
||||
Different terminals emit different numbers of raw events per physical wheel notch.
|
||||
We normalize by converting raw events into tick-equivalents:
|
||||
|
||||
`tick_equivalents = raw_events / events_per_tick`
|
||||
|
||||
Per-terminal defaults come from the probe logs (Appendix), and users can override them.
|
||||
|
||||
Config key: `tui.scroll_events_per_tick`.
|
||||
|
||||
### 3. Wheel vs trackpad behavior (and why it is heuristic)
|
||||
|
||||
Because device type is not directly observable, the implementation provides a mode setting:
|
||||
|
||||
- `tui.scroll_mode = "auto"` (default): infer wheel-like vs trackpad-like behavior per stream.
|
||||
- `tui.scroll_mode = "wheel"`: always treat streams as wheel-like.
|
||||
- `tui.scroll_mode = "trackpad"`: always treat streams as trackpad-like.
|
||||
|
||||
In auto mode:
|
||||
|
||||
- Streams start trackpad-like (safer: avoids overshoot when we guess wrong).
|
||||
- Streams promote to wheel-like when the first tick-worth of events arrives quickly.
|
||||
- For 1-event-per-tick terminals, "first tick completion time" is not observable, so there is a
|
||||
conservative end-of-stream fallback for very small bursts.
|
||||
|
||||
This design assumes that auto classification is a best-effort heuristic and must be overridable.
|
||||
|
||||
### 4. Applying scroll: wheel-like streams
|
||||
|
||||
Wheel-like streams target the "classic feel" requirement.
|
||||
|
||||
- Each raw event contributes `tui.scroll_wheel_lines / events_per_tick` lines.
|
||||
- Deltas flush immediately (not cadence-gated) so wheels feel snappy even on dense streams.
|
||||
- Wheel-like streams apply a minimum +/- 1 line when events were received but rounding would yield 0.
|
||||
|
||||
Defaults:
|
||||
|
||||
- `tui.scroll_wheel_lines = 3`
|
||||
|
||||
### 5. Applying scroll: trackpad-like streams
|
||||
|
||||
Trackpad-like streams are designed for fidelity first.
|
||||
|
||||
- Each raw event contributes `tui.scroll_trackpad_lines / trackpad_events_per_tick` lines.
|
||||
- Fractional remainder is carried across streams, so tiny gestures accumulate instead of being lost.
|
||||
- Trackpad deltas are cadence-gated to ~60 Hz (`REDRAW_CADENCE_MS`) to avoid redraw floods and to
|
||||
reduce "stop lag" / overshoot.
|
||||
- Trackpad streams intentionally do not apply a minimum +/- 1 line at stream end; if a gesture is
|
||||
small enough to round to 0, it should feel like "no movement", not a forced jump.
|
||||
|
||||
Dense wheel terminals (e.g. Ghostty/Warp) can emit trackpad streams with high event density.
|
||||
Using a wheel-derived `events_per_tick = 9` for trackpad would make trackpads feel slow, so we use
|
||||
a capped divisor for trackpad normalization:
|
||||
|
||||
- `trackpad_events_per_tick = min(events_per_tick, 3)`
|
||||
|
||||
Additionally, to keep small gestures precise while making large/fast swipes cover more content,
|
||||
trackpad-like streams apply bounded acceleration based on event count:
|
||||
|
||||
- `tui.scroll_trackpad_accel_events`: how many events correspond to +1x multiplier.
|
||||
- `tui.scroll_trackpad_accel_max`: maximum multiplier.
|
||||
|
||||
### 6. Guard rails and axis handling
|
||||
|
||||
- Horizontal scroll events are ignored for vertical scrolling.
|
||||
- Streams clamp event counts and accumulated line deltas to avoid floods.
|
||||
|
||||
## Terminal defaults and per-terminal tuning
|
||||
|
||||
Defaults are keyed by `TerminalName` (terminal family), not exact version.
|
||||
Probe data is version-specific, so defaults should be revalidated as more logs arrive.
|
||||
|
||||
Events-per-tick defaults derived from `wheel_single` medians:
|
||||
|
||||
- AppleTerminal: 3
|
||||
- WarpTerminal: 9
|
||||
- WezTerm: 1
|
||||
- Alacritty: 3
|
||||
- Ghostty: 3
|
||||
- Iterm2: 1
|
||||
- VsCode: 1
|
||||
- Kitty: 3
|
||||
- Unknown: 3
|
||||
|
||||
Note: probe logs measured Ghostty at ~9 events per tick, but we default to 3 because an upstream
|
||||
Ghostty change is expected to reduce wheel event density. Users can override with
|
||||
`tui.scroll_events_per_tick`.
|
||||
|
||||
Auto-mode wheel promotion thresholds can also be tuned per terminal if needed (see config below).
|
||||
|
||||
## Configuration knobs (TUI2)
|
||||
|
||||
These are user-facing knobs in `config.toml` under `[tui]`:
|
||||
|
||||
In this repo, "tick" always refers to a physical mouse wheel notch. Trackpads do not have ticks, so
|
||||
trackpad settings are expressed in terms of "tick-equivalents" (raw events normalized to a common
|
||||
scale).
|
||||
|
||||
The core normalization formulas are:
|
||||
|
||||
- Wheel-like streams:
|
||||
- `lines_per_event = scroll_wheel_lines / scroll_events_per_tick`
|
||||
- Trackpad-like streams:
|
||||
- `lines_per_event = scroll_trackpad_lines / min(scroll_events_per_tick, 3)`
|
||||
- (plus bounded acceleration from `scroll_trackpad_accel_*` and fractional carry across streams)
|
||||
|
||||
Keys:
|
||||
|
||||
- `scroll_events_per_tick` (number):
|
||||
- Raw vertical scroll events per physical wheel notch in your terminal (normalization input).
|
||||
- Affects wheel-like scroll speed and auto-mode wheel promotion timing.
|
||||
- Trackpad-like mode uses `min(..., 3)` as the divisor so dense wheel ticks (e.g. 9 events per
|
||||
notch) do not make trackpads feel artificially slow.
|
||||
- `scroll_wheel_lines` (number):
|
||||
- Lines per physical wheel notch (default 3).
|
||||
- Change this if you want "classic" wheel scrolling to be more/less aggressive globally.
|
||||
- `scroll_trackpad_lines` (number):
|
||||
- Baseline trackpad sensitivity in trackpad-like mode (default 1).
|
||||
- Change this if your trackpad feels consistently too slow/fast for small motions.
|
||||
- `scroll_trackpad_accel_events` (number):
|
||||
- Trackpad acceleration tuning (default 30). Smaller values accelerate earlier.
|
||||
- Trackpad-like streams compute a multiplier:
|
||||
- `multiplier = clamp(1 + abs(events) / scroll_trackpad_accel_events, 1..scroll_trackpad_accel_max)`
|
||||
- The multiplier is applied to the trackpad stream’s computed line delta (including any carried
|
||||
fractional remainder).
|
||||
- `scroll_trackpad_accel_max` (number):
|
||||
- Trackpad acceleration cap (default 3). Set to 1 to effectively disable acceleration.
|
||||
- `scroll_mode` (`auto` | `wheel` | `trackpad`):
|
||||
- `auto` (default): infer wheel-like vs trackpad-like per stream.
|
||||
- `wheel`: always wheel-like (good for wheel-only setups; trackpads will feel jumpy).
|
||||
- `trackpad`: always trackpad-like (good if auto misclassifies; wheels may feel slow).
|
||||
- `scroll_wheel_tick_detect_max_ms` (number):
|
||||
- Auto-mode promotion threshold: how quickly the first tick-worth of events must arrive to
|
||||
consider the stream wheel-like.
|
||||
- If wheel feels slow in a dense-wheel terminal, increasing this is usually better than changing
|
||||
`scroll_events_per_tick`.
|
||||
- `scroll_wheel_like_max_duration_ms` (number):
|
||||
- Auto-mode fallback for 1-event-per-tick terminals (WezTerm/iTerm/VS Code).
|
||||
- If wheel feels like trackpad (too slow) in those terminals, increasing this can help.
|
||||
- `scroll_invert` (bool):
|
||||
- Invert direction after terminal detection; applies consistently to wheel and trackpad.
|
||||
|
||||
## Previous approaches tried (and why they were replaced)
|
||||
|
||||
1. Cadence-based inference (rolling inter-event thresholds)
|
||||
|
||||
- Approach: infer wheel vs trackpad using inter-event timing thresholds (burst vs frame cadence vs slow),
|
||||
with terminal-specific tuning.
|
||||
- Problem: terminals differ more in event density and batching than in timing; timing overlaps heavily
|
||||
between wheel and trackpad. Small threshold changes had outsized, terminal-specific effects.
|
||||
|
||||
2. Pure event-count or pure duration classification
|
||||
|
||||
- Approach: classify wheel-like vs trackpad-like by event count <= N or duration <= M.
|
||||
- Problem: burst length overlaps heavily across devices/terminals; duration is more separable but still
|
||||
not strong enough to be authoritative.
|
||||
|
||||
3. Why streams + normalization won
|
||||
|
||||
- Streams give a stable unit ("what did the user do in one gesture?") that we can bound and reason about.
|
||||
- Normalization directly addresses the main cross-terminal source of variation: raw event density.
|
||||
- Classification remains heuristic, but is isolated and configurable.
|
||||
|
||||
## Appendix A: Follow-up analysis (latest log per terminal; 2025-12-20)
|
||||
|
||||
This section is derived from a "latest log per terminal" subset analysis. The exact event count is
|
||||
not significant; it is included only as a note about which subset was used.
|
||||
|
||||
Key takeaways:
|
||||
|
||||
- Burst length overlaps heavily between wheel and trackpad. Simple "event count <= N" classifiers perform poorly.
|
||||
- Burst span (duration) is more separable: wheel bursts typically complete in < ~180-200 ms, while trackpad
|
||||
bursts are often hundreds of milliseconds.
|
||||
- Conclusion: explicit wheel vs trackpad classification is inherently weak from these events; prefer a
|
||||
stream model, plus a small heuristic and a config override (`tui.scroll_mode`) for edge cases.
|
||||
|
||||
Data notes (latest per terminal label):
|
||||
|
||||
- Logs used (one per terminal, by filename timestamp):
|
||||
- mouse_scroll_log_Apple_Terminal_2025-12-19T19-53-54Z.jsonl
|
||||
- mouse_scroll_log_WarpTerminal_2025-12-19T19-59-38Z.jsonl
|
||||
- mouse_scroll_log_WezTerm_2025-12-19T20-00-36Z.jsonl
|
||||
- mouse_scroll_log_alacritty_2025-12-19T19-56-45Z.jsonl
|
||||
- mouse_scroll_log_ghostty_2025-12-19T19-52-44Z.jsonl
|
||||
- mouse_scroll_log_iTerm_app_2025-12-19T19-55-08Z.jsonl
|
||||
- mouse_scroll_log_vscode_2025-12-19T19-51-20Z.jsonl
|
||||
- mouse_scroll_log_xterm-kitty_2025-12-19T19-58-19Z.jsonl
|
||||
|
||||
Per-terminal burst separability (wheel vs trackpad), summarized as median and p90:
|
||||
|
||||
- Apple Terminal:
|
||||
- Wheel: length median 9.5 (p90 49), span median 94 ms (p90 136)
|
||||
- Trackpad: length median 13.5 (p90 104), span median 238 ms (p90 616)
|
||||
- Warp:
|
||||
- Wheel: length median 43 (p90 169), span median 88 ms (p90 178)
|
||||
- Trackpad: length median 60 (p90 82), span median 358 ms (p90 721)
|
||||
- WezTerm:
|
||||
- Wheel: length median 4 (p90 10), span median 91 ms (p90 156)
|
||||
- Trackpad: length median 10.5 (p90 36), span median 270 ms (p90 348)
|
||||
- alacritty:
|
||||
- Wheel: length median 14 (p90 63), span median 109 ms (p90 158)
|
||||
- Trackpad: length median 12.5 (p90 63), span median 372 ms (p90 883)
|
||||
- ghostty:
|
||||
- Wheel: length median 32.5 (p90 163), span median 99 ms (p90 157)
|
||||
- Trackpad: length median 14.5 (p90 60), span median 366 ms (p90 719)
|
||||
- iTerm:
|
||||
- Wheel: length median 4 (p90 9), span median 91 ms (p90 230)
|
||||
- Trackpad: length median 9 (p90 36), span median 223 ms (p90 540)
|
||||
- VS Code:
|
||||
- Wheel: length median 3 (p90 9), span median 94 ms (p90 120)
|
||||
- Trackpad: length median 3 (p90 12), span median 192 ms (p90 468)
|
||||
- Kitty:
|
||||
- Wheel: length median 15.5 (p90 59), span median 87 ms (p90 233)
|
||||
- Trackpad: length median 15.5 (p90 68), span median 292 ms (p90 563)
|
||||
|
||||
Wheel_single medians (events per tick) in the latest logs:
|
||||
|
||||
- Apple: 3
|
||||
- Warp: 9
|
||||
- WezTerm: 1
|
||||
- alacritty: 3
|
||||
- ghostty: 9 (measured); TUI2 defaults use 3 because an upstream Ghostty change is expected to
|
||||
reduce wheel event density. If your Ghostty build still emits ~9 events per wheel tick, set
|
||||
`tui.scroll_events_per_tick = 9`.
|
||||
- iTerm: 1
|
||||
- VS Code: 1
|
||||
- Kitty: 3
|
||||
|
||||
## Appendix B: Scroll probe findings (authoritative; preserved verbatim)
|
||||
|
||||
The remainder of this document is preserved from the original scroll-probe spec.
|
||||
It is intentionally not rewritten so the data and rationale remain auditable.
|
||||
|
||||
Note: the original text uses "events per line" terminology; the implementation treats this as an
|
||||
events-per-wheel-tick normalization factor (see "Normalization: events-per-tick").
|
||||
|
||||
Note: the pseudocode in the preserved spec is not the exact current implementation; it is kept as
|
||||
historical context for how the probe data originally mapped into an algorithm. The current
|
||||
implementation is described in the sections above.
|
||||
|
||||
## 1. TL;DR
|
||||
|
||||
Analysis of 16 scroll-probe logs (13,734 events) across 8 terminals shows large per-terminal variation in how many raw events are emitted per physical wheel tick (1-9+ events). Timing alone does not distinguish wheel vs trackpad; event counts and burst duration are more reliable. The algorithm below treats scroll input as short streams separated by gaps, normalizes events into line deltas using a per-terminal events-per-line factor, coalesces redraws at 60 Hz, and applies a minimum 1-line delta for discrete bursts. This yields stable behavior across dense streams, sparse bursts, and terminals that emit horizontal events.
|
||||
|
||||
## 2. Data overview
|
||||
|
||||
- Logs analyzed: 16
|
||||
- Total events: 13,734
|
||||
- Terminals covered:
|
||||
- Apple_Terminal 455.1
|
||||
- WarpTerminal v0.2025.12.17.17.stable_02
|
||||
- WezTerm 20240203-110809-5046fc22
|
||||
- alacritty
|
||||
- ghostty 1.2.3
|
||||
- iTerm.app 3.6.6
|
||||
- vscode 1.107.1
|
||||
- xterm-kitty
|
||||
- Scenarios captured: `wheel_single`, `wheel_small`, `wheel_long`, `trackpad_single`, `trackpad_slow`, `trackpad_fast` (directional up/down variants treated as distinct bursts).
|
||||
- Legacy `wheel_scroll_*` logs are mapped to `wheel_small` in analysis.
|
||||
|
||||
## 3. Cross-terminal comparison table
|
||||
|
||||
| Terminal | Scenario | Median Dt (ms) | P95 Dt (ms) | Typical burst | Notes |
|
||||
| --------------------------------------- | --------------- | -------------: | ----------: | ------------: | ----------- |
|
||||
| Apple_Terminal 455.1 | wheel_single | 0.14 | 97.68 | 3 |
|
||||
| Apple_Terminal 455.1 | wheel_small | 0.12 | 23.81 | 19 |
|
||||
| Apple_Terminal 455.1 | wheel_long | 0.03 | 15.93 | 48 |
|
||||
| Apple_Terminal 455.1 | trackpad_single | 92.35 | 213.15 | 2 |
|
||||
| Apple_Terminal 455.1 | trackpad_slow | 11.30 | 75.46 | 14 |
|
||||
| Apple_Terminal 455.1 | trackpad_fast | 0.13 | 8.92 | 96 |
|
||||
| WarpTerminal v0.2025.12.17.17.stable_02 | wheel_single | 0.07 | 0.34 | 9 |
|
||||
| WarpTerminal v0.2025.12.17.17.stable_02 | wheel_small | 0.05 | 5.04 | 65 |
|
||||
| WarpTerminal v0.2025.12.17.17.stable_02 | wheel_long | 0.01 | 0.42 | 166 |
|
||||
| WarpTerminal v0.2025.12.17.17.stable_02 | trackpad_single | 9.77 | 32.64 | 10 |
|
||||
| WarpTerminal v0.2025.12.17.17.stable_02 | trackpad_slow | 7.93 | 16.44 | 74 |
|
||||
| WarpTerminal v0.2025.12.17.17.stable_02 | trackpad_fast | 5.40 | 10.04 | 74 |
|
||||
| WezTerm 20240203-110809-5046fc22 | wheel_single | 416.07 | 719.64 | 1 |
|
||||
| WezTerm 20240203-110809-5046fc22 | wheel_small | 19.41 | 50.19 | 6 |
|
||||
| WezTerm 20240203-110809-5046fc22 | wheel_long | 13.19 | 29.96 | 10 |
|
||||
| WezTerm 20240203-110809-5046fc22 | trackpad_single | 237.56 | 237.56 | 1 |
|
||||
| WezTerm 20240203-110809-5046fc22 | trackpad_slow | 23.54 | 76.10 | 10 | 12.5% horiz |
|
||||
| WezTerm 20240203-110809-5046fc22 | trackpad_fast | 7.10 | 24.86 | 32 | 12.6% horiz |
|
||||
| alacritty | wheel_single | 0.09 | 0.33 | 3 |
|
||||
| alacritty | wheel_small | 0.11 | 37.24 | 24 |
|
||||
| alacritty | wheel_long | 0.01 | 15.96 | 56 |
|
||||
| alacritty | trackpad_single | n/a | n/a | 1 |
|
||||
| alacritty | trackpad_slow | 41.90 | 97.36 | 11 |
|
||||
| alacritty | trackpad_fast | 3.07 | 25.13 | 62 |
|
||||
| ghostty 1.2.3 | wheel_single | 0.05 | 0.20 | 9 |
|
||||
| ghostty 1.2.3 | wheel_small | 0.05 | 7.18 | 52 |
|
||||
| ghostty 1.2.3 | wheel_long | 0.02 | 1.16 | 146 |
|
||||
| ghostty 1.2.3 | trackpad_single | 61.28 | 124.28 | 3 | 23.5% horiz |
|
||||
| ghostty 1.2.3 | trackpad_slow | 23.10 | 76.30 | 14 | 34.7% horiz |
|
||||
| ghostty 1.2.3 | trackpad_fast | 3.84 | 37.72 | 47 | 23.4% horiz |
|
||||
| iTerm.app 3.6.6 | wheel_single | 74.96 | 80.61 | 1 |
|
||||
| iTerm.app 3.6.6 | wheel_small | 20.79 | 84.83 | 6 |
|
||||
| iTerm.app 3.6.6 | wheel_long | 16.70 | 50.91 | 9 |
|
||||
| iTerm.app 3.6.6 | trackpad_single | n/a | n/a | 1 |
|
||||
| iTerm.app 3.6.6 | trackpad_slow | 17.25 | 94.05 | 9 |
|
||||
| iTerm.app 3.6.6 | trackpad_fast | 7.12 | 24.54 | 33 |
|
||||
| vscode 1.107.1 | wheel_single | 58.01 | 58.01 | 1 |
|
||||
| vscode 1.107.1 | wheel_small | 16.76 | 66.79 | 5 |
|
||||
| vscode 1.107.1 | wheel_long | 9.86 | 32.12 | 8 |
|
||||
| vscode 1.107.1 | trackpad_single | n/a | n/a | 1 |
|
||||
| vscode 1.107.1 | trackpad_slow | 164.19 | 266.90 | 3 |
|
||||
| vscode 1.107.1 | trackpad_fast | 16.78 | 61.05 | 11 |
|
||||
| xterm-kitty | wheel_single | 0.16 | 51.74 | 3 |
|
||||
| xterm-kitty | wheel_small | 0.10 | 24.12 | 26 |
|
||||
| xterm-kitty | wheel_long | 0.01 | 16.10 | 56 |
|
||||
| xterm-kitty | trackpad_single | 155.65 | 289.87 | 1 | 12.5% horiz |
|
||||
| xterm-kitty | trackpad_slow | 16.89 | 67.04 | 16 | 30.4% horiz |
|
||||
| xterm-kitty | trackpad_fast | 0.23 | 16.37 | 78 | 20.6% horiz |
|
||||
|
||||
## 4. Key findings
|
||||
|
||||
- Raw wheel ticks vary by terminal: median events per tick are 1 (WezTerm/iTerm/vscode), 3 (Apple/alacritty/kitty), and 9 (Warp/ghostty).
|
||||
- Trackpad bursts are longer than wheel ticks but overlap in timing; inter-event timing alone does not distinguish device type.
|
||||
- Continuous streams have short gaps: overall inter-event p99 is 70.67 ms; trackpad_slow p95 is 66.98 ms.
|
||||
- Horizontal events appear only in trackpad scenarios and only in WezTerm/ghostty/kitty; ignore horizontal events for vertical scrolling.
|
||||
- Burst duration is a reliable discrete/continuous signal:
|
||||
- wheel_single median 0.15 ms (p95 80.61 ms)
|
||||
- trackpad_single median 0 ms (p95 237.56 ms)
|
||||
- wheel_small median 96.88 ms (p95 182.90 ms)
|
||||
- trackpad_slow median 320.69 ms (p95 812.10 ms)
|
||||
|
||||
## 5. Scrolling model (authoritative)
|
||||
|
||||
**Stream detection.** Treat scroll input as short streams separated by silence. A stream begins on the first scroll event and ends when the gap since the last event exceeds `STREAM_GAP_MS` or the direction flips. Direction flip immediately closes the current stream and starts a new one.
|
||||
|
||||
**Normalization.** Convert raw events into line deltas using a per-terminal `EVENTS_PER_LINE` factor derived from the terminal's median `wheel_single` burst length. If no terminal override matches, use the global default (`3`).
|
||||
|
||||
**Discrete vs continuous.** Classify the stream after it ends:
|
||||
|
||||
- If `event_count <= DISCRETE_MAX_EVENTS` **and** `duration_ms <= DISCRETE_MAX_DURATION_MS`, treat as discrete.
|
||||
- Otherwise treat as continuous.
|
||||
|
||||
**Discrete streams.** Apply the accumulated line delta immediately. If the stream's accumulated lines rounds to 0 but events were received, apply a minimum +/-1 line (respecting direction).
|
||||
|
||||
**Continuous streams.** Accumulate fractional lines and coalesce redraws to `REDRAW_CADENCE_MS`. Flush any remaining fractional lines on stream end (with the same +/-1 minimum if the stream had events but rounded to 0).
|
||||
|
||||
**Direction.** Always use the raw event direction. Provide a separate user-level invert option if needed; do not infer inversion from timing.
|
||||
|
||||
**Horizontal events.** Ignore horizontal events in vertical scroll logic.
|
||||
|
||||
## 6. Concrete constants (data-derived)
|
||||
|
||||
```text
|
||||
STREAM_GAP_MS = 80
|
||||
DISCRETE_MAX_EVENTS = 10
|
||||
DISCRETE_MAX_DURATION_MS = 250
|
||||
REDRAW_CADENCE_MS = 16
|
||||
DEFAULT_EVENTS_PER_LINE = 3
|
||||
MAX_EVENTS_PER_STREAM = 256
|
||||
MAX_ACCUMULATED_LINES = 256
|
||||
MIN_LINES_PER_DISCRETE_STREAM = 1
|
||||
DEFAULT_WHEEL_LINES_PER_TICK = 3
|
||||
```
|
||||
|
||||
Why these values:
|
||||
|
||||
- `STREAM_GAP_MS=80`: overall p99 inter-event gap is 70.67 ms; trackpad_slow p95 is 66.98 ms. 80 ms ends streams without splitting most continuous input.
|
||||
- `DISCRETE_MAX_EVENTS=10`: wheel_single p95 burst = 9; trackpad_single p95 burst = 10.
|
||||
- `DISCRETE_MAX_DURATION_MS=250`: trackpad_single p95 duration = 237.56 ms.
|
||||
- `REDRAW_CADENCE_MS=16`: coalesces dense streams to ~60 Hz; trackpad_fast p95 Dt = 19.83 ms.
|
||||
- `DEFAULT_EVENTS_PER_LINE=3`: global median wheel_single burst length.
|
||||
- `MAX_EVENTS_PER_STREAM=256` and `MAX_ACCUMULATED_LINES=256`: highest observed burst is 206; cap to avoid floods.
|
||||
- `DEFAULT_WHEEL_LINES_PER_TICK=3`: restores classic wheel speed; this is a UX choice rather than a data-derived constant.
|
||||
|
||||
## 7. Pseudocode (Rust-oriented)
|
||||
|
||||
```rust
|
||||
// This is intentionally a simplified sketch of the current implementation.
|
||||
// For the authoritative behavior, see `codex-rs/tui2/src/tui/scrolling/mouse.rs`.
|
||||
|
||||
enum StreamKind {
|
||||
Unknown,
|
||||
Wheel,
|
||||
Trackpad,
|
||||
}
|
||||
|
||||
struct Stream {
|
||||
start: Instant,
|
||||
last: Instant,
|
||||
dir: i32,
|
||||
event_count: usize,
|
||||
accumulated_events: i32,
|
||||
applied_lines: i32,
|
||||
kind: StreamKind,
|
||||
just_promoted: bool,
|
||||
}
|
||||
|
||||
struct State {
|
||||
stream: Option<Stream>,
|
||||
carry_lines: f32,
|
||||
last_redraw_at: Instant,
|
||||
cfg: Config,
|
||||
}
|
||||
|
||||
struct Config {
|
||||
events_per_tick: u16,
|
||||
wheel_lines_per_tick: u16,
|
||||
trackpad_lines_per_tick: u16,
|
||||
trackpad_accel_events: u16,
|
||||
trackpad_accel_max: u16,
|
||||
wheel_tick_detect_max: Duration,
|
||||
}
|
||||
|
||||
fn on_scroll_event(dir: i32, now: Instant, st: &mut State) -> i32 {
|
||||
// Close stream on idle gap or direction flip.
|
||||
if let Some(stream) = st.stream.as_ref() {
|
||||
let gap = now.duration_since(stream.last);
|
||||
if gap > STREAM_GAP || stream.dir != dir {
|
||||
finalize_stream(now, st);
|
||||
st.stream = None;
|
||||
}
|
||||
}
|
||||
|
||||
let stream = st.stream.get_or_insert_with(|| Stream {
|
||||
start: now,
|
||||
last: now,
|
||||
dir,
|
||||
event_count: 0,
|
||||
accumulated_events: 0,
|
||||
applied_lines: 0,
|
||||
kind: StreamKind::Unknown,
|
||||
just_promoted: false,
|
||||
});
|
||||
|
||||
stream.last = now;
|
||||
stream.dir = dir;
|
||||
stream.event_count = (stream.event_count + 1).min(MAX_EVENTS_PER_STREAM);
|
||||
stream.accumulated_events =
|
||||
(stream.accumulated_events + dir).clamp(-(MAX_EVENTS_PER_STREAM as i32), MAX_EVENTS_PER_STREAM as i32);
|
||||
|
||||
// Auto-mode promotion: promote to wheel-like when the first tick-worth of events arrives quickly.
|
||||
if matches!(stream.kind, StreamKind::Unknown) {
|
||||
let ept = st.cfg.events_per_tick.max(1) as usize;
|
||||
if ept >= 2 && stream.event_count >= ept && now.duration_since(stream.start) <= st.cfg.wheel_tick_detect_max {
|
||||
stream.kind = StreamKind::Wheel;
|
||||
stream.just_promoted = true;
|
||||
}
|
||||
}
|
||||
|
||||
flush_lines(now, st)
|
||||
}
|
||||
|
||||
fn on_tick(now: Instant, st: &mut State) -> i32 {
|
||||
if let Some(stream) = st.stream.as_ref() {
|
||||
let gap = now.duration_since(stream.last);
|
||||
if gap > STREAM_GAP {
|
||||
return finalize_stream(now, st);
|
||||
}
|
||||
}
|
||||
flush_lines(now, st)
|
||||
}
|
||||
|
||||
fn finalize_stream(now: Instant, st: &mut State) -> i32 {
|
||||
// In auto mode, any stream that isn't wheel-like by promotion stays trackpad-like.
|
||||
if let Some(stream) = st.stream.as_mut() {
|
||||
if matches!(stream.kind, StreamKind::Unknown) {
|
||||
stream.kind = StreamKind::Trackpad;
|
||||
}
|
||||
}
|
||||
|
||||
let lines = flush_lines(now, st);
|
||||
|
||||
// Carry fractional remainder across streams for trackpad-like input.
|
||||
if let Some(stream) = st.stream.as_ref() {
|
||||
if matches!(stream.kind, StreamKind::Trackpad) {
|
||||
st.carry_lines = desired_lines_f32(st, stream) - stream.applied_lines as f32;
|
||||
} else {
|
||||
st.carry_lines = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
lines
|
||||
}
|
||||
|
||||
fn flush_lines(now: Instant, st: &mut State) -> i32 {
|
||||
let Some(stream) = st.stream.as_mut() else { return 0; };
|
||||
|
||||
let wheel_like = matches!(stream.kind, StreamKind::Wheel);
|
||||
let cadence_elapsed = now.duration_since(st.last_redraw_at) >= REDRAW_CADENCE;
|
||||
let should_flush = wheel_like || cadence_elapsed || stream.just_promoted;
|
||||
if !should_flush {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let desired_total = desired_lines_f32(st, stream);
|
||||
let mut desired_lines = desired_total.trunc() as i32;
|
||||
|
||||
// Wheel guardrail: ensure we never produce a "dead tick" for non-zero input.
|
||||
if wheel_like && desired_lines == 0 && stream.accumulated_events != 0 {
|
||||
desired_lines = stream.accumulated_events.signum() * MIN_LINES_PER_DISCRETE_STREAM;
|
||||
}
|
||||
|
||||
let mut delta = desired_lines - stream.applied_lines;
|
||||
if delta == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
delta = delta.clamp(-MAX_ACCUMULATED_LINES, MAX_ACCUMULATED_LINES);
|
||||
stream.applied_lines += delta;
|
||||
stream.just_promoted = false;
|
||||
st.last_redraw_at = now;
|
||||
delta
|
||||
}
|
||||
|
||||
fn desired_lines_f32(st: &State, stream: &Stream) -> f32 {
|
||||
let wheel_like = matches!(stream.kind, StreamKind::Wheel);
|
||||
|
||||
let events_per_tick = if wheel_like {
|
||||
st.cfg.events_per_tick.max(1) as f32
|
||||
} else {
|
||||
// Trackpad divisor is capped so dense wheel terminals don't feel slow for trackpads.
|
||||
st.cfg.events_per_tick.clamp(1, DEFAULT_EVENTS_PER_LINE).max(1) as f32
|
||||
};
|
||||
|
||||
let lines_per_tick = if wheel_like {
|
||||
st.cfg.wheel_lines_per_tick.max(1) as f32
|
||||
} else {
|
||||
st.cfg.trackpad_lines_per_tick.max(1) as f32
|
||||
};
|
||||
|
||||
let mut total = (stream.accumulated_events as f32 * (lines_per_tick / events_per_tick))
|
||||
.clamp(-(MAX_ACCUMULATED_LINES as f32), MAX_ACCUMULATED_LINES as f32);
|
||||
|
||||
if !wheel_like {
|
||||
total = (total + st.carry_lines).clamp(-(MAX_ACCUMULATED_LINES as f32), MAX_ACCUMULATED_LINES as f32);
|
||||
|
||||
// Bounded acceleration for large swipes (keep small swipes precise).
|
||||
let event_count = stream.accumulated_events.abs() as f32;
|
||||
let accel = (1.0 + (event_count / st.cfg.trackpad_accel_events.max(1) as f32))
|
||||
.clamp(1.0, st.cfg.trackpad_accel_max.max(1) as f32);
|
||||
total = (total * accel).clamp(-(MAX_ACCUMULATED_LINES as f32), MAX_ACCUMULATED_LINES as f32);
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
```
|
||||
|
||||
## 8. Terminal-specific adjustments (minimal)
|
||||
|
||||
Use per-terminal `EVENTS_PER_LINE` overrides derived from median `wheel_single` bursts:
|
||||
|
||||
```text
|
||||
Apple_Terminal 455.1 = 3
|
||||
WarpTerminal v0.2025.12.17.17.stable_02 = 9
|
||||
WezTerm 20240203-110809-5046fc22 = 1
|
||||
alacritty = 3
|
||||
ghostty 1.2.3 = 9
|
||||
iTerm.app 3.6.6 = 1
|
||||
vscode 1.107.1 = 1
|
||||
xterm-kitty = 3
|
||||
```
|
||||
|
||||
If terminal is not matched, use `DEFAULT_EVENTS_PER_LINE = 3`.
|
||||
|
||||
## 9. Known weird cases and guardrails
|
||||
|
||||
- Extremely dense streams (sub-ms Dt) occur in Warp/ghostty/kitty; redraw coalescing is mandatory.
|
||||
- Sparse bursts (hundreds of ms between events) occur in trackpad_single; do not merge them into long streams.
|
||||
- Horizontal scroll events (12-35% of trackpad events in some terminals) must be ignored for vertical scrolling.
|
||||
- Direction inversion is user-configurable in terminals; always use event direction and expose an application-level invert setting.
|
||||
- Guard against floods: cap event counts and accumulated line deltas per stream.
|
||||
@@ -1,169 +0,0 @@
|
||||
# Streaming Wrapping Reflow (tui2)
|
||||
|
||||
This document describes a correctness bug in `codex-rs/tui2` and the chosen fix:
|
||||
while streaming assistant markdown, soft-wrap decisions were effectively persisted as hard line
|
||||
breaks, so resizing the viewport could not reflow prose.
|
||||
|
||||
## Goal
|
||||
|
||||
- Resizing the viewport reflows transcript prose (including streaming assistant output).
|
||||
- Width-derived breaks are always treated as *soft wraps* (not logical newlines).
|
||||
- Copy/paste continues to treat soft wraps as joinable (via joiners), and hard breaks as newlines.
|
||||
|
||||
Non-goals:
|
||||
|
||||
- Reflowing terminal scrollback that has already been printed.
|
||||
- Reflowing content that is intentionally treated as preformatted (e.g., code blocks, raw stdout).
|
||||
|
||||
## Background: where reflow happens in tui2
|
||||
|
||||
TUI2 renders the transcript as a list of `HistoryCell`s:
|
||||
|
||||
1. A cell stores width-agnostic content (string, diff, logical lines, etc.).
|
||||
2. At draw time (and on resize), `transcript_render` asks each cell for lines at the *current*
|
||||
width (ideally via `HistoryCell::transcript_lines_with_joiners(width)`).
|
||||
3. `TranscriptViewCache` caches the wrapped visual lines keyed by width; a width change triggers a
|
||||
rebuild.
|
||||
|
||||
This only works if cells do *not* persist width-derived wrapping inside their stored state.
|
||||
|
||||
## The bug: soft wraps became hard breaks during streaming
|
||||
|
||||
Ratatui represents multi-line content as `Vec<Line>`. If we split a paragraph into multiple `Line`s
|
||||
because the viewport is narrow, that split is indistinguishable from an explicit newline unless we
|
||||
also carry metadata describing which breaks were “soft”.
|
||||
|
||||
Streaming assistant output used to generate already-wrapped `Line`s and store them inside the
|
||||
history cell. Later, when the viewport became wider, the transcript renderer could not “un-split”
|
||||
those baked lines — they looked like hard breaks.
|
||||
|
||||
## Chosen solution (A, F1): stream logical markdown lines; wrap in the cell at render-time
|
||||
|
||||
User choice recap:
|
||||
|
||||
- **A**: Keep append-only streaming (new history cell per commit tick), but make the streamed data
|
||||
width-agnostic.
|
||||
- **F1**: Make the agent message cell responsible for wrapping-to-width so transcript-level wrapping
|
||||
can be a no-op for it.
|
||||
|
||||
### Key idea: separate markdown parsing from wrapping
|
||||
|
||||
We introduce a width-agnostic “logical markdown line” representation that preserves the metadata
|
||||
needed to wrap correctly later:
|
||||
|
||||
- `codex-rs/tui2/src/markdown_render.rs`
|
||||
- `MarkdownLogicalLine { content, initial_indent, subsequent_indent, line_style, is_preformatted }`
|
||||
- `render_markdown_logical_lines(input: &str) -> Vec<MarkdownLogicalLine>`
|
||||
|
||||
This keeps:
|
||||
|
||||
- hard breaks (paragraph/list boundaries, explicit newlines),
|
||||
- markdown indentation rules for wraps (list markers, nested lists, blockquotes),
|
||||
- preformatted runs (code blocks) stable.
|
||||
|
||||
### Updated streaming pipeline
|
||||
|
||||
- `codex-rs/tui2/src/markdown_stream.rs`
|
||||
- `MarkdownStreamCollector` is newline-gated (no change), but now commits
|
||||
`Vec<MarkdownLogicalLine>` instead of already-wrapped `Vec<Line>`.
|
||||
- Width is removed from the collector; wrapping is not performed during streaming.
|
||||
|
||||
- `codex-rs/tui2/src/streaming/controller.rs`
|
||||
- Emits `AgentMessageCell::new_logical(...)` containing logical lines.
|
||||
|
||||
- `codex-rs/tui2/src/history_cell.rs`
|
||||
- `AgentMessageCell` stores `Vec<MarkdownLogicalLine>`.
|
||||
- `HistoryCell::transcript_lines_with_joiners(width)` wraps each logical line at the current
|
||||
width using `word_wrap_line_with_joiners` and composes indents as:
|
||||
- transcript gutter prefix (`• ` / ` `), plus
|
||||
- markdown-provided initial/subsequent indents.
|
||||
- Preformatted logical lines are rendered without wrapping.
|
||||
|
||||
Result: on resize, the transcript cache rebuilds against the new width and the agent output reflows
|
||||
correctly because the stored content contains no baked soft wraps.
|
||||
|
||||
## Overlay deferral fix (D): defer cells, not rendered lines
|
||||
|
||||
When an overlay (transcript/static) is active, TUI2 is in alt screen and the normal terminal buffer
|
||||
is not visible. Historically, `tui2` attempted to queue “history to print” for the normal buffer by
|
||||
deferring *rendered lines*, which baked the then-current width.
|
||||
|
||||
User choice recap:
|
||||
|
||||
- **D**: Store deferred *cells* and render them at overlay close time.
|
||||
|
||||
Implementation:
|
||||
|
||||
- `codex-rs/tui2/src/app.rs`
|
||||
- `deferred_history_cells: Vec<Arc<dyn HistoryCell>>` (replaces `deferred_history_lines`).
|
||||
- `AppEvent::InsertHistoryCell` pushes cells into the deferral list when `overlay.is_some()`.
|
||||
|
||||
- `codex-rs/tui2/src/app_backtrack.rs`
|
||||
- `close_transcript_overlay` renders deferred cells at the *current* width when closing the
|
||||
overlay, then queues the resulting lines for the normal terminal buffer.
|
||||
|
||||
Note: as of today, `Tui::insert_history_lines` queues lines but `Tui::draw` does not flush them into
|
||||
the terminal (see `codex-rs/tui2/src/tui.rs`). This section is therefore best read as “behavior we
|
||||
want when/if scrollback printing is re-enabled”, not a guarantee that content is printed during the
|
||||
main TUI loop. For the current intended behavior around printing, see
|
||||
`codex-rs/tui2/docs/tui_viewport_and_history.md`.
|
||||
|
||||
## Tests (G2)
|
||||
|
||||
User choice recap:
|
||||
|
||||
- **G2**: Add resize reflow tests + snapshot coverage.
|
||||
|
||||
Added coverage:
|
||||
|
||||
- `codex-rs/tui2/src/history_cell.rs`
|
||||
- `agent_message_cell_reflows_streamed_prose_on_resize`
|
||||
- `agent_message_cell_reflows_streamed_prose_vt100_snapshot`
|
||||
|
||||
These assert that a streamed agent cell produces fewer visual lines at wider widths and provide
|
||||
snapshots showing reflow for list items and blockquotes.
|
||||
|
||||
## Audit: other `HistoryCell`s and width-baked paths
|
||||
|
||||
This section answers “what else might behave like this?” up front.
|
||||
|
||||
### History cells
|
||||
|
||||
- `AgentMessageCell` (`codex-rs/tui2/src/history_cell.rs`): **was affected**; now stores logical
|
||||
markdown lines and wraps at render time.
|
||||
- `UserHistoryCell` (`codex-rs/tui2/src/history_cell.rs`): wraps at render time from stored `String`
|
||||
using `word_wrap_lines_with_joiners` (reflowable).
|
||||
- `ReasoningSummaryCell` (`codex-rs/tui2/src/history_cell.rs`): renders from stored `String` on each
|
||||
call; it does call `append_markdown(..., Some(width))`, but that wrapping is recomputed per width
|
||||
(reflowable).
|
||||
- `PrefixedWrappedHistoryCell` (`codex-rs/tui2/src/history_cell.rs`): wraps at render time and
|
||||
returns joiners (reflowable).
|
||||
- `PlainHistoryCell` (`codex-rs/tui2/src/history_cell.rs`): stores `Vec<Line>` and returns it
|
||||
unchanged (not reflowable by design; used for already-structured/preformatted output).
|
||||
|
||||
Rule of thumb: any cell that stores already-wrapped `Vec<Line>` for prose is a candidate for the
|
||||
same bug; cells that store source text or logical lines and compute wrapping inside
|
||||
`display_lines(width)` are safe.
|
||||
|
||||
### Width-baked output outside the transcript model
|
||||
|
||||
Even with the streaming fix, some paths are inherently width-baked:
|
||||
|
||||
- Printed transcript after exit (`codex-rs/tui2/src/app.rs`): `AppExitInfo.session_lines` is rendered
|
||||
once using the final width and then printed; it cannot reflow afterward.
|
||||
- Optional scrollback insertion helper (`codex-rs/tui2/src/insert_history.rs`): once ANSI is written
|
||||
to the terminal, that output cannot be reflowed later. This helper is currently used for
|
||||
deterministic ANSI emission (`write_spans`) and tests; it is not wired into the main TUI draw
|
||||
loop.
|
||||
- Static overlays (`codex-rs/tui2/src/pager_overlay.rs`): reflow depends on whether callers provided
|
||||
width-agnostic input; pre-split `Vec<Line>` cannot be “un-split” within the overlay.
|
||||
|
||||
## Deferred / follow-ups
|
||||
|
||||
The fix above is sufficient to unblock correct reflow on resize. Remaining choices can be deferred:
|
||||
|
||||
- Streaming granularity: one logical line can wrap into multiple visual lines, so “commit tick”
|
||||
updates can appear in larger chunks than before. If this becomes a UX issue, we can add a render-
|
||||
time “progressive reveal” layer without reintroducing width baking.
|
||||
- Expand logical-line rendering to other markdown-ish cells if needed (e.g., unify `append_markdown`
|
||||
usage), but only if we find a concrete reflow bug beyond `AgentMessageCell`.
|
||||
@@ -1,564 +0,0 @@
|
||||
# TUI2 Viewport, Transcript, and History – Design Notes
|
||||
|
||||
This document describes the viewport and history model we are implementing in the new
|
||||
`codex-rs/tui2` crate. It builds on lessons from the legacy TUI and explains why we moved away
|
||||
from directly writing history into terminal scrollback.
|
||||
|
||||
The target audience is Codex developers and curious contributors who want to understand or
|
||||
critique how TUI2 owns its viewport, scrollback, and suspend behavior.
|
||||
|
||||
Unless stated otherwise, references to “the TUI” in this document mean the TUI2 implementation;
|
||||
when we mean the legacy TUI specifically, we call it out explicitly.
|
||||
|
||||
---
|
||||
|
||||
## 1. Problem Overview
|
||||
|
||||
Historically, the legacy TUI tried to “cooperate” with the terminal’s own scrollback:
|
||||
|
||||
- The inline viewport sat somewhere above the bottom of the screen.
|
||||
- When new history arrived, we tried to insert it directly into the terminal scrollback above the
|
||||
viewport.
|
||||
- On certain transitions (e.g. switching sessions, overlays), we cleared and re‑wrote portions of
|
||||
the screen from scratch.
|
||||
|
||||
This had several failure modes:
|
||||
|
||||
- **Terminal‑dependent behavior.**
|
||||
|
||||
- Different terminals handle scroll regions, clears, and resize semantics differently.
|
||||
- What looked correct in one terminal could drop or duplicate content in another.
|
||||
|
||||
- **Resizes and layout churn.**
|
||||
|
||||
- The TUI reacts to resizes, focus changes, and overlay transitions.
|
||||
- When the viewport moved or its size changed, our attempts to keep scrollback “aligned” with the
|
||||
in‑memory history could go out of sync.
|
||||
- In practice this meant:
|
||||
- Some lines were lost or overwritten.
|
||||
- Others were duplicated or appeared in unexpected places.
|
||||
|
||||
- **“Clear and rewrite everything” didn’t save us.**
|
||||
- We briefly tried a strategy of clearing large regions (or the full screen) and re‑rendering
|
||||
history when the layout changed.
|
||||
- This ran into two issues:
|
||||
- Terminals treat full clears differently. For example, Terminal.app often leaves the cleared
|
||||
screen as a “page” at the top of scrollback, some terminals interpret only a subset of the
|
||||
ANSI clear/scrollback codes, and others (like iTerm2) gate “clear full scrollback” behind
|
||||
explicit user consent.
|
||||
- Replaying a long session is expensive and still subject to timing/race conditions with user
|
||||
output (e.g. shell prompts) when we weren’t in alt screen.
|
||||
|
||||
The net result: the legacy TUI could not reliably guarantee “the history you see on screen is complete, in
|
||||
order, and appears exactly once” across terminals, resizes, suspend/resume, and overlay transitions.
|
||||
|
||||
---
|
||||
|
||||
## 2. Goals
|
||||
|
||||
The redesign is guided by a few explicit goals:
|
||||
|
||||
1. **Codex, not the terminal, owns the viewport.**
|
||||
|
||||
- The in‑memory transcript (a list of history entries) is the single source of truth for what’s
|
||||
on screen.
|
||||
- The TUI decides how to map that transcript into the current viewport; scrollback becomes an
|
||||
output target, not an extra data structure we try to maintain.
|
||||
|
||||
2. **History must be correct, ordered, and never silently dropped.**
|
||||
|
||||
- Every logical history cell should either:
|
||||
- Be visible in the TUI, or
|
||||
- Have been printed into scrollback as part of a suspend/exit flow.
|
||||
- We would rather (rarely) duplicate content than risk losing it.
|
||||
|
||||
3. **Avoid unnecessary duplication.**
|
||||
|
||||
- When emitting history to scrollback (on suspend or exit), print each logical cell’s content at
|
||||
most once.
|
||||
- Streaming cells are allowed to be “re‑seen” as they grow, but finished cells should not keep
|
||||
reappearing.
|
||||
|
||||
4. **Behave sensibly under resizes.**
|
||||
|
||||
- TUI rendering should reflow to the current width on every frame.
|
||||
- History printed to scrollback may have been wrapped at different widths over time; that is
|
||||
acceptable, but it must not cause missing content or unbounded duplication.
|
||||
|
||||
5. **Suspend/alt‑screen interaction is predictable.**
|
||||
- `Ctrl+Z` should:
|
||||
- Cleanly exit alt screen, if active.
|
||||
- Print a consistent transcript prefix into normal scrollback.
|
||||
- Resume with the TUI fully redrawn, without stale artifacts.
|
||||
|
||||
---
|
||||
|
||||
## 3. New Viewport & Transcript Model
|
||||
|
||||
### 3.1 Transcript as a logical sequence of cells
|
||||
|
||||
At a high level, the TUI transcript is a list of “cells”, each representing one logical thing in
|
||||
the conversation:
|
||||
|
||||
- A user prompt (with padding and a distinct background).
|
||||
- An agent response (which may arrive in multiple streaming chunks).
|
||||
- System or info rows (session headers, migration banners, reasoning summaries, etc.).
|
||||
|
||||
Each cell knows how to draw itself for a given width: how many lines it needs, what prefixes to
|
||||
use, how to style its content. The transcript itself is purely logical:
|
||||
|
||||
- It has no scrollback coordinates or terminal state baked into it.
|
||||
- It can be re‑rendered for any viewport width.
|
||||
|
||||
The TUI’s job is to take this logical sequence and decide how much of it fits into the current
|
||||
viewport, and how it should be wrapped and styled on screen.
|
||||
|
||||
### 3.2 Building viewport lines from the transcript
|
||||
|
||||
To render the main transcript area above the composer, the TUI:
|
||||
|
||||
1. Defines a “transcript region” as the full frame minus the height of the bottom input area.
|
||||
2. Flattens all cells into a list of visual lines, remembering for each visual line which cell it
|
||||
came from and which line within that cell it corresponds to.
|
||||
3. Uses this flattened list plus a scroll position to decide which visual line should appear at the
|
||||
top of the region.
|
||||
4. Clears the transcript region and draws the visible slice of lines into it.
|
||||
5. For user messages, paints the entire row background (including padding lines) so the user block
|
||||
stands out even when it does not fill the whole width.
|
||||
6. Applies selection styling and other overlays on top of the rendered lines.
|
||||
|
||||
Scrolling (mouse wheel, PgUp/PgDn, Home/End) operates entirely in terms of these flattened lines
|
||||
and the current scroll anchor. The terminal’s own scrollback is not part of this calculation; it
|
||||
only ever sees fully rendered frames.
|
||||
|
||||
### 3.3 Alternate screen, overlays, and redraw guarantees
|
||||
|
||||
The TUI uses the terminal’s alternate screen for:
|
||||
|
||||
- The main interactive chat session (so the viewport can cover the full terminal).
|
||||
- Full‑screen overlays such as the transcript pager, diff view, model migration screen, and
|
||||
onboarding.
|
||||
|
||||
Conceptually:
|
||||
|
||||
- Entering alt screen:
|
||||
|
||||
- Switches the terminal into alt screen and expands the viewport to cover the full terminal.
|
||||
- Clears that alt‑screen buffer.
|
||||
|
||||
- Leaving alt screen:
|
||||
|
||||
- Disables “alternate scroll” so mouse wheel events behave predictably.
|
||||
- Returns to the normal screen.
|
||||
|
||||
- On leaving overlays and on resuming from suspend, the TUI viewport is explicitly cleared and fully
|
||||
redrawn:
|
||||
- This prevents stale overlay content or shell output from lingering in the TUI area.
|
||||
- The next frame reconstructs the UI entirely from the in‑memory transcript and other state, not
|
||||
from whatever the terminal happened to remember.
|
||||
|
||||
Alt screen is therefore treated as a temporary render target. The only authoritative copy of the UI
|
||||
is the in‑memory state.
|
||||
|
||||
---
|
||||
|
||||
## 4. Mouse, Selection, and Scrolling
|
||||
|
||||
Mouse interaction is a first‑class part of the new design:
|
||||
|
||||
- **Scrolling.**
|
||||
|
||||
- Mouse wheel scrolls the transcript in fixed line increments.
|
||||
- Keyboard shortcuts (PgUp/PgDn/Home/End) use the same scroll model, so the footer can show
|
||||
consistent hints regardless of input device.
|
||||
|
||||
- **Selection.**
|
||||
|
||||
- A click‑and‑drag gesture defines a linear text selection in terms of the flattened transcript
|
||||
lines (not raw buffer coordinates).
|
||||
- Selection tracks the _content_ rather than a fixed screen row. When the transcript scrolls, the
|
||||
selection moves along with the underlying lines instead of staying glued to a particular Y
|
||||
position.
|
||||
- The selection only covers the “transcript text” area; it intentionally skips the left gutter
|
||||
that we use for bullets/prefixes.
|
||||
|
||||
- **Copy.**
|
||||
- When the user triggers copy, the TUI reconstructs the wrapped transcript lines using the same
|
||||
flattening/wrapping rules as the visible view.
|
||||
- It then reconstructs a high‑fidelity clipboard string from the selected logical lines:
|
||||
- Preserves meaningful indentation (especially for code blocks).
|
||||
- Treats soft-wrapped prose as a single logical line by joining wrap continuations instead of
|
||||
inserting hard newlines.
|
||||
- Emits Markdown source markers (e.g. backticks and fences) for copy/paste, even if the UI
|
||||
chooses to render those constructs without showing the literal markers.
|
||||
- Copy operates on the full selection range, even if the selection extends outside the current
|
||||
viewport.
|
||||
- The resulting text is sent to the system clipboard and a status footer indicates success or
|
||||
failure.
|
||||
|
||||
Because scrolling, selection, and copy all operate on the same flattened transcript representation,
|
||||
they remain consistent even as the viewport resizes or the chat composer grows/shrinks. Owning our
|
||||
own scrolling also means we must own mouse interactions end‑to‑end: if we left scrolling entirely
|
||||
to the terminal, we could not reliably line up selections with transcript content or avoid
|
||||
accidentally copying gutter/margin characters instead of just the conversation text.
|
||||
|
||||
Scroll normalization details and the data behind it live in
|
||||
`codex-rs/tui2/docs/scroll_input_model.md`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Printing History to Scrollback
|
||||
|
||||
We still want the final session (and suspend points) to appear in the user’s normal scrollback, but
|
||||
we no longer try to maintain scrollback in lock‑step with the TUI frame. Instead, we treat
|
||||
scrollback as an **append‑only log** of logical transcript cells.
|
||||
|
||||
In practice this means:
|
||||
|
||||
- The TUI may print history both when you suspend (`Ctrl+Z`) and when you exit.
|
||||
- Some users may prefer to only print on exit (for example to keep scrollback quieter during long
|
||||
sessions). The current design anticipates gating suspend‑time printing behind a config toggle so
|
||||
that this behavior can be made opt‑in or opt‑out without touching the core viewport logic, but
|
||||
that switch has not been implemented yet.
|
||||
|
||||
### 5.1 Cell‑based high‑water mark
|
||||
|
||||
Internally, the TUI keeps a simple “high‑water mark” for history printing:
|
||||
|
||||
- Think of this as “how many cells at the front of the transcript have already been sent to
|
||||
scrollback.”
|
||||
- It is just a counter over the logical transcript, not over wrapped lines.
|
||||
- It moves forward only when we have actually printed more history.
|
||||
|
||||
This means we never try to guess “how many terminal lines have already been printed”; we only
|
||||
remember that “the first N logical entries are done.”
|
||||
|
||||
### 5.2 Rendering new cells for scrollback
|
||||
|
||||
When we need to print history (on suspend or exit), we:
|
||||
|
||||
1. Take the suffix of the transcript that lies beyond the high‑water mark.
|
||||
2. Render just that suffix into styled lines at the **current** terminal width.
|
||||
3. Write those lines to stdout.
|
||||
4. Advance the high‑water mark to include all cells we just printed.
|
||||
|
||||
Older cells are never re‑rendered for scrollback; they remain in whatever wrapping they had when
|
||||
they were first printed. This avoids the line‑count–based bugs we had before while still allowing
|
||||
the on‑screen TUI to reflow freely.
|
||||
|
||||
### 5.3 Suspend (`Ctrl+Z`) flow
|
||||
|
||||
On suspend (typically `Ctrl+Z` on Unix):
|
||||
|
||||
- Before yielding control back to the shell, the TUI:
|
||||
- Leaves alt screen if it is active and restores normal terminal modes.
|
||||
- Determines which transcript cells have not yet been printed and renders them for the current
|
||||
width.
|
||||
- Prints those new lines once into normal scrollback.
|
||||
- Marks those cells as printed in the high‑water mark.
|
||||
- Finally, sends the process to the background.
|
||||
|
||||
On `fg`, the process resumes, re‑enters TUI modes, and redraws the viewport from the in‑memory
|
||||
transcript. The history printed during suspend stays in scrollback and is not touched again.
|
||||
|
||||
### 5.4 Exit flow
|
||||
|
||||
When the TUI exits, we follow the same principle:
|
||||
|
||||
- We compute the suffix of the transcript that has not yet been printed (taking into account any
|
||||
prior suspends).
|
||||
- We render just that suffix to styled lines at the current width.
|
||||
- The outer `main` function leaves alt screen, restores the terminal, and prints those lines, plus a
|
||||
blank line and token usage summary.
|
||||
|
||||
If you never suspended, exit prints the entire transcript once. If you did suspend one or more
|
||||
times, exit prints only the cells appended after the last suspend. In both cases, each logical
|
||||
conversation entry reaches scrollback exactly once.
|
||||
|
||||
---
|
||||
|
||||
## 6. Streaming, Width Changes, and Tradeoffs
|
||||
|
||||
### 6.1 Streaming cells
|
||||
|
||||
Streaming agent responses are represented as a sequence of history entries:
|
||||
|
||||
- The first chunk produces a “first line” entry for the message.
|
||||
- Subsequent chunks produce continuation entries that extend that message.
|
||||
|
||||
From the history/scrollback perspective:
|
||||
|
||||
- Each streaming chunk is just another entry in the logical transcript.
|
||||
- The high‑water mark is a simple count of how many entries at the _front_ of the transcript have
|
||||
already been printed.
|
||||
- As new streaming chunks arrive, they are appended as new entries and will be included the next
|
||||
time we print history on suspend or exit.
|
||||
|
||||
We do **not** attempt to reprint or retroactively merge older chunks. In scrollback you will see the
|
||||
streaming response as a series of discrete blocks, matching the internal history structure.
|
||||
|
||||
Today, streaming rendering still “bakes in” some width at the time chunks are committed: line breaks
|
||||
for the streaming path are computed using the width that was active at the time, and stored in the
|
||||
intermediate representation. This is a known limitation and is called out in more detail in
|
||||
`codex-rs/tui2/docs/streaming_wrapping_design.md`; a follow‑up change will make streaming behavior
|
||||
match the rest of the transcript more closely (wrap only at display time, not at commit time).
|
||||
|
||||
### 6.2 Width changes over time
|
||||
|
||||
Because we now use a **cell‑level** high‑water mark instead of a visual line‑count, width changes
|
||||
are handled gracefully:
|
||||
|
||||
- On every suspend/exit, we render the not‑yet‑printed suffix of the transcript at the **current**
|
||||
width and append those lines.
|
||||
- Previously printed entries remain in scrollback with whatever wrapping they had at the time they
|
||||
were printed.
|
||||
- We no longer rely on “N lines printed before, therefore skip N lines of the newly wrapped
|
||||
transcript,” which was the source of dropped and duplicated content when widths changed.
|
||||
|
||||
This does mean scrollback can contain older cells wrapped for narrower or wider widths than the
|
||||
final terminal size, but:
|
||||
|
||||
- Each logical cell’s content appears exactly once.
|
||||
- New cells are append‑only and never overwrite or implicitly “shrink” earlier content.
|
||||
- The on‑screen TUI always reflows to the current width independently of scrollback.
|
||||
|
||||
If we later choose to also re‑emit the “currently streaming” cell when printing on suspend (to make
|
||||
sure the latest chunk of a long answer is always visible in scrollback), that would intentionally
|
||||
duplicate a small number of lines at the boundary of that cell. The design assumes any such behavior
|
||||
would be controlled by configuration (for example, by disabling suspend‑time printing entirely for
|
||||
users who prefer only exit‑time output).
|
||||
|
||||
### 6.3 Why not reflow scrollback?
|
||||
|
||||
In theory we could try to reflow already‑printed content when widths change by:
|
||||
|
||||
- Recomputing the entire transcript at the new width, and
|
||||
- Printing diffs that “rewrite” old regions in scrollback.
|
||||
|
||||
In practice, this runs into the same issues that motivated the redesign:
|
||||
|
||||
- Terminals treat full clears and scroll regions differently.
|
||||
- There is no portable way to “rewrite” arbitrary portions of scrollback above the visible buffer.
|
||||
- Interleaving user output (e.g. shell prompts after suspend) makes it impossible to reliably
|
||||
reconstruct the original scrollback structure.
|
||||
|
||||
We therefore deliberately accept that scrollback is **append‑only** and not subject to reflow;
|
||||
correctness is measured in terms of logical transcript content, not pixel‑perfect layout.
|
||||
|
||||
---
|
||||
|
||||
## 7. Backtrack and Overlays (Context)
|
||||
|
||||
While this document is focused on viewport and history, it’s worth mentioning a few related
|
||||
behaviors that rely on the same model.
|
||||
|
||||
### 7.1 Transcript overlay and backtrack
|
||||
|
||||
The transcript overlay (pager) is a full‑screen view of the same logical transcript:
|
||||
|
||||
- When opened, it takes a snapshot of the current transcript and renders it in an alt‑screen
|
||||
overlay.
|
||||
- Backtrack mode (`Esc` sequences) walks backwards through user messages in that snapshot and
|
||||
highlights the candidate “edit from here” point.
|
||||
- Confirming a backtrack request forks the conversation on the server and trims the in‑memory
|
||||
transcript so that only history up to the chosen user message remains, then re‑renders that prefix
|
||||
in the main view.
|
||||
|
||||
The overlay is purely a different _view_ of the same transcript; it never infers anything from
|
||||
scrollback.
|
||||
|
||||
---
|
||||
|
||||
## 8. Summary of Tradeoffs
|
||||
|
||||
**What we gain:**
|
||||
|
||||
- The TUI has a clear, single source of truth for history (the in‑memory transcript).
|
||||
- Viewport rendering is deterministic and independent of scrollback.
|
||||
- Suspend and exit flows:
|
||||
- Print each logical history cell exactly once.
|
||||
- Are robust to terminal width changes.
|
||||
- Interact cleanly with alt screen and raw‑mode toggling.
|
||||
- Streaming, overlays, selection, and backtrack all share the same logical history model.
|
||||
- Because cells are always re‑rendered live from the transcript, per‑cell interactions can become
|
||||
richer over time. Instead of treating the transcript as “dead text”, we can make individual
|
||||
entries interactive after they are rendered: expanding or contracting tool calls, diffs, or
|
||||
reasoning summaries in place, jum…truncated… \*\*\*
|
||||
|
||||
---
|
||||
|
||||
## 9. TUI2 Implementation Notes
|
||||
|
||||
This section maps the design above onto the `codex-rs/tui2` crate so future viewport work has
|
||||
concrete code pointers.
|
||||
|
||||
### 9.1 Transcript state and layout
|
||||
|
||||
The main app struct (`codex-rs/tui2/src/app.rs`) tracks the transcript and viewport state with:
|
||||
|
||||
- `transcript_cells: Vec<Arc<dyn HistoryCell>>` – the logical history.
|
||||
- `transcript_scroll: TranscriptScroll` – whether the viewport is pinned to the bottom or
|
||||
anchored at a specific cell/line pair.
|
||||
- `transcript_selection: TranscriptSelection` – a selection expressed in content-relative
|
||||
coordinates over the flattened, wrapped transcript (line index + column).
|
||||
- `transcript_view_top` / `transcript_total_lines` – the current viewport’s top line index and
|
||||
total number of wrapped lines for the inline transcript area.
|
||||
|
||||
### 9.2 Rendering, wrapping, and selection
|
||||
|
||||
`App::render_transcript_cells` defines the transcript region, builds flattened lines via
|
||||
`App::build_transcript_lines`, wraps them with `word_wrap_lines_borrowed` from
|
||||
`codex-rs/tui2/src/wrapping.rs`, and applies selection via `apply_transcript_selection` before
|
||||
writing to the frame buffer.
|
||||
|
||||
Streaming wrapping details live in `codex-rs/tui2/docs/streaming_wrapping_design.md`.
|
||||
|
||||
### 9.3 Input, selection, and footer state
|
||||
|
||||
Mouse handling lives in `App::handle_mouse_event`, keyboard scrolling in
|
||||
`App::handle_key_event`, selection rendering in `App::apply_transcript_selection`, and copy in
|
||||
`App::copy_transcript_selection` plus `codex-rs/tui2/src/transcript_selection.rs` and
|
||||
`codex-rs/tui2/src/clipboard_copy.rs`. Scroll/selection UI state is forwarded through
|
||||
`ChatWidget::set_transcript_ui_state`,
|
||||
`BottomPane::set_transcript_ui_state`, and `ChatComposer::footer_props`, with footer text
|
||||
assembled in `codex-rs/tui2/src/bottom_pane/footer.rs`.
|
||||
|
||||
### 9.4 Exit transcript output
|
||||
|
||||
`App::run` returns `session_lines` on `AppExitInfo` after flattening with
|
||||
`App::build_transcript_lines` and converting to ANSI via `App::render_lines_to_ansi`. The CLI
|
||||
prints those lines before the token usage and resume hints.
|
||||
|
||||
## 10. Future Work and Open Questions
|
||||
|
||||
### 10.1 Current status
|
||||
|
||||
This design shipped behind the `tui2` feature flag (as a separate crate, duplicating the legacy
|
||||
`tui` crate to enable rollout without breaking existing behavior). The following items from early
|
||||
feedback are already implemented:
|
||||
|
||||
- Bottom pane positioning is pegged high with an empty transcript and moves down as the transcript
|
||||
fills (including on resume).
|
||||
- Wheel-based transcript scrolling uses the stream-based normalization model derived from scroll
|
||||
probe data (see `codex-rs/tui2/docs/scroll_input_model.md`).
|
||||
- While a selection is active, streaming stops “follow latest output” so the selection remains
|
||||
stable, and follow mode resumes after the selection is cleared.
|
||||
- Copy operates on the full selection range (including offscreen lines), using the same wrapping as
|
||||
on-screen rendering.
|
||||
- Copy selection uses `Ctrl+Shift+C` (VS Code uses `Ctrl+Y` because `Ctrl+Shift+C` is unavailable in
|
||||
the terminal) and shows an on-screen “copy” affordance near the selection.
|
||||
|
||||
### 10.2 Roadmap (prioritized)
|
||||
|
||||
This section captures a prioritized list of improvements we want to add to TUI2 based on early
|
||||
feedback, with the goal of making scrolling/selection/copy feel as close to “native terminal” (and
|
||||
Vim) behavior as we can while still owning the viewport.
|
||||
|
||||
**P0 — must-have (usability/correctness):**
|
||||
|
||||
- **Scrolling behavior.** Default to a classic multi-line wheel tick (3 lines, configurable) with
|
||||
acceleration/velocity for faster navigation, and ensure we stop scrolling when the user stops
|
||||
input (avoid redraw/event-loop backlog that makes scrolling feel “janky”).
|
||||
- **Mouse event bounds.** Ignore mouse events outside the transcript region so clicks in the
|
||||
composer/footer don’t start or mutate transcript selection state.
|
||||
- **Copy fidelity.** Preserve meaningful indentation (especially code blocks), treat soft-wrapped
|
||||
prose as a single logical line when copying, and copy markdown _source_ (including backticks and
|
||||
heading markers) even if we render it differently.
|
||||
|
||||
**P1 — should-have (UX polish and power user workflows):**
|
||||
|
||||
- **Streaming wrapping polish.** Ensure all streaming paths use display-time wrapping only, and add
|
||||
tests that cover resizing after streaming has started.
|
||||
- **Selection semantics.** Define and implement selection behavior across multi-step output (and
|
||||
whether step boundaries should be copy boundaries), while continuing to exclude the left gutter
|
||||
from copied text.
|
||||
- **Auto-scroll during drag.** While dragging a selection, auto-scroll when the cursor is at/near the
|
||||
top or bottom of the transcript viewport to allow selecting beyond the visible window.
|
||||
- **Width-aware selection.** Ensure selection highlighting and copy reconstruction handle wide glyphs
|
||||
correctly (emoji, CJK), matching terminal display width rather than raw character count.
|
||||
- **Multi-click selection.** Support double/triple/quad click selection (word/line/paragraph),
|
||||
implemented on top of the transcript/viewport model rather than terminal buffer coordinates.
|
||||
- **Find in transcript.** Add text search over the transcript (and consider integrating match
|
||||
markers with any future scroll indicator work).
|
||||
- **Cross-terminal behavior checks.** Validate copy/selection behavior across common terminals (incl.
|
||||
terminal-provided “override selection” modes like holding Shift) and document the tradeoffs.
|
||||
|
||||
**P2 — nice-to-have (polish, configuration, and interactivity):**
|
||||
|
||||
- **Suspend printing.** Decide whether printing history on suspend is desirable at all (it is not
|
||||
implemented yet). If we keep it, finalize the config shape/defaults, wire it through TUI startup,
|
||||
and document it in the appropriate config docs.
|
||||
- **Terminal integration.** Consider guiding (or optionally managing) terminal-emulator-specific
|
||||
settings that affect TUI behavior (for example iTerm’s clipboard opt-in prompts or Ghostty
|
||||
keybinding quirks), so the “works well out of the box” path is consistent across terminals.
|
||||
- **Interactive cells (unlocked by transcript ownership).** Because transcript entries are structured
|
||||
objects (not dead text in terminal scrollback), we can attach metadata to rendered regions and map
|
||||
mouse/keys back to the underlying cell reliably across resizes and reflow. Examples:
|
||||
- **Drill into a specific tool/command output.** Click (or press Enter) on a tool call / command
|
||||
cell to open a focused overlay that shows the command, exit status, timing, and stdout/stderr as
|
||||
separate sections, with dedicated “copy output” actions. This enables copying _just_ one command’s
|
||||
output even when multiple commands are interleaved in a turn.
|
||||
- **Copy an entire cell or entire turn.** Provide an action to copy a whole logical unit (one cell,
|
||||
or “user prompt + assistant response”), without gutters and with well-defined boundaries. This is
|
||||
hard to do with raw selection because step boundaries and padding aren’t reliably expressible in
|
||||
terminal coordinates once the viewport moves or reflows.
|
||||
- **Expand/collapse structured subregions with source-aware copy.** Tool calls, diffs, and
|
||||
markdown can render in a compact form by default and expand in place. Copy actions can choose
|
||||
between “copy rendered view” and “copy source” (e.g. raw markdown, raw JSON arguments, raw diff),
|
||||
since we retain the original source alongside the rendered lines.
|
||||
- **Cell-scoped actions.** Actions like “copy command”, “yank into composer”, “retry tool call”, or
|
||||
“open related view” (diff/pager) can be offered per cell and behave deterministically, because the
|
||||
UI can address cells by stable IDs rather than by fragile screen coordinates.
|
||||
- **Additional affordances.** Consider an ephemeral scrollbar and/or a more explicit “selecting…”
|
||||
status if footer hints aren’t sufficient.
|
||||
- **UX capture.** Maintain short “golden path” clips showing scrolling (mouse + keys), selection and
|
||||
copy, streaming under resize, and suspend/resume + exit printing.
|
||||
|
||||
### 10.3 Open questions
|
||||
|
||||
This section collects design questions that follow naturally from the current model and are worth
|
||||
explicit discussion before we commit to further UI changes.
|
||||
|
||||
- **“Scroll mode” vs “live follow” UI.**
|
||||
|
||||
- We already distinguish “scrolled away from bottom” vs “following the latest output” in the
|
||||
footer and scroll state. Do we need a more explicit “scroll mode vs live mode” affordance (e.g.,
|
||||
a dedicated indicator or toggle), or is the current behavior sufficient and adding more chrome
|
||||
would be noise?
|
||||
|
||||
- **Ephemeral scroll indicator.**
|
||||
|
||||
- For long sessions, a more visible sense of “where am I?” could help. One option is a minimalist
|
||||
scrollbar that appears while the user is actively scrolling and fades out when idle. A full
|
||||
“mini‑map” is probably too heavy for a TUI given the limited vertical space, but we could
|
||||
imagine adding simple markers along the scrollbar to show where prior prompts occurred, or
|
||||
where text search matches are, without trying to render a full preview of the buffer.
|
||||
|
||||
- **Selection affordances.**
|
||||
|
||||
- Today, the primary hint that selection is active is the reversed text plus the on-screen “copy”
|
||||
affordance (`Ctrl+Shift+C`) and the footer hint. Do we want an explicit “Selecting… (Esc to
|
||||
cancel)” status while a drag is in progress, or would that be redundant/clutter for most users?
|
||||
|
||||
- **Suspend banners in scrollback.**
|
||||
|
||||
- When printing history on suspend, should we also emit a small banner such as
|
||||
`--- codex suspended; history up to here ---` to make those boundaries obvious in scrollback?
|
||||
This would slightly increase noise but could make multi‑suspend sessions easier to read.
|
||||
|
||||
- **Configuring suspend printing behavior.**
|
||||
|
||||
- The design already assumes that suspend‑time printing can be gated by config. Questions to
|
||||
resolve:
|
||||
- Should printing on suspend be on or off by default?
|
||||
- Should we support multiple modes (e.g., “off”, “print all new cells”, “print streaming cell
|
||||
tail only”) or keep it binary?
|
||||
|
||||
- **Streaming duplication at the edges.**
|
||||
- If we later choose to always re‑emit the “currently streaming” message when printing on suspend,
|
||||
we would intentionally allow a small amount of duplication at the boundary of that message (for
|
||||
example, its last line appearing twice across suspends). Is that acceptable if it improves the
|
||||
readability of long streaming answers in scrollback, and should the ability to disable
|
||||
suspend‑time printing be our escape hatch for users who care about exact de‑duplication?\*\*\*
|
||||
|
||||
---
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓▒▓▒██▒▒██▒
|
||||
▒▒█▓█▒█▓█▒▒░░▒▒ ▒ █▒
|
||||
█░█░███ ▒░ ░ █░ ░▒░░░█
|
||||
▓█▒▒████▒ ▓█░▓░█
|
||||
▒▒▓▓█▒░▒░▒▒ ▓░▒▒█
|
||||
░█ █░ ░█▓▓░░█ █▓▒░░█
|
||||
█▒ ▓█ █▒░█▓ ░▒ ░▓░
|
||||
░░▒░░ █▓▓░▓░█ ░░
|
||||
░▒░█░ ▓░░▒▒░ ▓░██████▒██ ▒ ░
|
||||
▒░▓█ ▒▓█░ ▓█ ░ ░▒▒▒▓▓███░▓█▓█░
|
||||
▒▒▒ ▒ ▒▒█▓▓░ ░▒████ ▒█ ▓█▓▒▓
|
||||
█▒█ █ ░ ██▓█▒░
|
||||
▒▒█░▒█▒ ▒▒▒█░▒█
|
||||
▒██▒▒ ██▓▓▒▓▓▓▒██▒█░█
|
||||
░█ █░░░▒▒▒█▒▓██
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒████▒██▒
|
||||
██░███▒░▓▒██
|
||||
▒▒█░░▓░░▓░█▒██
|
||||
░▒▒▓▒░▓▒▓▒███▒▒█
|
||||
▓ ▓░░ ░▒ ██▓▒▓░▓
|
||||
░░ █░█░▓▓▒ ░▒ ░
|
||||
▒ ░█ █░░░░█ ░▓█
|
||||
░░▒█▓█░░▓▒░▓▒░░
|
||||
░▒ ▒▒░▓░░█▒█▓░░
|
||||
░ █░▒█░▒▓▒█▒▒▒░█░
|
||||
█ ░░░░░ ▒█ ▒░░
|
||||
▒░██▒██ ▒░ █▓▓
|
||||
░█ ░░░░██▓█▓░▓░
|
||||
▓░██▓░█▓▒ ▓▓█
|
||||
██ ▒█▒▒█▓█
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
███████▒
|
||||
▓ ▓░░░▒▒█
|
||||
▓ ▒▒░░▓▒█▓▒█
|
||||
░▒▒░░▒▓█▒▒▓▓
|
||||
▒ ▓▓▒░█▒█▓▒░░█
|
||||
░█░░░█▒▓▓░▒▓░░
|
||||
██ █░░░░░░▒░▒▒
|
||||
░ ░░▓░░▒▓ ░ ░
|
||||
▓ █░▓░░█▓█░▒░
|
||||
██ ▒░▓▒█ ▓░▒░▒
|
||||
█░▓ ░░░░▒▓░▒▒░
|
||||
▒▒▓▓░▒█▓██▓░░
|
||||
▒ █░▒▒▒▒░▓
|
||||
▒█ █░░█▒▓█░
|
||||
▒▒ ███▒█░
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
█████▓
|
||||
█▒░▒▓░█▒
|
||||
░▓▒██
|
||||
▓█░░░▒▒ ░
|
||||
░ █░░░░▓▓░
|
||||
░█▓▓█▒ ▒░
|
||||
░ ░▓▒░░▒
|
||||
░ ▓█▒░░
|
||||
██ ░▓░░█░░
|
||||
░ ▓░█▓█▒
|
||||
░▓ ░ ▒██▓
|
||||
█ █░ ▒█░
|
||||
▓ ██░██▒░
|
||||
█▒▓ █░▒░░
|
||||
▒ █░▒▓▓
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▓████
|
||||
░▒▒░░
|
||||
░░▒░
|
||||
░██░▒
|
||||
█ ░░
|
||||
▓▓░░
|
||||
█ ░░
|
||||
█ ░
|
||||
▓█ ▒░▓
|
||||
░ █▒░
|
||||
█░▓▓ ░░
|
||||
░▒▒▒░
|
||||
░██░▒
|
||||
█▒▒░▒
|
||||
█ ▓ ▒
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
████▓
|
||||
█▓▒▒▓▒
|
||||
░▒░░▓ ░
|
||||
░░▓░ ▒░█
|
||||
░░░▒ ░
|
||||
░█░░ █░
|
||||
░░░░ ▓ █
|
||||
░░▒░░ ▒
|
||||
░░░░
|
||||
▒▓▓ ▓▓
|
||||
▒░ █▓█░
|
||||
░█░░▒▒▒░
|
||||
▓ ░▒▒▒░
|
||||
░▒▓█▒▒▓
|
||||
▒█ █▒▓
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
█████░▒
|
||||
░█▒░░▒▓██
|
||||
▓▓░█▒▒░ █░
|
||||
░▓░ ▓▓█▓▒▒░
|
||||
░░▒ ▒▒░░▓ ▒░
|
||||
▒░░▓░░▓▓░
|
||||
░░ ░░░░░░█░
|
||||
░░▓░░█░░░ █▓░
|
||||
░░████░░░▒▓▓░
|
||||
░▒░▓▓░▒░█▓ ▓░
|
||||
░▓░░░░▒░ ░ ▓
|
||||
░██▓▒░░▒▓ ▒
|
||||
█░▒█ ▓▓▓░ ▓░
|
||||
░▒░░▒▒▓█▒▓
|
||||
▒▒█▒▒▒▒▓
|
||||
░░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▒█ ███░▒
|
||||
▓▒░░█░░▒░▒▒
|
||||
░▓▓ ▒▓▒▒░░ █▒
|
||||
▓▓▓ ▓█▒▒░▒░░██░
|
||||
░░▓▒▓██▒░░█▓░░▒
|
||||
░░░█░█ ░▒▒ ░ ░▓░
|
||||
▒▒░ ▓░█░░░░▓█ █ ░
|
||||
░▓▓ ░░░░▓░░░ ▓ ░░
|
||||
▒▒░░░█░▓▒░░ ██ ▓
|
||||
█ ▒▒█▒▒▒█░▓▒░ █▒░
|
||||
░░░█ ▓█▒░▓ ▓▓░░░
|
||||
░░█ ░░ ░▓▓█ ▓
|
||||
▒░█ ░ ▓█▓▒█░
|
||||
▒░░ ▒█░▓▓█▒░
|
||||
█▓▓▒▒▓▒▒▓█
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
█▒███▓▓░█▒
|
||||
▒▓██░░░█▒█░█ ▒█
|
||||
██▒▓▒▒▒░██ ░░░▒ ▒
|
||||
▓░▓▒▓░ ▒░ █░▓▒░░░▒▒
|
||||
░▓▒ ░ ░ ▓▒▒▒▓▓ █
|
||||
░▒██▓░ █▓▓░ ▓█▒▓░▓▓
|
||||
█ ▓▓░ █▓▓░▒ █ ░░▓▒░
|
||||
▓ ▒░ ▓▓░░▓░█░░▒▓█
|
||||
█▓█▓▒▒▒█░▒▒░▒▒▓▒░░░ ░
|
||||
░ ▒▓▒▒░▓█▒▓░░▒ ▒███▒
|
||||
▒▒▒▓ ████▒▒░█▓▓▒ ▒█
|
||||
▒░░▒█ ░▓░░░ ▓
|
||||
▒▒▒ █▒▒ ███▓▒▒▓
|
||||
█ ░██▒▒█░▒▓█▓░█
|
||||
░█▓▓▒██░█▒██
|
||||
░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▒▒█▒▒█▓░█▒
|
||||
▒█ ▒▓███░▒▒█ █▓▓▒
|
||||
▒▓▓░█ █▒ █ ▓▒ █▓▓▒ █
|
||||
█░░█▓█▒ █ █▒░▒▓▒░▒▓▒▒▒█
|
||||
▒▒▓▓ ▓░ ▒ █▒▒▓░▓░▒▒▓▒▒▒
|
||||
▓▒░ ██░▓▒▒▒▓███░█▓▓▒▓░▓░
|
||||
░░▒▓▓ █▓█▓░ ▒▓ █░▒░▒█
|
||||
▒▓░░ ▒▒ ░░▓▒ ░▓░
|
||||
▒ █▒▒▒▓▒▓█░░█░█▓▒█ ░█░░
|
||||
▒▒▒░█▒█ ░░▓▒▒▒▒░░░▒▓░░▒ █
|
||||
░▓░▒░ █████░ ▒▒▒▓░▓█▓░▓░
|
||||
▒▒ █▒█ ░░█ ▓█▒█
|
||||
▒▒██▒▒▓ ▒█▒▒▓▒█░
|
||||
█░▓████▒▒▒▒██▒▓▒██
|
||||
░░▒▓▒▒█▓█ ▓█
|
||||
░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▒▒▒█░█▒▒░▓▒
|
||||
▒█░░░▒▓▒▒▒▒█▒█░███
|
||||
██▓▓▓ ░██░ ░█▓█░█▓▒
|
||||
▓▓░██▒░ ▒▒▒██▒░██
|
||||
░░▓░▓░ █░▒ ▓ ░▒ ░▒█
|
||||
░▒▓██ ▒░█░▓ ▓▓ █▓█░
|
||||
▒▒░░█ ▓█▒▓░██░ ▓▓▓█░
|
||||
░░░░ ░▓ ▒░ █ ░ ░░░
|
||||
░█░▒█▒▓▓▒▒▒░░░░██▓█░▓ ▒ ░░
|
||||
▒▓▓█░▒█▓▒██▒█░█ ▒▒ ▓▒▒▒█▓▓░▒
|
||||
█▒ ▓█░ ██ ▒▒▒▓░▓▓ ▓▓█
|
||||
▒▒▒█▒▒ ░▓▓▒▓▓█
|
||||
█ ▒▒░░██ █▓▒▓▓░▓░
|
||||
█ ▓░█▓░█▒▒▒▓▓█ ▓█░█
|
||||
░▓▒▓▓█▒█▓▒█▓▒
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓▒▓▒█▒▒▒██▒
|
||||
▒██▓█▓█░░░▒░░▒▒█░██▒
|
||||
█░█░▒██░█░░ ░ █▒█▓░░▓░█
|
||||
▒░▓▒▓████▒ ▓█▒░▓░█
|
||||
█▒ ▓█▒░▒▒▒▒▒ ▒█░▒░█
|
||||
█▓█ ░ ░█▒█▓▒█ ▒▒░█░
|
||||
█░██░ ▒▓░▓░▒░█ ▓ ░ ░
|
||||
░ ▒░ █░█░░▓█ ░█▓▓░
|
||||
█ ▒░ ▓░▒▒▒░ ▓░█████████░▒░░█
|
||||
▒▒█░ ▓░░█ ▓█ ░▒▒▒▒▒▒▓▓▒▒░█▓ ░
|
||||
▒▒▒ █ █▒▓▓░█ ░ ███████ ░██░░
|
||||
█▒▒▓▓█ ░ ██▓▓██
|
||||
▓▒▒▒░██ █▒▒█ ▒░
|
||||
░░▒▓▒▒ ██▓▓▒▓▓▓▒█░▒░░█
|
||||
░████░░▒▒▒▒░▓▓█
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▒█▒░░▒█▒█▒▒
|
||||
█▓▒ ▓█▒█▒▒▒░░▒▒█▒██
|
||||
██ ▒██ ░█ ░ ▒ ▒██░█▒
|
||||
▒░ ▒█░█ ▒██░▒▓█▒▒
|
||||
▒░ █░█ ▒▓ ▒░░▒█▒░░▒
|
||||
▓░█░█ ███▓░ ▓ █▒░░▒
|
||||
▓░▓█░ ██ ▓██▒ █▒░▓
|
||||
░▒▒▓░ ▓▓░ █ ░░ ░
|
||||
░▓░░▓█▒▓▒▒▒▒▒▒▒██▓▒▒▒▒█ ▓ ░▒
|
||||
█░▒░▒ ▓░░▒▒▒▒░▒ █▒▒ ░▒▒ █▓ ░░
|
||||
▒█▒▒█ █ ▒█▒░░█░ ▓▒
|
||||
█ ▒█▓█ ▒▓█▓░▓
|
||||
▒▒▒██░▒ █▓█░▓██
|
||||
▒█▓▓ ░█▒▓▓█▓ ░ ░█▓██
|
||||
░██░▒ ▒▒▒▒▒░█
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▒█▒█▒▒█▒██▒▒
|
||||
███░░▒▒█░▒░█▓▒░▓██▒
|
||||
▓█▒▒██▒ ░ ░▒░██▒░██
|
||||
██░▓ █ ▒█▓██▓██
|
||||
▓█▓█░ █░▓▒▒ ▒▒▒▒█
|
||||
▓ ▓░ ███▒▓▓ ▒▒▒█
|
||||
░█░░ ▒ ▓░█▓█ ▒▓▒
|
||||
░▒ ▒▓ ░█ ░ ░
|
||||
░ ░ ██▓▓▓▓▓███ ▒░█ ░█ ▓▓ ░
|
||||
░ ░▒ ░▒ ▒█░ ▒ ░█░█ ▓ ▓▓
|
||||
▓ ▓ ░░ █░ ██▒█▓ ▓░ █
|
||||
██ ▓▓▒ ▒█ ▓
|
||||
█▒ ▒▓▒ ▒▓▓██ █░
|
||||
█▒▒ █ ██▓░░▓▓▒█ ▓░
|
||||
███▓█▒▒▒▒█▒▓██░
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒██▒█▒▒█▒██▒
|
||||
▒█▓█░▓▒▓░▓▒░░▓░█▓██▒
|
||||
█▓█▓░▒██░ ░ █▒███▒▒██
|
||||
▓█░██ ██░░░▒█▒
|
||||
▒░░▓█ █▒▓░▒░▓▓▓█░
|
||||
▒░█▓░ █░▓░▓▒▓░ ▒░▒▒░
|
||||
░██▒▓ ░█░▒█▓█ ░░▓░
|
||||
░░▒░░ ░▒░░▒▒ ░▒░ ░
|
||||
░░█ █ █░▒▒▓▓▓▒██▒▒█░▒ ▒█ ▒░▓
|
||||
▒░▒ █▒▒▒█ ▓█ ░▓▓░ ▒█▓▒ ░██ ▓▒▒
|
||||
▒▒▒▒░ ██ ░ ░▓██▒▓▓▓ █░
|
||||
▒█▒▒▒█ ▒██ ░██
|
||||
█ █▓ ██▒ ▒▓██ █▒▓
|
||||
█▓███ █░▓▒█▓▓▓▒█ ███
|
||||
░ ░▒▓▒▒▒▓▒▒▓▒█░
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒██▒▒████▒█▒▒
|
||||
▒▒░█░▒▒█▒▒▒█░▒░█░█▒
|
||||
█ █░██▓█░ ░▓█░▒▓░░█
|
||||
▓▓░█▓▓░ ▒▓▓▒░░▓▒
|
||||
▓▓░░▓█ █▓████▓█▒░▒
|
||||
█▒░ ▓░ ▒█████▓██░░▒░█
|
||||
░░░ ░ ▓▓▓▓ ▒░░ ░██
|
||||
░▓░ ░ ░ ░█▒▒█ ░ █▓░
|
||||
▒ ▒ ░█░▓▒▒▒▒▒▓▒░▒█░▒ ▒▒ ░ ░░░
|
||||
░▒▒▒░ ▒ ▓░▒ ▒░▒▒█░ ▒▒░
|
||||
▓█░ ░ ░ █░▓▓▒░▒▓▒▓░
|
||||
█░░▒░▓ █▓░▒▒▓░
|
||||
▒ ░██▓▒▒ ▒▓ ▓█▓█▓
|
||||
▒▒▒█▓██▒░▒▒▒██ ▓▒██░
|
||||
░ █▒▒░▒▒█▒▒██░
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒░▒▓███▒▒█▒
|
||||
█ ▒▓ ░▒▒░▒▒██▒██
|
||||
█ █▓▒▓█ ░ ▓░▓█░███ ▒
|
||||
██▓▓█▓░▒█▒░░▓░ ▒█▒░▒▒█
|
||||
█ ▓▓▒▓█ ░ ▓▒▒░░░▒░██
|
||||
░█▒█▒░ ███▓ ▓░▓ ▓ ▒
|
||||
░ ░░ █▓▒█▓ ▓▒▒░▒▒░▒
|
||||
░ ▒░░ ░█▒▓▒▒░░▒▓▓░░░
|
||||
░▓ ░▓▓▓▓██░░░██▒██▒░ ░ ░░
|
||||
▒ ▓ █░▓██▓▓██░▓▒▒██░ ░█░
|
||||
▒ █▒░▒█ ░ ▒█▓█▒░▒▓█░
|
||||
▒ ▒██▒ ░ ▓▓▓
|
||||
▒▓█▒░░▓ ▒▒ ▒▓▓▒█
|
||||
▓▓██▒▒ ░░▓▒▒▓░▒▒▓░
|
||||
█▓▒██▓▒▒▒▒▒██
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒█▒█▓████▒
|
||||
█ ███░▒▓▒░█░░█
|
||||
▓░▓▓██ ▓░█▒▒▒░░░▒
|
||||
░██░ ▓ ▒░ ▒░██▒▓
|
||||
█▒▒▒█▓█▒▓▓▒░ ░▓▓▒▓█
|
||||
▒█░░░▒██▓▒░▓ ▓░█░▓▓░█
|
||||
░▓░█░ ░▒▒▓▒▒▓░▒▓▒ ░▒░
|
||||
░░░▓░▓ ░▒▒▒▓░▒▒░▒░░▒
|
||||
▒█▒░ ░▒▒▒▒▒▒█░░▒▒░██░▒
|
||||
▓▓ ░▓░█░▒░░▓█▒░▒█▒▓▒░
|
||||
▒░█▓▒░░ ██▓░▒░▓░░
|
||||
░▒ ░▓█▓▒▓██▓▒▓█▓▓░▓
|
||||
▒░▒░▒▒▒█▓▓█▒▓▒░░▓
|
||||
▒▓▓▒▒▒█▒░██ █░█
|
||||
░█ █▒██▒█░█
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓███ ██
|
||||
▓█░▓▓▒░█▓░█
|
||||
▓█ ░▓▒░▒ ▒█
|
||||
▓█ █░░░▒░░▒█▓▒
|
||||
░▒█▒░▓░ █▒▓▓░▒▓
|
||||
▒ ░▓▓▓ █▒▒ ▒▒▓
|
||||
░ ██▒░░▓░░▓▓ █
|
||||
▓▓ ▒░░░▒▒▒░░▓░░
|
||||
░ ▓▒█▓█░█▒▒▓▒░░
|
||||
▓▒░▓█░▒▒██▒▒█░
|
||||
░░ ▓░█ ▒█▓░█▒░░
|
||||
▒▒░░▓▒ ▓▓ ░░░
|
||||
█ █░▒ ▒░▓░▓█
|
||||
░ █▒▒ █▒██▓
|
||||
▒▓▓▒█░▒▒█
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▓█████
|
||||
░▓▓▓░▓▒
|
||||
▓█░ █░▓█░
|
||||
░░░▒░░▓░░
|
||||
░ ░░▒▓█▒
|
||||
░▒▓▒ ░░░░░
|
||||
▒ ░░▒█░░
|
||||
░ ░░░░▒ ░░
|
||||
░▓ ▓ ░█░░░░
|
||||
█▒ ▓ ▒░▒█░░
|
||||
░▓ ▒▒███▓█
|
||||
░░██░░▒▓░
|
||||
░▒▒█▒█▓░▒
|
||||
▒▒▒░▒▒▓▓
|
||||
█▒ ▒▒▓
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▓██▓
|
||||
░█▒░░
|
||||
▒ ▓░░
|
||||
░▓░█░
|
||||
░ ░░
|
||||
░ ▓ ░
|
||||
▒░░ ▒░
|
||||
░▓ ░
|
||||
▓▒ ▒░
|
||||
░░▓▓░░
|
||||
░ ▒░
|
||||
░▒█▒░
|
||||
░▒█░░
|
||||
█▒▒▓░
|
||||
░ ▓█░
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
██████
|
||||
█░█▓ █▒
|
||||
▒█░░ █ ░
|
||||
░░░░▒▒█▓
|
||||
▒ ░ ░ ░
|
||||
░█░░░ ▒▒
|
||||
░▒▒░░░ ▒
|
||||
░░▒░░
|
||||
░░░█░ ░
|
||||
▒░▒░░ ░
|
||||
█░░▓░▒ ▒
|
||||
░▓░░░ ▒░
|
||||
░░░░░░▒░
|
||||
░▒░█▓ ░█
|
||||
░░█ ▓█
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓▒▓██▒▒▒▒█▒
|
||||
▒██▓▒░░█░ ▒▒░▓▒▒░██▒
|
||||
█▓▓█▓░█ ░ ░ ░ ███▓▒░█
|
||||
▓█▓▒░▓██▒ ░▒█ ░░▒
|
||||
█▓█░▓▒▓░░█▒▒ ▒▒▒░░▒
|
||||
▓░▒▒▓ ▓█░▒▓▒▒ ░ ▒▒░
|
||||
▒█ ░ ██▒░▒ ░█ ▓█▓░█
|
||||
█▓░█░ █▓░ ▓▒░ ░▒░▒░
|
||||
▓ █░ ▓░██░░█▓░▒██▒▒▒██▒░▒ ▓░
|
||||
█▒▓▒█ ▓▓█▓▓▓░ ░█░▒▒█ ▒▓█▓▒░░▒░░
|
||||
█▒░ ░ ░░██ ███ ███▓▓▓█▓
|
||||
██░ ▒█ ░ ▓▒█▒▓▓
|
||||
▒▒▓▓█▒█ ██▓▓ █░█
|
||||
▒▒██▒██▒▒▓▒▓█▓▒█▓░▒█
|
||||
░███▒▓░▒▒▒▒░▓▓▒
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓ ████
|
||||
▒▓▓░░▒██▒▒
|
||||
█▒░█▒▒░██▒
|
||||
░░▒░▓░▒▒░▒ ▒█
|
||||
▒█░░░▒░█░█ ░
|
||||
░█░▒█ █░░░░▓░
|
||||
▒▓░░░▒▒ ▒▓▒░ ▒░
|
||||
░ ██▒░█░ ░▓ ░
|
||||
░▒ ▒░▒░▒▓░█ ░
|
||||
░░▒░▒▒░░ ██ ░
|
||||
▒░░▓▒▒█░░░█░░
|
||||
░█▓▓█▓█▒░░ ░
|
||||
▒░▒░░▓█░░█░▓
|
||||
█▒██▒▒▓░█▓█
|
||||
▒▓▓░▒▒▒▓█
|
||||
░░░░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓▓████▒█
|
||||
▒██▓██▒ █▒███
|
||||
█░▒▓▓█▒▒░▓ ░▒█▒
|
||||
█░▓█▒▒█▓▒█▒▒░▒░░▒
|
||||
▒░░░░█▓█▒▒█ ▒░▓▒▒
|
||||
▓░▒░░▒░█ ▒▓██▓▓░█ ░
|
||||
▓░░ ░▒█░▒▓▒▓▓█░█░▓░
|
||||
▒▒█ ░░ ░▒ ░▒ ░░▒▓░
|
||||
░▒█▒░█▒░░░▓█░░░▒ ░
|
||||
░░░▓▓░░▒▒▒▒▒░▒░░ █
|
||||
▒█▒▓█░█ ▓███░▓░█░▒
|
||||
░░░▒▒▒█ ▒▒█ ░
|
||||
▓░█▒▒ █ ▓ ░█░▓░
|
||||
▓░▒░▓▒░░█░ █░░
|
||||
█ ▒░▒██▓▓▓█
|
||||
░░░░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
█████▓▓░█▒
|
||||
▓█░██░▒░░██░░█
|
||||
▓▒█▒▒██▒▓▓░█░█▒███
|
||||
█▓▓░▒█░▓▓ ▓ █▒▒░██ █
|
||||
▓▓░█░█▒██░▓ █░█░▒▓▒█▒█
|
||||
▒▓▒▒█▒█░░▓░░█▒ ░█▓ █
|
||||
█░ ▓█░█▒░░██░█▒░▓▒▓▓░█▒
|
||||
░░░█▒ ▒░░ ▓█░▓▓▒ ▒░ ░
|
||||
▒░░▓▒ █▒░ ▒▒░███░░░▒░ ▒░
|
||||
█ ▒░░█▒█▒▒▒▒▒▒░░█░▓░▓▒
|
||||
█▒█░░▓ ░█ ███▒▓▓▓▓▓▓
|
||||
▒█░▒▒▒ █▒░▓█░
|
||||
███░░░█▒ ▒▓▒░▓ █
|
||||
▒▓▒ ░█░▓▒█░▒█ ▒▓
|
||||
░▓▒▒▒██▓█▒
|
||||
░░░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒██▒█▒█▒░▓▒
|
||||
▒██░░▒█▒░▓░▓░█░█▓
|
||||
▒▓▒░████▒ ░ █▓░░█ █
|
||||
█▒▓░▓▒░█▒ █░░▒▒█
|
||||
▒▓░▓░░░▓▒▒▒ ░█▒▒▒
|
||||
▓▓█ ▒▒▒▒░▒█ ▓▒▓▒▒
|
||||
░░█ ▒██░▒░▒ ░█░░
|
||||
█░██ ███▒▓▒█ ▒ ░█
|
||||
░░░ ░ █░ ▓████▓▒▒█░░█▓▒░▒░
|
||||
▒▓░█ ▓▓█▓░░░▒▒▒▒▒░░█▒▒▒░░▓
|
||||
▒▒▒█ ░▓░▓ ▓ ███ ░░█▓▒░
|
||||
▒█▒██ █ ▓▓▓▓▒▓
|
||||
█▒ ███▓█ ▒█░█▓█▒█
|
||||
▒░ █▒█░█▓█▒ ▓█▒█░█
|
||||
▒▒██▒▒▒▒██▓▓
|
||||
░░░░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒█▒████▒░█▒
|
||||
▒███▓▒▓░ ░██▒██▓█▒▒
|
||||
▒▓▓█░█ ▓░█░ ░▒▒▒█ ███
|
||||
█▓▒░█▒▓█▒ █░██▒▒
|
||||
▓▓░▒▓▓░ ░ █ ▒▒█▒▒
|
||||
█▓▒░░▓ ▒▒ ░▒█▒ ▒█▒░▒
|
||||
░█▒░▒ █▒▒█░▒▒ ░▓░▒
|
||||
▒░▒ ▓ ░█▒░▓ ░ ▓ ▒▒
|
||||
██▓▓ ▓▒▓▓ ▒▒▒██████░▒▒ ░▒░
|
||||
░░▒█▓██▒ ▓▓█░░░▒░▓▒▒▒█▓▒░░░░▒
|
||||
▓▒▒█ ░▒░█▒ ██░░░░▒ █▓█▒░█
|
||||
▓█▒▓▒▒▒ ▓▓▓░▓█
|
||||
▒█░░█▒▓█ ▒█▒ ▒▓█░
|
||||
▓▒▓░ ░██▓██▒█▒█░██▓█
|
||||
░▒▓▒▒▒▒▒▒▓▒█▒▒
|
||||
░░░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒██▓▒███▒██▒
|
||||
██▒█▓░███ ░█░▓ ░█▒▒
|
||||
▒▓▓░▓██░▒█ ░ ░ █▒█▓ ░██
|
||||
█▓▓█▓█▓█▒ ██▒▒░▒
|
||||
▓▓░░▓▓▒ ▒██ ░▒█░█
|
||||
▓▓▓▓█░ █░▒ ▓▓█▒ ░▒▒░
|
||||
▒ ▓▓ ▒▒ ██▒▓ ░▒▒▒
|
||||
░░░▓ ▓▒▒▓▓█ ▓ ▓
|
||||
▓ █▒ █░░▓▓ ▓░▒▒▒▓▒▒█░░ ░░▒█
|
||||
░█▒▓█ ▓▓▓ ██▓░▓ ▒█▒▒▒▒▓ ░▓█ ░█
|
||||
▓░▒██▓▒▒░▓▒░ ░ ▒▒▒▒█▒▒█▓▓▒█░
|
||||
▓▒▒▓░ ▒▓█ █▒
|
||||
▒▓░▒▓█▓█ █▓▓▒███
|
||||
▒▒ ░█░▓▓░░█░▓▓█ ▒▓▓
|
||||
▒░▓▒▒▒▓▒▒███ ▒
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▒█▒████▒██▒
|
||||
▒▒ ▒█▓▓▓█▒█▓██ ███▒
|
||||
█▒█▒███▓█ ░░ ░ █░██░██░█
|
||||
▒░ ██▒▒▒▒ ██░▒ ░
|
||||
█▓▒▓▒█░▒░▒█▓ ▒▒▓█
|
||||
▓ █▓░ █▒ ░▓█ ▒▒█
|
||||
░ ▓ ░ ▒ ▒▒ ░▒░█
|
||||
░░▒░ ▒▒ ▒▓▓ ▒░ ░
|
||||
░█ ░ ▓▓ ██ ████▒█████▒ ░▒░░
|
||||
▒█░▒ █░▒▒▓░▓ ░░▒▒▒▒▒▒▒░░ ▒▓█░
|
||||
█ █░▒ █▒█▓▒ ██▒▒▒▒▒ ░█ ▓
|
||||
██ ▒▓▓ █▓░ ▓
|
||||
▒▓░░█░█ ███ ▓█░
|
||||
██▒ ██▒▒▓░▒█░▓ ▓ █▓██
|
||||
░██▓░▒██▒██████
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓▒▓█▒▒█▒██▒
|
||||
▒▓ ██░▓ ░▒▒▓█▓░ ▓██▒
|
||||
██▒░░░██ ░ ░▒░▒▒█░▓▒▒▒
|
||||
▓▓░█░ ▓██ ░██▒█▒
|
||||
▓░▓▒░▒░▒▓▒░█ ▒ ▒░█▒
|
||||
▓░░▒░ █▒░░▓█▒ █ ▒▒░█
|
||||
▒░▓░ ███▒█ ░█ █ ▓░
|
||||
░▓▒ █░▓█▒░░ ░░░
|
||||
▒░ ░▒ ▓░▓ ▒▓▓█░███▒▒▒▒██ ░░█
|
||||
░▒▓ ░ █▓▓▓█▒░░▒▒░█▓▒█▓▓▒▓░▓▓ ░
|
||||
░░▓█▒█▒▒█▒▓ ████████▒▓░░░░
|
||||
█░▒ ░▒░ █▒▓▓███
|
||||
▒▒█▓▒ █▒ ▒▓▒██▓░▓
|
||||
░░░▒▒██▒▓▓▒▓██▒██▒░█░
|
||||
█▒▒░▓░▒▒▒▒▒▓▓█░
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓▒▓▓█▒▒▒██▒
|
||||
▒█ █▓█▓░░█░▒█▓▒░ ██
|
||||
█▒▓▒█░█ ░ ▒▒░█▒ ███
|
||||
█░▓░▓░▓▒█ ▓▒░░░░▒
|
||||
█▒▓█▓▒▒█░▒▒█ ░ ▒░▒░▒
|
||||
░░░░▓ ▒▒░▒▓▓░▒ █▓░░
|
||||
░▓░ █ ░▒▒░▒ ░█ ██░█░█
|
||||
░▓░▒ █▒▒░▓▒░ █░▒░
|
||||
░█░▒█ ▓▒░ █░█▒▒░█░▒▒▒██▒ ░▓░
|
||||
▒▒░▒██▓██ ░ ▓▓▒▒▒█▒▓█▓░▓█░░
|
||||
▒█░░█░█▒▒▓█░ ██ █░▓░▒▓
|
||||
▒▒█▓▒▒ ░ ▓▒▓██▒
|
||||
▒▓█▒░▒█▒ ▒▒████▓█
|
||||
▒░█░███▒▓░▒▒██▒█▒░▓█
|
||||
▒▓█▒█ ▒▒▒▓▒███░
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓▒▓▓█▒▒██▒▒
|
||||
█▒▓▓█░▒██░██▓▒███▒
|
||||
███░░░█ ░ ░▓▒███▓▒▒
|
||||
▓█░█░█▒▒█ ▒█░░░░█
|
||||
█▒░░░█▒▒██▒ ▓▒▒░▒█
|
||||
▓▓▓░▓░▒█▓░▒▒░█ ▓▒▒▓░
|
||||
▒ █░░ ▒▒░▓▒▒ ▒█░▒░
|
||||
░ ░░░ ▒░▒░▓░░ ░█▒░░
|
||||
▒▓░▓░ ▓█░░█▓▓█▒░█░▒▒██▒▓▒▓░
|
||||
░░▒█▓▒▒▒▓█ ░▓▒██░░█▓▒▒▒░█░▒
|
||||
▓ ░ ▓░░░▓▓ █ ██ ░▒▒▓░
|
||||
█ ▓ ▓█░ █▓▒▓▓░░
|
||||
▓░▒▒███ ▒█▒▒▓███
|
||||
░ ░██ █ ▓░▒▒████ ▓▓█
|
||||
▒▓▓███▒▒▒░▒███
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▓░▓██▒▒██▒
|
||||
██░█▒░███▒▒▒▓ ░██
|
||||
█ █░░░█░ ░▒░░ █▓▒██
|
||||
▒▒░░░░▓█ ▒░▒█░▓█
|
||||
░█░█░░▒░▓▒█ ▓ █░░▒
|
||||
░ ▓░░ ░█▒▓░▒ █▓░░░
|
||||
░▒ ░ ▒▒░▒░▒░ ██▒░░
|
||||
▒ ▓░░ ▒█▓░█░░ █ ░░░
|
||||
▓ ░█ █ ▒▓░▒▓░░▓▓▒░░▒▓█▒░░
|
||||
░██░░▒▓░░▓█░▓▒░░▒▒█▒█▓▒░▒░
|
||||
▒ ▒▒▓█░█▒▓ ██████ ▒▓░░
|
||||
█▒ ▓▒▓▒░ █ ▓▓▓▓█
|
||||
█▓██▒▒▒▒ █▒░██▓██
|
||||
▒▒█▒░█▒▓░▒▒▒██░██▓
|
||||
░█ ░▓░▒▒█▒▓██
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▒▒█▒▓██▒██▒
|
||||
█ █▓░░░█▒▒ ░ █
|
||||
▒░▒█░▓▓█ █ ░▓░█▒█▒█
|
||||
▒█▒█▓░██░ █ ▒▒░░▒
|
||||
█ ▓░▓█▒░▓▒ ▓█▒░░█
|
||||
░██░▒▒▒▒▒░▒█ ▒█░░░
|
||||
░█░░░ █▒▓▒░░░ ░▒░▓░█
|
||||
▒█░░▓ ░█▒▓░██▓ ▓░▓░░
|
||||
▒ ▒░░▒▒ ▓█▒░░▓█████▒░░░
|
||||
▒█▓▒▒░ █░█░░▓░▒▒▒░░▒█
|
||||
▓▓▒▒░▒░░░▓█▒█▒█ ▒█ ▓▒░
|
||||
██ ░▒░░░ ▓█▓▓▓█
|
||||
█▒▒█▒▒▒▒ ▒▓▒▒░█▓█
|
||||
▓▓█░██ ▓▓██▓▓▒█░░
|
||||
░░▒██▒░▒██▓▒░
|
||||
░░
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
▓▒▒█▓██▒█
|
||||
▓█▒▓░░█ ▒ ▒▓▒▒
|
||||
▓ █░░▓█▒▒▒▓ ▒▒░█
|
||||
░░▓▓▒▒ ▒▒█░▒▒░██
|
||||
▓█ ▓▒█ ░██ █▓██▓█░░
|
||||
░ ░░░ ▒░▒▓▒▒ ░█░█░░░
|
||||
░ ░█▒░██░▒▒█ ▓█▓ ░░░
|
||||
░ ░▓▒█▒░░░▒▓▒▒▒░ ░░
|
||||
█░ ▓░ ░░░░█░░█░░░
|
||||
░▒░░░▒█░▒░▒░░░░▒▒░░░
|
||||
░▒▓▒▒░▓ ████░░ ▓▒░
|
||||
▒░░░▒█░ █▓ ▒▓░░
|
||||
▒█▒░▒▒ ▓▓▒▓░▓█
|
||||
▒▓ ▒▒░█▓█▒▓▓█░░
|
||||
█▓▒ █▒▒░▓█▓
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eoeddccddcoe
|
||||
edoocecocedxxde ecce
|
||||
oxcxccccee eccecxdxxxc
|
||||
dceeccooe ocxdxo
|
||||
eedocexeeee coxeeo
|
||||
xc ce xcodxxo coexxo
|
||||
cecoc cexcocxe xox
|
||||
xxexe oooxdxc cex
|
||||
xdxce dxxeexcoxcccccceco dc x
|
||||
exdc edce oc xcxeeeodoooxoooox
|
||||
eeece eeoooe eecccc eccoodeo
|
||||
ceo co e ococex
|
||||
eeoeece edecxecc
|
||||
ecoee ccdddddodcceoxc
|
||||
ecccxxxeeeoedccc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eccccecce
|
||||
ccecccexoeco
|
||||
eeoxxoxxoxceoo
|
||||
xeeoexdeoeocceeo
|
||||
o dxxcxe cooeoxo
|
||||
xe cxcxooe eecx
|
||||
e xcccxxxxc xoo
|
||||
c xxecocxxoeeoexx
|
||||
c xe eexdxxcecdxx
|
||||
x oxeoxeoeceeexce
|
||||
o cxxxxxcc eocexe
|
||||
eecoeocc exccooo
|
||||
xc xxxxcodooxoe
|
||||
deccoxcde ooc
|
||||
co eceeodc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
occcccce
|
||||
oc dxxxeeo
|
||||
oceexxdecoeo
|
||||
xeexxddoedoo
|
||||
ecodexcecdexxo
|
||||
xcexxceddxeoxx
|
||||
cc oxxxxxxexde
|
||||
x xxoxxeo xcx
|
||||
o cxoxxcocxex
|
||||
cc exodocoxexe
|
||||
ceo xxxxdoxeex
|
||||
eeooxecoccdxe
|
||||
e cxeeeexdc
|
||||
ec cxxoeoce
|
||||
ee cccece
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
ccccco
|
||||
odeeoxoe
|
||||
c xoeco
|
||||
ocxxxddcx
|
||||
x cxxxxoox
|
||||
xcoocecexc
|
||||
x xoexxe
|
||||
x ocexxc
|
||||
co xoxxcxx
|
||||
x oxcdce
|
||||
xo xcdcco
|
||||
o cx eox
|
||||
o ccxocex
|
||||
ceocoxexe
|
||||
e cxeoo
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
occco
|
||||
xeexx
|
||||
xeexc
|
||||
xccxe
|
||||
c xx
|
||||
cdoxx
|
||||
o xx
|
||||
c cx
|
||||
oc exo
|
||||
xc cdx
|
||||
ceoo xe
|
||||
xeeex
|
||||
xcoxe
|
||||
ceexd
|
||||
o ocd
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
ccccd
|
||||
ooeeoe
|
||||
xexxo x
|
||||
xxoxcexo
|
||||
xxxe x
|
||||
xcxx cx
|
||||
xxxx o c
|
||||
xxexe e
|
||||
xxxx c
|
||||
ceoo do
|
||||
exccooox
|
||||
xcxxeeex
|
||||
o cxddde
|
||||
xeoceeo
|
||||
ec cdo
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
cccccxe
|
||||
eodxxedco
|
||||
ooxcdexccx
|
||||
xoe ooooeex
|
||||
xxdcdexxocex
|
||||
exxoxxoox c
|
||||
xx xxxxxxox
|
||||
xxoxxcxxx cox
|
||||
xxcoocxxxeodx
|
||||
xexdoxexco ox
|
||||
xoxxxxex e d
|
||||
xccoexxeo d
|
||||
cxeo oooe de
|
||||
xexxeeoceo
|
||||
eeceeeeo
|
||||
ee
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
edcccccxe
|
||||
oexxcxxexde
|
||||
xooceodexx ce
|
||||
ooo dceexexxccx
|
||||
xxdeoccdxxcoxee
|
||||
xxxcxc xed x xox
|
||||
eex oeoxxxxocco x
|
||||
xod xexxoxxxcd ex
|
||||
eexxxcxoexxccc o
|
||||
cceeoddecxoex oex
|
||||
xxxcccocexdcdoxxe
|
||||
xxc xe eooo o
|
||||
exc x oooeox
|
||||
exxcecxoocex
|
||||
cdoeddeedc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
odcccddxoe
|
||||
edccxxxcdcxoceo
|
||||
oceoeddecocxxxece
|
||||
oxoeoxcee cxdexxxde
|
||||
xoe x xcoedeoo o
|
||||
edcooe odox oodoxoo
|
||||
c dox oooxe ccxxodx
|
||||
ocdx ooxxoxoxxddc
|
||||
oocoeddcxeexeedexxx x
|
||||
xcedeexoceoxxe eccce
|
||||
eeeoccccccceexcooe ec
|
||||
exxec eoxxe d
|
||||
eee cee ocooeeo
|
||||
o xccdeceedcdxc
|
||||
ecdoeocxcecc
|
||||
e
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eddcddcdxoe
|
||||
eccedoccxeeoccdde
|
||||
eodxcccdcocoeccooe c
|
||||
oxxcooecc ceeeodxedeeeo
|
||||
eeoo ox ecceeoxoxeedeee
|
||||
oex ooxoeeeoocoxcooeoeox
|
||||
xxedo cocoxceoccxdxdo
|
||||
ceoxx eecxxde xdxc
|
||||
ecc oedddddcxxoxcoeo xcxe
|
||||
eeexcec xxoeeeexxxedxee o
|
||||
xoxeeccccccce eeeoxocoeoe
|
||||
ee oeo eeccocec
|
||||
eecceeo eceeoeoe
|
||||
cxoccccdddecceoeoc
|
||||
cxxeoeeooccdcc
|
||||
e
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eeddcxcddxoe
|
||||
ecxxxeodddeceoxcoo
|
||||
ocddocxcce ecdoecde
|
||||
odxcoee eddcoexco
|
||||
xxoeoe oxecocxe xeo
|
||||
xeocc excxo oo cocx
|
||||
edxxc oceoxcoe odocx
|
||||
xxxx xdcexco x xxx
|
||||
xcxeoddddddxxxxccdcxd e cxx
|
||||
edooxdcoecceoeo ee deeeoooxe
|
||||
cecocxcccccccc eeeoxoo ooc
|
||||
eeecee eooeooc
|
||||
c eexxco oddooxde
|
||||
ccoxcoxceeddocc dcxc
|
||||
cxoedoceooecoe
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eoeddcdddcoe
|
||||
ecoocdcxxxdxxdecxcce
|
||||
oxcxeccxcee eccdcoxxdxo
|
||||
exoeoccooe ooexoxo
|
||||
oecocexeeeee eoxexo
|
||||
cocce xcecoec eexcx
|
||||
oxccx eoxdxexo ocxcx
|
||||
xc ee oxcxxdc xcoox
|
||||
cccdx dxeeexcoxccccccccoxexxc
|
||||
edcx oxxc oc xdeeeeeooeexco x
|
||||
eee c ceooxc ecccccccccxocxx
|
||||
ceeooo e ocdooc
|
||||
oeeexco odec exc
|
||||
exedeecccdddddodceexxc
|
||||
eccccxxeeeexdocc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eecdxxdcdoee
|
||||
oddcdoeodddxxeececo
|
||||
oocecccxcc ecececcxce
|
||||
excecxc eocxeocee
|
||||
ex oxc eo exxecexxe
|
||||
oeoxc cccdxco cexxe
|
||||
dxdcx oc occe oexo
|
||||
xeeoe ccddxco xxcx
|
||||
xoxxdoddddddddeocdeeeec o xe
|
||||
cxexec oeeeeeexe ceecxde oo xx
|
||||
eoeecccccccccc eodxxox oe
|
||||
c ecoo eocoxo
|
||||
eeecoxe odcedcc
|
||||
eooocxceddodcxceoocc
|
||||
eccxe deeeexccc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eeodcddcdcoee
|
||||
occeeeecxdxcdeeocce
|
||||
dceeccece eexcceeco
|
||||
ocxdcc eodcodco
|
||||
oooce oxoee eeeeo
|
||||
ocox occeoo eeeo
|
||||
xcxe e oeooc edec
|
||||
ee ed cxo x x
|
||||
x x ocdddddccc exocxo do x
|
||||
x xe xe eox ececxo ocoo
|
||||
d co eeccc ce cceod oe o
|
||||
cc dde ecc o
|
||||
ce eoe eodcc oe
|
||||
cde ccccdxxdddccc oe
|
||||
cccdceeeeoedcce
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eocdcddcdcoe
|
||||
ecocxoeoxoexxdxcocce
|
||||
odcdxecce ecceccceeco
|
||||
dcxccc ooxxxece
|
||||
exxoc oeoxdxoodcx
|
||||
excoe oxoxdeoe exedx
|
||||
xcceo xcxecoc xxox
|
||||
xxdxe xexxee xexcx
|
||||
xxoco cxddddddcceecxe eo exdc
|
||||
exd ceeeo oocxoox ecdecxoo oed
|
||||
eeeex cccccccce edcceooocoe
|
||||
eceeeo ecocxoc
|
||||
cccd cce eococceo
|
||||
cdccoccxddcddodccccoc
|
||||
cxcxedeeeodeodce
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eocedccccdcee
|
||||
edxcxeeoeddoxexcxce
|
||||
occxcodce cxdcxedxxo
|
||||
odxcdoe eddexxde
|
||||
ooxeoc ooooccocexe
|
||||
oexcoe ecccccoccxxexo
|
||||
exxcx odoo exe c xcc
|
||||
xox x xcxoeeo x cox
|
||||
ece xcxddddddddxecxecee x xxx
|
||||
xeeexcdc oee exeeox eex
|
||||
ocx x eccccccc ceoddxeoeoe
|
||||
oxxexo ooxeeoe
|
||||
e xocoee eocdcoco
|
||||
edecdccexddecccoecce
|
||||
cx cdexeeceecce
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
exedcccddoe
|
||||
oceocxeexddcoecc
|
||||
occdeoccx oedcxcco e
|
||||
ocooooxdoeexoe ecexeec
|
||||
o ooeoo eccoeexeeexoc
|
||||
xoecee cooo oxd oce
|
||||
x xx ooeoocoeexeexe
|
||||
x exx xodoeexxeooexx
|
||||
xo xddddccxxxccecoex x xx
|
||||
e o cxoooddooxoeeccx xcx
|
||||
e cexeccccccce eoocexdooe
|
||||
e eoce x codo
|
||||
eoceexo edceodec
|
||||
oocoeecxxddddxeeoe
|
||||
cdeccdeeeddcc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
ecdcdcccce
|
||||
o coceedexcxxo
|
||||
oxoooocoxcedexxxe
|
||||
xccx o dx cexoceo
|
||||
oeeeoocedoexc xooeoc
|
||||
eoxxxeccoexd oxoxooxo
|
||||
xoxcx xeeoeeoxeoecxdx
|
||||
xxxoxoc xedeoxeexdxxe
|
||||
ecexcxeeddddcxxeexccxe
|
||||
oocxoxoxexxdcexecdoex
|
||||
excoexecccccccoxexoxe
|
||||
xecxdcdeoocdeooooxo
|
||||
eeexeeecdooeoexxo
|
||||
eodeeecdxcc cxc
|
||||
xoccecoecxc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
edccccco
|
||||
ocxdoexcdxo
|
||||
occcxdexecceo
|
||||
dccoxxxexxecoe
|
||||
xeoexoxcceodxed
|
||||
e cxodocceeceeo
|
||||
x ccdxxoxxddcc
|
||||
oo exxxeedxxoxx
|
||||
x oecdcxcddoexx
|
||||
oexooxeeoceecx
|
||||
xecoxcceooecexx
|
||||
eexxoe oocxxe
|
||||
c cxe eeoxoo
|
||||
xcceecceccd
|
||||
eodecxeec
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
dcccco
|
||||
xddoxoe
|
||||
dce cxocx
|
||||
xxxexxdxx
|
||||
x exeocd
|
||||
xeoecexxxe
|
||||
d cxxecxx
|
||||
x exxxdcxx
|
||||
xo o xcxxxx
|
||||
cd ocexecxx
|
||||
xo eecccoc
|
||||
xxccxxeox
|
||||
xddcdooxe
|
||||
eeexedoo
|
||||
cec eeo
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
occd
|
||||
xcexe
|
||||
d dxe
|
||||
xoecx
|
||||
x xx
|
||||
x ocx
|
||||
exx ex
|
||||
xoccx
|
||||
oe ex
|
||||
xxodxx
|
||||
x ex
|
||||
xdcdx
|
||||
xdcxx
|
||||
ceeox
|
||||
x ocx
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
ccccco
|
||||
oxco ce
|
||||
eoxx ccx
|
||||
xxxxeeoo
|
||||
e xcx x
|
||||
xoxxx ee
|
||||
xeexxx e
|
||||
xxdxx
|
||||
xxxcx e
|
||||
exdxx e
|
||||
cxxoxe d
|
||||
xoxxx ex
|
||||
xxxxexex
|
||||
xdxcocxc
|
||||
xxc oo
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eoddccddddoe
|
||||
ecooexxcxcddxdeexcce
|
||||
odocdxccce ecx cccoexo
|
||||
ocoexdoce edc xxe
|
||||
cocxoeoxxcee eeexxe
|
||||
oxeeo ooxedee x eex
|
||||
dc x ccexecxo ocoxo
|
||||
ooxox ooxcoex xexdx
|
||||
occx dxccxxcoxdcceeeccexecdx
|
||||
oedeo oocoddx xcxeeo doodeexexe
|
||||
cex x cxxcoc cccccccccoooooo
|
||||
ccx ec e oeceoo
|
||||
deooceo ocdocoxc
|
||||
decoecceddddoddcdeecc
|
||||
ecccedxeeeexdoec
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
edcccco
|
||||
eodxxeccde
|
||||
ccexoeexcoe
|
||||
xxexoxeexe eo
|
||||
dcxxeexoxo x
|
||||
xcxec cxxxxox
|
||||
eoxxxee eoex de
|
||||
cx ccdxoxcxo e
|
||||
cxecexdxeoxo e
|
||||
cxxexeexx co e
|
||||
exxdeecxxxcxx
|
||||
xcoooocexxc x
|
||||
exexxocxxoxo
|
||||
oeocdeoxooc
|
||||
eooxeeedc
|
||||
eeee
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eodccccdo
|
||||
eccdcoeccecco
|
||||
oxeooodeeocxece
|
||||
oxoceecdeoeexexxe
|
||||
exxxxcoceeocexoee
|
||||
dxeexexccedcoooxocx
|
||||
oxx xecxeododcxcxox
|
||||
eeo xxcxe xeccxxeox
|
||||
xeoexcexxxocxxxe x
|
||||
cxxxooxxeeeeexexx c
|
||||
eceocxo occceoxcxe
|
||||
xxxeeeo edc x
|
||||
dxcde o o xceoe
|
||||
dxexoexeoxcoxe
|
||||
ccdxeccoodc
|
||||
eeee
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
occccddxoe
|
||||
dcxccxexxccxxo
|
||||
oecdeocedoecxcecco
|
||||
cooxeoedo o oeexco o
|
||||
ooxoxceccxd ceoxeoeceo
|
||||
eoeeoecxedxxce xco c
|
||||
cxcdoecexxooxodeoeooxce
|
||||
xxxoe cexxcocxdoecexcce
|
||||
exxoe cexceexcccxxxdxcde
|
||||
ccceexceceeeeeexxcxdxoe
|
||||
oecxxo xccccccedooooo
|
||||
eoxeee oexocx
|
||||
cccxxxce eoexo o
|
||||
eoecxcxddceecceo
|
||||
xddeeococecc
|
||||
eee
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eocdcdcdxoe
|
||||
eccxxecdxdxoxcxco
|
||||
eoexcccodce ccoxxcco
|
||||
oeoxoexoe cxxeec
|
||||
eoxoexxoeee xceee
|
||||
ooo eeeeeeo oeoee
|
||||
xxc eocxexe xcxx
|
||||
cxoo occeodo ecxc
|
||||
xxx x oe ocooodddcxxcoexex
|
||||
eoxccodooexxeeeeexxceeexxo
|
||||
edeo xoxo o ccccccc xxooee
|
||||
ececoco oododo
|
||||
ceccocdo ecxoocec
|
||||
exccecxodcecdoecxc
|
||||
cddcoeeeeccdoc
|
||||
eeee
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eodccccdxoe
|
||||
ecccoedxcxccdccdode
|
||||
eoooxccdxce eeeeoccco
|
||||
ooexceooe cxocee
|
||||
ooxeoox xc o eecee
|
||||
ooexeo eecxece eoexe
|
||||
xcexe ceecxee xdxe
|
||||
exdcd xcexocx o ee
|
||||
ocooc oeooceddccccccxeec xee
|
||||
xxeooooecoocxxxexoeeeooexxexe
|
||||
oeeo xexce ccceeeee oooexc
|
||||
ooeddee odoxoc
|
||||
ecexcedo ecdceooe
|
||||
oeoxcxcodocdcdceccdc
|
||||
cxeddeeeeeddcde
|
||||
eee
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eocddcccdcoe
|
||||
ocdcoxccccxcxdcxcde
|
||||
eooxdccxecce eccdcocxco
|
||||
ooocoodoe cceexe
|
||||
ooxxooe ceco xecxo
|
||||
dodoce cxecooce xeex
|
||||
e oo ee cceo xeee
|
||||
xxxd oeedoc o co
|
||||
o oe oxxodcoxddededcxx xxdc
|
||||
xoedc oodcccoxd eoeeeeocxoc xc
|
||||
oeeocoeexoee eceeeeceecooeox
|
||||
coeeox eoc oe
|
||||
edeedodo odoeccc
|
||||
ceecxcxodxxcxdocceodc
|
||||
cexddeeoeecccce
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eecdccccdcoe
|
||||
edccecodocecdcccccce
|
||||
oeceoccoccee eccxccxocxo
|
||||
exccceeee ccxecx
|
||||
ooedecxeeeoo eeoc
|
||||
o ooe ce cxoo ceec
|
||||
x d e e cee xexo
|
||||
xxex ee eoo ex x
|
||||
xccx oo occcocceccccce xexx
|
||||
ecxe oxeeoxo exeeeeeeexx eoce
|
||||
c cxe cecoe ccceeeeec xoco
|
||||
cocedo ooxco
|
||||
eoxxcxo occcooe
|
||||
coecccdedxecxdcocodcc
|
||||
eccoxeooeooccccc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eoddcddcdcoe
|
||||
eocccxo xedocdxcocoe
|
||||
ocdxxxccce eexeecxoeee
|
||||
ooxoxcoco cxccece
|
||||
oxoexdxedexo ecexce
|
||||
oxxex cexxoce c edxo
|
||||
cexde ccceccxo o cdx
|
||||
xoe oxocexx xxx
|
||||
ex xe dxoceoocxccceeeeoo xxc
|
||||
xeo x oooooexedexooeodoedxoocx
|
||||
exdceoeeoeo ccccccccceoxxxe
|
||||
oxecxee oedoccc
|
||||
eeode oe eoeocdxo
|
||||
xxxdecceddddocdccexce
|
||||
ceexdxeeeeedoce
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eodddcdddcoe
|
||||
ecccocoxxcxdcdexcco
|
||||
ceoecxcce cedxce oco
|
||||
oxoxoxodo oexxxxe
|
||||
oeocoeecxeeo e exexe
|
||||
xxxxo eexedoxe coxx
|
||||
xox c eeexecxo ccxcxo
|
||||
xoxec oedxoex cxex
|
||||
xoxec oexcoxcdexcxeeecoecxox
|
||||
eexeoooccc xc ooedeodoooxocxe
|
||||
eoxxoxoeeoce ccccccccoxdxeo
|
||||
eecoee e oeocoe
|
||||
eocexdce edcoccdc
|
||||
excxoccedxdeocdcexdc
|
||||
eocecceeeoeocce
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eodddcddccee
|
||||
oedocxdccxccdeocce
|
||||
oooxxxcc ecxodcccoee
|
||||
ooxcxcedo ecxxxxo
|
||||
cdxxxceecce oeexeo
|
||||
dooxoeecdxeexo odeox
|
||||
e cxx eexoee ecxex
|
||||
x xxx exdxoxx xcexx
|
||||
eoxox ocxxcdocexcxeecceoeox
|
||||
xxeooeeedc xodcoxxodddexoxe
|
||||
o x oxxxdoc cccccccceeeox
|
||||
o d ooe odeooxe
|
||||
oeeecco eceeococ
|
||||
ecxcocc dxeeoccc ddc
|
||||
eodccoeeeeeocc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eoxdccddcoe
|
||||
ocecexcccdded eco
|
||||
c oxxxce eexe coeco
|
||||
eexxxxdc execxoo
|
||||
ecxcxxexoeo o cxxe
|
||||
x dxxc ecedxe ooxxx
|
||||
eecx eexexex ccexx
|
||||
ecoxx dcoxcxe c xxx
|
||||
ocxc oceoxeoxxddexxddcexx
|
||||
xocxxddxxocxoexxeeododexex
|
||||
e deocxceo cccccccceoxx
|
||||
ce oeoee ocoodoc
|
||||
cdoceeee oexococc
|
||||
eecexcedxeeeccxcco
|
||||
cxccxdxeeoedcc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
eecedccdcoe
|
||||
occoxxxcdd x cc
|
||||
exdoxooc ocxoxceceo
|
||||
ececoxocx c dexxe
|
||||
c oxooexoe ocexxo
|
||||
xcoxeeeeexec ecxxx
|
||||
xcxxx cedexex xexoxo
|
||||
eoxxo xceoxoco oeoxx
|
||||
e exxee ocdxxococooexxx
|
||||
ecodexcoxoxxdxdeexxdc
|
||||
ooeexexxxocececceccoex
|
||||
cocxexee oooooc
|
||||
ceeceeee eoeexcoc
|
||||
odcxoc ddccdodoxe
|
||||
xxeccexeocode
|
||||
ee
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
odecoccdo
|
||||
oceoxxccd eoee
|
||||
o oxxoceedo eexo
|
||||
c xxodde eeoxeexco
|
||||
occdeccxco coccdcxx
|
||||
x xxxcexedee xcxcxxx
|
||||
e xcexccxeeocooo exx
|
||||
x xoeoexxxeodeex xx
|
||||
coxc oxcxxxxcxxoxxe
|
||||
xexxxeoxexexxxxeexxx
|
||||
c eeoeexocccccxxcoex
|
||||
exxxeoe oo eoxe
|
||||
ecexee odedxoc
|
||||
eoceexcocdddcxe
|
||||
coe ceexdcoc
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
_._:=++==+,_
|
||||
_=,/*\+/+\=||=_ _"+_
|
||||
,|*|+**"^` `"*`"~=~||+
|
||||
;*_\*',,_ /*|;|,
|
||||
\^;/'^|\`\\ ".|\\,
|
||||
~* +` |*/;||, '.\||,
|
||||
+^"-* '\|*/"|_ ! |/|
|
||||
||_|` ,//|;|* "`|
|
||||
|=~'` ;||^\|".~++++++_+, =" |
|
||||
_~;* _;+` /* |"|___.:,,,|/,/,|
|
||||
\^_"^ ^\,./` `^*''* ^*"/,;_/
|
||||
*^, ", ` ,'/*_|
|
||||
^\,`\+_ _=_+|_+"
|
||||
^*,\_!*+:;=;;.=*+_,|*
|
||||
`*"*|~~___,_;+*"
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
_+***\++_
|
||||
*'`+*+\~/_*,
|
||||
^_,||/~~-~+\,,
|
||||
|__/\|;_.\,''\\,
|
||||
/ ;||"|^ /_/|/
|
||||
|` '|*~//\ `_"|
|
||||
\ ~*"*||~|* |/,
|
||||
" ||\+/+||-_ .\||
|
||||
" ~\ \\|;~~+\+;||
|
||||
| ,|\,|_/_*___|*`
|
||||
, "|||||""!\,"\|`
|
||||
\`',\,*" "",//
|
||||
|' |||~*,:,/|/`
|
||||
;`**/|+;_!//'
|
||||
*, _*\_,;*
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
,****++_
|
||||
/" ;|||\\,
|
||||
/"__||;\*/\,
|
||||
|__||=;,_=//
|
||||
_".;\|+\';_||,
|
||||
|+`||+_;;|_/||
|
||||
** ,||||||_|=\
|
||||
| ||/||\/ |"|
|
||||
/ '|/||*/+|_|
|
||||
** _|/=,"/|_|^
|
||||
'`- ||||=/|\\|
|
||||
\_-/|_*/**;|`
|
||||
!_ *|\\^_|;"
|
||||
\+!*||,_/*`
|
||||
\_ '*+_+`
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
+***+.
|
||||
,=`_/|,\
|
||||
" |/\+,
|
||||
/+~||=="|
|
||||
| '~|||./|
|
||||
|'..*^"_|"
|
||||
| ~/\||\
|
||||
| /+\||"
|
||||
*, ~/||+|~
|
||||
| /|*;*_
|
||||
|. |"=**/
|
||||
, *|!_,|
|
||||
/ **|,*\|
|
||||
'^/",|\|`
|
||||
\ '~\./
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
/***,
|
||||
|__||
|
||||
|`_|"
|
||||
|**|_
|
||||
* ||
|
||||
":-||
|
||||
, ||
|
||||
+ "|
|
||||
/+ _~.
|
||||
|" +=|
|
||||
'`.. ~`
|
||||
|___|
|
||||
|+,|_
|
||||
*__|=
|
||||
, ."=
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
+***;
|
||||
,/__.\
|
||||
|_||. |
|
||||
||/|"^~,
|
||||
|||\ |
|
||||
~*|| '|
|
||||
|||| . *
|
||||
||\|` \
|
||||
|||~ "
|
||||
"^// ;/
|
||||
\|"",.,|
|
||||
|*~|___|
|
||||
/!"|===`
|
||||
|\/*__/
|
||||
_* '=/
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
++***~_
|
||||
`,=||^:*,
|
||||
//|*=\|"*|
|
||||
|/` //,.__|
|
||||
||="=\||/"^|
|
||||
\||-||//| "
|
||||
|| ||||~~,|
|
||||
||/~|+||| '-|
|
||||
||+,,*|||_.:|
|
||||
|_|;/|\~*. .|
|
||||
|/||||_| ` ;
|
||||
|**.^~|\- =
|
||||
'|\, ///` ;`
|
||||
|^||\\.+\/
|
||||
\^*^___/
|
||||
``
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
_=+"**+~_
|
||||
/^||*||\|=\
|
||||
|//"\/=\|| '\
|
||||
/// ;' \|\||**|
|
||||
||;_ =||*/|`\
|
||||
|||*| /|= !| ~.|
|
||||
\\| ,||||/*", |
|
||||
|/; |`||/|||"; `|
|
||||
\\|~|+~/^||"*+ /
|
||||
*"__,==\*|._| ,_|
|
||||
|||+""/*\|;";.~|`
|
||||
||* | `//, /
|
||||
\|* | /,/_,|
|
||||
\|~"_*~//+_|
|
||||
':._=:__;*
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
,=+++;;~,_
|
||||
_;**|~~*=*|,"^,
|
||||
,*\/_==`+,"|||_"\
|
||||
/|/_/|" |;\~||=\
|
||||
|/_ ~ "/\=\// ,
|
||||
`=*,/` ,:/| /,=/|./
|
||||
*!;/| ,//|_ *"||/=|
|
||||
-"=|! !//||/ ,||=;*
|
||||
,/*/\==+~\_|\^:\||| |
|
||||
|"_;__|/*\/||\!\+'+\
|
||||
\\\/"""****\_|*//\ \'
|
||||
\||_* `/||` ;
|
||||
_\\!*\_ ,',/^_/
|
||||
, ~*+=\+`_;*:|'
|
||||
`+;/_,+~*_+*
|
||||
`
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
_==+==+;~,_
|
||||
_+"_;,++~__,"+;;_
|
||||
_/:|*"*=" "._"+//\ *
|
||||
,||*.,^" _/=~\;\\\,
|
||||
_\// /| _\/~/|_\;\\_
|
||||
/\| ,, _/,*,|'-/^/`/~!
|
||||
||\:/ +/*/|"_/"*|=|=,
|
||||
"\-~| ^\"||;^ |;|"
|
||||
\"" ,\==;=;+~|,|*/\, |*|`
|
||||
_\\|*\* ~|/__\_~||_;~`\ ,
|
||||
|/|\`""*****` \__/|/*/`-`
|
||||
\\!,\, ``*"/*_'
|
||||
\^*+^^. _*^_/\,`
|
||||
'|.**++===^'*_/_,*
|
||||
"~|_/__,.+";+"
|
||||
`
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
__==+~+==~._
|
||||
_+|||\/===_*_,|*,,
|
||||
,*;;/"|+*` `*:,`*;\
|
||||
/;|*,^` _==+,^|*,
|
||||
||/`/` ,|^"/"|\ |\,
|
||||
|\/*' _|*~/!./ '.*|
|
||||
^=|~' /*^/|+,` /:/+|
|
||||
|||| |;"\|", | |||
|
||||
|*|\,=;;===~~~|+*;*|; \ "||
|
||||
^;/,|=*/^*+\,`, ^_ :\_\,/.|_
|
||||
'\"/+|"""""**" ^\_/|// //'
|
||||
\\^*_\ `//_//'
|
||||
'!_\~~*, ,;=./|;`
|
||||
'".|*/~+__=;/*" ;*~'
|
||||
"~._:-'_,.^*-^
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
_._:=+===+,_
|
||||
_+,/*;+||~=~|=_'|*+_
|
||||
,|*|\**~*`` `"*=*/||;|,
|
||||
_|/_/*',,_ -,\|/|,
|
||||
,^"/*^|\_\\_ ^,|\|,
|
||||
'/+"` |*\+/\+ \\|*|
|
||||
,|'*| ^/|;|_|, /"|"|
|
||||
|" \` ,|*||;* |'/.|
|
||||
*""=| ;|^^_|".~++++++++,|_|~*
|
||||
_='| /||' /* |=\____..__|+/!|!
|
||||
\\\ * *\..|' `"*******"|,*||
|
||||
'\_./, ` ,+;/,*
|
||||
.\__|+, ,=_+!_|"
|
||||
`~^;__"*+:;=;;.=*`_||*
|
||||
`*+*+~~____~;/*"
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
__+=~~=+=,__
|
||||
,;=";,_,===||_^*\+,
|
||||
,,"_+*"~*" `"^"\+*|+_
|
||||
_|"_*|* _,+|\/*\\
|
||||
_| ,|* _/!_||^*\||\
|
||||
/`,|' +*';|"/ '\~|\
|
||||
;|;+| ,* .+*^ ,\|/
|
||||
|_^/` "";:|", |~"|
|
||||
|/||;,=;======_,';^^\\* / |\
|
||||
'|^|_" /``____|\ *\\"|=\ ,/ ||
|
||||
\,^\'"""""""*" \,=||,| /\
|
||||
* ^*/, _/*.|/
|
||||
\_^*,~_ ,;*`;*'
|
||||
^,-."~+^;;,:"~"`,/*'
|
||||
`*+~_!=____|*""
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user