@@ -8,11 +8,13 @@ mod terminal;
88use crate :: model:: { Model , Screen } ;
99use crate :: props:: Props ;
1010use crate :: raw_json_lines:: { RawJsonLines , SourceName } ;
11- use anyhow:: anyhow;
11+ use anyhow:: { Context , anyhow} ;
1212use clap:: Parser ;
13+ use ratatui:: prelude:: Backend ;
14+ use ratatui:: Terminal ;
1315use std:: fs:: File ;
1416use std:: io;
15- use std:: io:: { BufRead , Write } ;
17+ use std:: io:: BufRead ;
1618use std:: path:: { Path , PathBuf } ;
1719
1820#[ derive( Parser , Debug ) ]
@@ -36,21 +38,35 @@ struct Args {
3638
3739fn main ( ) -> anyhow:: Result < ( ) > {
3840 let args = Args :: parse ( ) ;
39- let props: Props = init_props ( & args) ?;
41+ let props: Props = init_props ( & args) . context ( "failed to init props" ) ?;
4042
41- let lines = load_files ( & args. files ) ?;
43+ let lines = load_files ( & args. files ) . context ( "failed to load files" ) ?;
4244
4345 terminal:: install_panic_hook ( ) ;
44- let mut terminal = terminal:: init_terminal ( ) ?;
46+ let terminal = terminal:: init_terminal ( ) . context ( "failed to initialize terminal" ) ?;
4547
46- let mut model = Model :: new ( props, terminal. size ( ) . map_err ( |e| anyhow ! ( "{e}" ) ) ?, & lines) ;
48+ if let Err ( err) = run_app ( terminal, props, lines) {
49+ eprintln ! ( "{err:?}" ) ;
50+ }
51+
52+ terminal:: restore_terminal ( ) . context ( "failed to restore terminal state" ) ?;
53+
54+ Ok ( ( ) )
55+ }
56+
57+ fn run_app ( mut terminal : Terminal < impl Backend > , props : Props , lines : RawJsonLines ) -> Result < ( ) , anyhow:: Error > {
58+ let terminal_size = terminal. size ( ) . map_err ( |e| anyhow ! ( "{e}" ) ) . context ( "failed to get terminal size" ) ?;
59+ let mut model = Model :: new ( props, terminal_size, & lines) ;
4760
4861 while model. active_screen != Screen :: Done {
4962 // Render the current view
50- terminal. draw ( |f| terminal:: view ( & mut model, f) ) . map_err ( |e| anyhow ! ( "{e}" ) ) ?;
63+ terminal
64+ . draw ( |f| terminal:: view ( & mut model, f) )
65+ . map_err ( |e| anyhow ! ( "{e}" ) )
66+ . context ( "failed to draw to terminal" ) ?;
5167
5268 // Handle events and map to a Message
53- let mut current_msg = event:: handle_event ( & model) ?;
69+ let mut current_msg = event:: handle_event ( & model) . context ( "failed to handle event" ) ?;
5470
5571 // Process updates as long as they return a non-None message
5672 while let Some ( msg) = current_msg {
@@ -60,29 +76,32 @@ fn main() -> anyhow::Result<()> {
6076 }
6177 }
6278
63- terminal:: restore_terminal ( ) ?;
6479 Ok ( ( ) )
6580}
6681
82+
6783fn init_props ( args : & Args ) -> anyhow:: Result < Props > {
68- let mut props = Props :: init ( ) ?;
84+ let mut props = Props :: init ( ) . context ( "failed to load props" ) ?;
85+
6986 if let Some ( e) = & args. field_order {
7087 props. fields_order = e. clone ( ) ;
7188 }
89+
7290 if let Some ( e) = & args. suppressed_fields {
7391 props. fields_suppressed = e. clone ( ) ;
7492 }
93+
7594 Ok ( props)
7695}
7796
7897fn load_files ( files : & [ PathBuf ] ) -> anyhow:: Result < RawJsonLines > {
7998 let mut raw_lines = RawJsonLines :: default ( ) ;
80- for f in files {
81- let path = PathBuf :: from ( f ) ;
82- match path. extension ( ) . map ( |e| e. to_str ( ) ) {
83- Some ( Some ( "json" ) ) => load_lines_from_json ( & mut raw_lines, & path) ?,
84- Some ( Some ( "zip" ) ) => load_lines_from_zip ( & mut raw_lines, & path) ?,
85- _ => writeln ! ( & mut io :: stderr ( ) , "unknown file extension: '{}'" , path. to_string_lossy( ) ) . expect ( "failed to write to stderr" ) ,
99+
100+ for path in files {
101+ match path. extension ( ) . and_then ( |e| e. to_str ( ) ) {
102+ Some ( "json" ) => load_lines_from_json ( & mut raw_lines, path) . with_context ( || format ! ( "failed to load lines from {path:?}" ) ) ?,
103+ Some ( "zip" ) => load_lines_from_zip ( & mut raw_lines, path) . with_context ( || format ! ( "failed to load lines from {path:?}" ) ) ?,
104+ _ => eprintln ! ( "unknown file extension: '{}'" , path. to_string_lossy( ) ) ,
86105 }
87106 }
88107
@@ -93,34 +112,56 @@ fn load_lines_from_json(
93112 raw_lines : & mut RawJsonLines ,
94113 path : & Path ,
95114) -> anyhow:: Result < ( ) > {
96- for ( line_nr, line) in io:: BufReader :: new ( File :: open ( path) ?) . lines ( ) . enumerate ( ) {
97- raw_lines. push ( SourceName :: JsonFile ( path. file_name ( ) . unwrap ( ) . to_string_lossy ( ) . into ( ) ) , line_nr + 1 , line?) ;
115+ let json_file = File :: open ( path) . context ( "failed to open json" ) ?;
116+ let json_file = io:: BufReader :: new ( json_file) ;
117+
118+ for ( line_nr, line) in json_file. lines ( ) . enumerate ( ) {
119+ let line = line. context ( "failed to read json line" ) ?;
120+ let file_name = path
121+ . file_name ( )
122+ . context ( "BUG: json path is missing filename" ) ?
123+ . to_string_lossy ( )
124+ . into ( ) ;
125+ let source_name = SourceName :: JsonFile ( file_name) ;
126+
127+ raw_lines. push ( source_name, line_nr + 1 , line) ;
98128 }
129+
99130 Ok ( ( ) )
100131}
101132
102133fn load_lines_from_zip (
103134 raw_lines : & mut RawJsonLines ,
104135 path : & Path ,
105136) -> anyhow:: Result < ( ) > {
106- let zip_file = File :: open ( path) ?;
107- let mut archive = zip:: ZipArchive :: new ( zip_file) ?;
137+ let zip_file = File :: open ( path) . context ( "failed to open zip" ) ?;
138+ let mut archive = zip:: ZipArchive :: new ( zip_file) . context ( "failed to parse zip" ) ?;
108139
109140 for i in 0 ..archive. len ( ) {
110- let f = archive. by_index ( i) ?;
111- if f. is_file ( ) && f. name ( ) . ends_with ( ".json" ) {
112- let json_file = f. name ( ) . to_string ( ) ;
113- for ( line_nr, line) in io:: BufReader :: new ( f) . lines ( ) . enumerate ( ) {
114- raw_lines. push (
115- SourceName :: JsonInZip {
116- zip_file : path. file_name ( ) . unwrap ( ) . to_string_lossy ( ) . into ( ) ,
117- json_file : json_file. clone ( ) ,
118- } ,
119- line_nr + 1 ,
120- line?,
121- ) ;
122- }
141+ let f = archive
142+ . by_index ( i)
143+ . with_context ( || format ! ( "failed to get file with index {i} from zip" ) ) ?;
144+
145+ if !f. is_file ( ) || !f. name ( ) . ends_with ( ".json" ) {
146+ continue ;
147+ }
148+
149+ let json_file = f. name ( ) . to_string ( ) ;
150+ let f = io:: BufReader :: new ( f) ;
151+
152+ for ( line_nr, line) in f. lines ( ) . enumerate ( ) {
153+ let line = line. context ( "failed to read line from file in zip" ) ?;
154+ let zip_file = path
155+ . file_name ( )
156+ . context ( "BUG: zip path is missing filename" ) ?
157+ . to_string_lossy ( )
158+ . into ( ) ;
159+ let json_file = json_file. clone ( ) ;
160+ let source_name = SourceName :: JsonInZip { zip_file, json_file } ;
161+
162+ raw_lines. push ( source_name, line_nr + 1 , line) ;
123163 }
124164 }
165+
125166 Ok ( ( ) )
126167}
0 commit comments