summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNamilskyy <alive6863@gmail.com>2025-04-01 22:29:47 +0300
committerNamilskyy <alive6863@gmail.com>2025-04-01 22:31:49 +0300
commitc9bca4946f43629e9b5a3f6549dc3851c6e713b3 (patch)
tree5548312adc31c3299f1c74d7b0dee6589ff0214e
parent0b069b828d117655053bd8972e32424ec78cbdb5 (diff)
Implemented the scrolling fucntion
-rw-r--r--Cargo.lock556
-rw-r--r--render1.rs117
-rw-r--r--src/hex.rs48
-rw-r--r--src/input.rs25
-rw-r--r--src/render.rs133
5 files changed, 833 insertions, 46 deletions
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..021dd8e
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,556 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "bitflags"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
+[[package]]
+name = "castaway"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "compact_str"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
+dependencies = [
+ "castaway",
+ "cfg-if",
+ "itoa",
+ "ryu",
+ "static_assertions",
+]
+
+[[package]]
+name = "crossterm"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
+dependencies = [
+ "bitflags",
+ "crossterm_winapi",
+ "libc",
+ "mio",
+ "parking_lot",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "libc"
+version = "0.2.171"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
+
+[[package]]
+name = "lru"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
+dependencies = [
+ "hashbrown",
+]
+
+[[package]]
+name = "mew"
+version = "0.2.0"
+dependencies = [
+ "crossterm",
+ "ratatui",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "ratatui"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef"
+dependencies = [
+ "bitflags",
+ "cassowary",
+ "compact_str",
+ "crossterm",
+ "itertools 0.12.1",
+ "lru",
+ "paste",
+ "stability",
+ "strum",
+ "unicode-segmentation",
+ "unicode-truncate",
+ "unicode-width",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "signal-hook"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+
+[[package]]
+name = "stability"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "unicode-truncate"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
+dependencies = [
+ "itertools 0.13.0",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/render1.rs b/render1.rs
new file mode 100644
index 0000000..3f92c20
--- /dev/null
+++ b/render1.rs
@@ -0,0 +1,117 @@
+use std::io;
+use ratatui::{
+ layout::{Constraint, Direction, Layout},
+ style::{Color, Style},
+ text::{Line, Span},
+ widgets::{
+ Block, Borders, Paragraph, ScrollbarState, Scrollbar, ScrollbarOrientation,
+ },
+ Terminal,
+ prelude::Alignment,
+ symbols,
+};
+
+pub fn draw(
+ terminal: &mut Terminal<impl ratatui::backend::Backend>,
+ data: &[u8],
+ cursor: usize,
+ filename: &str,
+ scrollbar_state: &mut ScrollbarState,
+) -> io::Result<()> {
+ terminal.draw(|frame| {
+ let size = frame.size();
+ let layout = Layout::default()
+ .direction(Direction::Vertical)
+ .constraints([Constraint::Min(1), Constraint::Length(1)])
+ .split(size);
+
+ // Исправление: Устанавливаем длину содержимого скролла
+ let content_length = data.len() * 2; // 2 символа на байт
+ scrollbar_state.content_length(content_length);
+
+ let visible_lines = layout[0].height as usize;
+ scrollbar_state.viewport_content_length(visible_lines);
+
+ let lines: Vec<Line> = data.chunks(16).enumerate().map(|(i, chunk)| {
+ let addr = Span::raw(format!("{:08x} │ ", i * 16));
+ let mut hex: Vec<Span> = Vec::new();
+ let mut ascii_repr = String::new();
+
+ for (j, &byte) in chunk.iter().enumerate() {
+ let hex_str = format!("{:02x}", byte);
+ let byte_index = i * 16 + j; // Индекс байта в данных
+ let cursor_byte = cursor / 2; // Байт, на котором находится курсор
+
+ for (k, ch) in hex_str.chars().enumerate() {
+ let cur_idx = byte_index * 2 + k; // Индекс символа в hex-строке
+ let style = if cur_idx == cursor {
+ Style::default().bg(Color::White).fg(Color::Black)
+ } else {
+ Style::default()
+ };
+ hex.push(Span::styled(ch.to_string(), style));
+ }
+
+ if j < 15 {
+ let space = if j % 4 == 3 { " " } else { " " };
+ hex.push(Span::raw(space));
+ }
+
+ ascii_repr.push(if byte.is_ascii_graphic() || byte == b' ' {
+ byte as char
+ } else {
+ '.'
+ });
+ }
+
+ let missing_bytes = 16 - chunk.len();
+ let padding = missing_bytes * 3;
+ let spaces = " ".repeat(padding);
+
+ let ascii = Span::raw(format!("{} │ {}", spaces, ascii_repr));
+
+ Line::from(
+ vec![addr]
+ .into_iter()
+ .chain(hex)
+ .chain(std::iter::once(ascii))
+ .collect::<Vec<_>>()
+ )
+ }).collect();
+
+ frame.render_widget(
+ Paragraph::new(lines).block(Block::default().borders(Borders::ALL)),
+ layout[0]
+ );
+
+ frame.render_stateful_widget(
+ Scrollbar::default()
+ .orientation(ScrollbarOrientation::VerticalRight)
+ .symbols(symbols::scrollbar::VERTICAL),
+ layout[0],
+ scrollbar_state,
+ );
+
+ // Исправление: Корректное вычисление прогресса
+ let progress = if data.is_empty() {
+ 100
+ } else {
+ let cursor_byte = cursor / 2;
+ (cursor_byte * 100).saturating_div(data.len())
+ };
+
+ let status_text = format!(
+ "{} \t 0x{:08x} \t {:3}%",
+ filename,
+ cursor / 2,
+ progress
+ );
+
+ let status_bar = Paragraph::new(
+ Line::from(Span::raw(status_text))
+ ).alignment(Alignment::Center);
+
+ frame.render_widget(status_bar, layout[1]);
+ })?;
+ Ok(())
+} \ No newline at end of file
diff --git a/src/hex.rs b/src/hex.rs
index 67f692d..7980252 100644
--- a/src/hex.rs
+++ b/src/hex.rs
@@ -1,27 +1,64 @@
use std::{fs, io};
use std::io::stdout;
use ratatui::{backend::CrosstermBackend, Terminal};
+use ratatui::widgets::{ScrollbarState, ScrollDirection};
use crossterm::{execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}};
use crate::{input, render};
-
+
pub struct HexEditor {
filename: String,
data: Vec<u8>,
cursor: usize,
- terminal: Terminal<CrosstermBackend<std::io::Stdout>>,
+ terminal: Terminal<CrosstermBackend<std::io::Stdout>,>,
+ scrollbar_state: ScrollbarState,
+ scroll_position: usize
}
impl HexEditor {
+
pub fn new(filename: String, data: Vec<u8>) -> io::Result<Self> {
enable_raw_mode()?;
execute!(stdout(), EnterAlternateScreen)?;
let terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
- Ok(Self { filename, data, cursor: 0, terminal })
+ let line_count = (data.len() + 15) / 16;
+ let scrollbar_state = ScrollbarState::default()
+ .content_length(line_count)
+ .viewport_content_length(10);
+
+ Ok(Self {
+ filename,
+ data,
+ cursor: 0,
+ terminal,
+ scrollbar_state,
+ scroll_position: 0,
+ })
}
+
pub fn run(&mut self) -> io::Result<()> {
- while input::handle_input(&mut self.cursor, &mut self.data[..])? {
- render::draw(&mut self.terminal, &self.data, self.cursor, &self.filename)?;
+ while input::handle_input(
+ &mut self.cursor,
+ &mut self.data,
+ &mut self.scroll_position
+ )? {
+ let total_lines = (self.data.len() + 15) / 16;
+ let visible_lines = self.terminal.size()?.height as usize;
+
+
+ self.scrollbar_state = ScrollbarState::new(total_lines)
+ .viewport_content_length(visible_lines)
+ .position(self.scroll_position);
+
+
+ render::draw(
+ &mut self.terminal,
+ &self.data,
+ self.cursor,
+ &self.filename,
+ self.scroll_position,
+ &mut self.scrollbar_state
+ )?;
}
self.cleanup()
}
@@ -32,4 +69,5 @@ impl HexEditor {
fs::write(&self.filename, &self.data)?;
Ok(())
}
+
}
diff --git a/src/input.rs b/src/input.rs
index 0db7e16..1258ac0 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -1,20 +1,35 @@
use std::{io, time::Duration};
use crossterm::{event::{self, KeyCode, KeyEvent}};
-pub fn handle_input(cursor: &mut usize, data: &mut [u8]) -> io::Result<bool> {
+pub fn handle_input(
+ cursor: &mut usize,
+ data: &mut [u8],
+ scroll_position: &mut usize
+) -> io::Result<bool> {
if event::poll(Duration::from_millis(100))? {
if let event::Event::Key(KeyEvent { code, .. }) = event::read()? {
match code {
KeyCode::Esc => return Ok(false),
KeyCode::Left if *cursor > 0 => *cursor -= 1,
KeyCode::Right if *cursor < data.len() * 2 - 1 => *cursor += 1,
- KeyCode::Up if *cursor >= 32 => *cursor -= 32,
- KeyCode::Down if *cursor + 32 < data.len() * 2 => *cursor += 32,
+ KeyCode::Up => {
+ if *cursor >= 32 {
+ *cursor -= 32;
+ *scroll_position = scroll_position.saturating_sub(1);
+ }
+ },
+ KeyCode::Down => {
+ if *cursor + 32 < data.len() * 2 {
+ *cursor += 32;
+ *scroll_position = scroll_position.saturating_add(1);
+ }
+ },
KeyCode::Char(c) if c.is_ascii_hexdigit() => {
let byte_index = *cursor / 2;
let shift = if *cursor % 2 == 0 { 4 } else { 0 };
- data[byte_index] = (data[byte_index] & (0x0F << (4 - shift))) | (c.to_digit(16).unwrap() as u8) << shift;
- }
+ data[byte_index] = (data[byte_index] & (0x0f << (4 - shift)))
+ | (c.to_digit(16).unwrap() as u8) << shift;
+ },
_ => {}
}
}
diff --git a/src/render.rs b/src/render.rs
index a0cb234..061dbfe 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -3,12 +3,22 @@ use ratatui::{
layout::{Constraint, Direction, Layout},
style::{Color, Style},
text::{Line, Span},
- widgets::{Block, Borders, Paragraph},
+ widgets::{
+ Block, Borders, Paragraph, ScrollbarState, Scrollbar, ScrollbarOrientation,
+ },
Terminal,
prelude::Alignment,
+ symbols,
};
-pub fn draw(terminal: &mut Terminal<impl ratatui::backend::Backend>, data: &[u8], cursor: usize, filename: &str) -> io::Result<()> {
+pub fn draw(
+ terminal: &mut Terminal<impl ratatui::backend::Backend>,
+ data: &[u8],
+ cursor: usize,
+ filename: &str,
+ scroll_position: usize,
+ scrollbar_state: &mut ScrollbarState,
+) -> io::Result<()> {
terminal.draw(|frame| {
let size = frame.size();
let layout = Layout::default()
@@ -16,52 +26,103 @@ pub fn draw(terminal: &mut Terminal<impl ratatui::backend::Backend>, data: &[u8]
.constraints([Constraint::Min(1), Constraint::Length(1)])
.split(size);
- let lines: Vec<Line> = data.chunks(16).enumerate().map(|(i, chunk)| {
- let addr = Span::raw(format!("{:08x} │ ", i * 16));
- let mut hex: Vec<Span> = Vec::new();
- let mut ascii_repr = String::new();
- for (j, &byte) in chunk.iter().enumerate() {
- let hex_str = format!("{:02x}", byte);
- let index = i * 32 + j * 2;
+ let total_lines = (data.len() + 15) / 16;
+ let visible_height = layout[0].height as usize;
- for (k, ch) in hex_str.chars().enumerate() {
- let cur_idx = index + k;
- let style = if cur_idx == cursor {
- Style::default().bg(Color::White).fg(Color::Black)
+ *scrollbar_state = ScrollbarState::new(total_lines)
+ .viewport_content_length(visible_height)
+ .position(scroll_position);
+
+ let lines: Vec<Line> = data
+ .chunks(16)
+ .enumerate()
+ .skip(scroll_position)
+ .take(visible_height)
+ .map(|(i, chunk)| {
+ let addr = format!("{:08X} │ ", i * 16);
+ let mut hex_spans = Vec::new();
+ let mut ascii = String::new();
+
+ for (j, &byte) in chunk.iter().enumerate() {
+ let global_pos = i * 16 + j;
+ let nibbles = format!("{:02X}", byte);
+
+ for (k, c) in nibbles.chars().enumerate() {
+ let is_cursor = (global_pos * 2 + k) == cursor;
+ let style = if is_cursor {
+ Style::default().bg(Color::White).fg(Color::Black)
+ } else {
+ Style::default()
+ };
+ hex_spans.push(Span::styled(c.to_string(), style));
+ }
+
+
+ if j < 15 {
+ hex_spans.push(Span::raw(if j % 4 == 3 { " " } else { " " }));
+ }
+
+
+ ascii.push(if byte.is_ascii_graphic() || byte == b' ' {
+ byte as char
} else {
- Style::default()
- };
- hex.push(Span::styled(ch.to_string(), style));
+ '.'
+ });
}
- if j < 15 {
- let space = if j % 4 == 3 { " " } else { " " };
- hex.push(Span::raw(space));
+
+ if chunk.len() < 16 {
+ let missing = 16 - chunk.len();
+ hex_spans.push(Span::raw(" ".repeat(missing * 3)));
+ ascii.push_str(&".".repeat(missing));
}
- ascii_repr.push(if byte.is_ascii_graphic() || byte == b' ' { byte as char } else { '.' });
- }
+ Line::from(vec![
+ Span::raw(addr),
+ Span::raw(hex_spans.iter().map(|s| s.content.as_ref()).collect::<String>()),
+ Span::raw(" │ "),
+ Span::raw(ascii),
+ ])
+ })
+ .collect();
+
+
+ frame.render_widget(
+ Paragraph::new(lines)
+ .block(Block::default().borders(Borders::ALL)),
+ layout[0]
+ );
+
- let missing_bytes = 16 - chunk.len();
- let padding = missing_bytes * 3;
- let spaces = " ".repeat(padding);
+ frame.render_stateful_widget(
+ Scrollbar::default()
+ .orientation(ScrollbarOrientation::VerticalRight)
+ .symbols(symbols::scrollbar::VERTICAL),
+ layout[0],
+ scrollbar_state,
+ );
- let ascii = Span::raw(format!("{} │ {}", spaces, ascii_repr));
- Line::from(vec![addr]
- .into_iter()
- .chain(hex)
- .chain(std::iter::once(ascii))
- .collect::<Vec<_>>())
- }).collect();
+ let progress = if data.is_empty() {
+ 0
+ } else {
+ (cursor / 2 * 100) / data.len()
+ };
- frame.render_widget(Paragraph::new(lines).block(Block::default().borders(Borders::ALL)), layout[0]);
+ let status = format!(
+ "{} │ Offset: 0x{:08X} │ {}%",
+ filename,
+ cursor / 2,
+ progress
+ );
- let progress = if data.is_empty() { 100 } else { (cursor / 2 * 100) / data.len() };
- let status_text = format!("{} \t 0x{:08x} \t {:3}%", filename, cursor / 2, progress);
- let status_bar = Paragraph::new(Line::from(Span::raw(status_text))).alignment(Alignment::Center);
- frame.render_widget(status_bar, layout[1]);
+ frame.render_widget(
+ Paragraph::new(status)
+ .alignment(Alignment::Center)
+ .block(Block::default().borders(Borders::TOP)),
+ layout[1]
+ );
})?;
Ok(())
}