1
1
use ratatui:: {
2
2
layout:: { Constraint , Flex , Layout , Rect } ,
3
3
style:: { Color , Style , Stylize } ,
4
+ text:: { Line , Span } ,
4
5
widgets:: { Block , Borders , Clear , Paragraph , Scrollbar , ScrollbarOrientation } ,
5
6
Frame ,
6
7
} ;
7
8
8
9
use crate :: App ;
9
10
10
- use super :: { ORANGE , SCROLL_CONTROL_TEXT , YELLOW } ;
11
+ use super :: { BLUE , DARK_GRAY , GREEN , ORANGE , SCROLL_CONTROL_TEXT , YELLOW } ;
11
12
12
- fn to_hexdump_str ( data : & [ u8 ] ) -> String {
13
- data. chunks ( 16 )
14
- . enumerate ( )
15
- . map ( |( i, chunk) | {
16
- let address = format ! ( "{:08x}:" , i * 16 ) ;
17
- let hex_values =
18
- chunk. iter ( ) . map ( |byte| format ! ( "{:02x}" , byte) ) . collect :: < Vec < _ > > ( ) . join ( " " ) ;
19
- let ascii_values = chunk
20
- . iter ( )
21
- . map ( |& byte| if byte. is_ascii_graphic ( ) { byte as char } else { '.' } )
22
- . collect :: < String > ( ) ;
23
- format ! ( "{:<10} {:48} |{}|" , address, hex_values, ascii_values)
24
- } )
25
- . collect :: < Vec < _ > > ( )
26
- . join ( "\n " )
13
+ fn to_hexdump_str ( buffer : & [ u8 ] ) -> Vec < Line > {
14
+ let mut lines = Vec :: new ( ) ;
15
+ for ( offset, chunk) in buffer. chunks ( 16 ) . enumerate ( ) {
16
+ let mut hex_spans = Vec :: new ( ) ;
17
+ // bytes
18
+ for byte in chunk. iter ( ) {
19
+ let color = color ( * byte) ;
20
+ hex_spans. push ( Span :: styled ( format ! ( "{:02x} " , byte) , Style :: default ( ) . fg ( color) ) ) ;
21
+ }
22
+
23
+ // ascii
24
+ hex_spans. push ( Span :: raw ( "| " ) ) ;
25
+ for byte in chunk. iter ( ) {
26
+ let ascii_char = if byte. is_ascii_graphic ( ) { * byte as char } else { '.' } ;
27
+ let color = color ( * byte) ;
28
+ hex_spans. push ( Span :: styled ( ascii_char. to_string ( ) , Style :: default ( ) . fg ( color) ) ) ;
29
+ }
30
+
31
+ let line = Line :: from_iter (
32
+ vec ! [ Span :: raw( format!( "{:08x}: " , offset * 16 ) ) , Span :: raw( "" ) ]
33
+ . into_iter ( )
34
+ . chain ( hex_spans) ,
35
+ ) ;
36
+
37
+ lines. push ( line) ;
38
+ }
39
+
40
+ lines
41
+ }
42
+
43
+ fn color ( byte : u8 ) -> Color {
44
+ if byte == 0x00 {
45
+ DARK_GRAY
46
+ } else if byte. is_ascii_graphic ( ) {
47
+ BLUE
48
+ } else if byte. is_ascii_whitespace ( ) {
49
+ GREEN
50
+ } else if byte. is_ascii ( ) {
51
+ ORANGE
52
+ } else {
53
+ YELLOW
54
+ }
27
55
}
28
56
29
57
fn popup_area ( area : Rect , percent_x : u16 ) -> Rect {
@@ -49,18 +77,16 @@ pub fn draw_hexdump(app: &mut App, f: &mut Frame, hexdump: Rect, show_popup: boo
49
77
pos = format ! ( "(0x{:02x?})" , r. 0 ) ;
50
78
let data = & r. 1 ;
51
79
52
- let data = to_hexdump_str ( data) ;
53
- let lines = data. lines ( ) ;
54
- let len = lines. count ( ) ;
80
+ let lines = to_hexdump_str ( data) ;
81
+ let len = lines. len ( ) ;
55
82
56
83
let max = hexdump. height ;
57
84
let skip = if len <= max as usize { 0 } else { app. hexdump_scroll } ;
85
+ let lines: Vec < Line > = lines. into_iter ( ) . skip ( skip) . collect ( ) ;
58
86
app. hexdump_scroll_state = app. hexdump_scroll_state . content_length ( len) ;
87
+ let paragraph =
88
+ Paragraph :: new ( lines) . block ( block ( & pos) ) . style ( Style :: default ( ) . fg ( Color :: White ) ) ;
59
89
60
- let lines: Vec < & str > = data. lines ( ) . skip ( skip) . collect ( ) ;
61
- let paragraph = Paragraph :: new ( lines. join ( "\n " ) )
62
- . block ( block ( & pos) )
63
- . style ( Style :: default ( ) . fg ( Color :: White ) ) ;
64
90
f. render_widget ( paragraph, hexdump) ;
65
91
f. render_stateful_widget (
66
92
Scrollbar :: new ( ScrollbarOrientation :: VerticalRight ) ,
0 commit comments