@@ -187,9 +187,13 @@ impl AddListItem for GithubAddListItem {
187187impl Downloadable for GithubAddListItem {
188188 async fn download ( & self , dir : PathBuf ) -> Result < ( ) > {
189189 let gh = GHReleasesAPI :: new ( ) ;
190- let version_data = gh. get_releases ( & self . repo , & self . game_version ) . await ;
190+ let [ owner, repo] = self . repo . split ( '/' ) . collect :: < Vec < & str > > ( ) [ ..] else {
191+ error ! ( "Invalid repo {}" , self . repo) ;
192+ return Ok ( ( ) ) ;
193+ } ;
194+ let version_data = gh. get_releases ( owner, repo) . await ;
191195 if let Ok ( version_data) = version_data {
192- let release = get_mod_from_release ( & version_data, "fabric" , & self . version ) . await ;
196+ let release = get_mod_from_release ( & version_data, "fabric" , & self . game_version ) . await ;
193197 if let Ok ( release) = release {
194198 let url = release. get_download_url ( ) . unwrap ( ) ;
195199 let file_name = url. path_segments ( ) . unwrap ( ) . last ( ) . unwrap ( ) ;
@@ -204,8 +208,8 @@ impl Downloadable for GithubAddListItem {
204208 }
205209 } else {
206210 error ! (
207- "Could not find version {} for {}" ,
208- & self . version , & self . name
211+ "Could not find version {} for {}: {version_data:?} " ,
212+ & self . game_version , & self . name
209213 ) ;
210214 }
211215 Ok ( ( ) )
@@ -352,16 +356,104 @@ impl AddComponent {
352356 _ => State :: Normal ,
353357 } ;
354358 }
359+ pub fn search ( & mut self ) -> Result < Option < Action > > {
360+ let version = self . version_input . value ( ) ;
361+ if version. is_empty ( ) {
362+ return Ok ( None ) ;
363+ }
364+ let search_term = self . input . value ( ) ;
365+ let first_search = self . search_result_list . selected_items . is_empty ( ) ;
366+ let search_results = match self . source_list . state . selected ( ) {
367+ Some ( selected) => {
368+ let selected = self . source_list . list_items [ selected] . clone ( ) ;
369+ match selected {
370+ Source :: Modrinth => {
371+ let mods =
372+ futures:: executor:: block_on ( Modrinth :: search_mods ( search_term, 100 , 0 ) ) ;
373+ debug ! ( search = ?search_term) ;
374+ let hits = mods. hits ;
375+ debug ! ( search = ?hits) ;
376+ hits. into_iter ( )
377+ . map ( |mod_| {
378+ let mut mod_ = ModrinthAddListItem {
379+ name : mod_. title ,
380+ source : Source :: Modrinth ,
381+ project_id : mod_. project_id ,
382+ version : "" . to_string ( ) ,
383+ game_version : version. to_string ( ) ,
384+ slug : mod_. slug ,
385+ selected : true ,
386+ } ;
387+
388+ let enabled = if first_search {
389+ false
390+ } else {
391+ self . search_result_list
392+ . selected_items
393+ . contains ( & SearchResult :: ModrinthMod ( mod_. clone ( ) ) )
394+ } ;
395+
396+ mod_. selected = enabled;
397+ SearchResult :: ModrinthMod ( mod_)
398+ } )
399+ . collect :: < Vec < SearchResult > > ( )
400+ }
401+ Source :: Github => {
402+ let split = search_term. split ( '/' ) . collect :: < Vec < & str > > ( ) ;
403+ let repo = split. last ( ) . unwrap_or ( & "" ) ;
404+ let owner = split. first ( ) . unwrap_or ( & "" ) ;
405+ let releases = futures:: executor:: block_on (
406+ GHReleasesAPI :: new ( ) . get_releases ( owner, repo) ,
407+ ) ;
408+ if let Ok ( releases) = releases {
409+ releases
410+ . into_iter ( )
411+ . filter_map ( |release| {
412+ if !release. name . clone ( ) ?. contains ( version) {
413+ return None ;
414+ } ;
415+ let mut github = GithubAddListItem {
416+ name : release. name ?,
417+ source : Source :: Github ,
418+ repo : search_term. to_string ( ) ,
419+ version : release. tag_name . clone ( ) ,
420+ game_version : version. to_string ( ) ,
421+ selected : false ,
422+ } ;
423+ let enabled = if first_search {
424+ false
425+ } else {
426+ self . search_result_list
427+ . selected_items
428+ . contains ( & SearchResult :: Github ( github. clone ( ) ) )
429+ } ;
430+ github. selected = enabled;
431+ Some ( SearchResult :: Github ( github) )
432+ } )
433+ . collect :: < Vec < SearchResult > > ( )
434+ } else {
435+ error ! ( err=?releases. err( ) . unwrap( ) . to_string( ) , "Error finding or downloading mod" ) ;
436+ Vec :: new ( )
437+ }
438+ }
439+ }
440+ }
441+ None => Vec :: new ( ) ,
442+ } ;
443+ self . search_result_list . list_items = search_results;
444+ self . state = State :: SearchResultList ;
445+ Ok ( None )
446+ }
355447}
356448
357449impl ModrinthAddListItem {
358450 pub fn format ( & self ) -> Vec < Line < ' static > > {
359451 let selected_indicator = if self . selected {
360- Span :: styled ( "[x]" , Style :: default ( ) . fg ( Color :: Green ) )
452+ Span :: styled ( "[x] " , Style :: default ( ) . fg ( Color :: Green ) )
361453 } else {
362- Span :: raw ( "[ ]" )
454+ Span :: raw ( "[ ] " )
363455 } ;
364- let padding = Span :: raw ( " " ) ;
456+ let padding = Span :: raw ( " " ) ;
365457 vec ! [
366458 Line :: from( vec![
367459 selected_indicator,
@@ -370,10 +462,6 @@ impl ModrinthAddListItem {
370462 Style :: default ( ) . add_modifier( Modifier :: BOLD ) ,
371463 ) ,
372464 Span :: raw( " " ) ,
373- Span :: styled(
374- format!( "v{}" , self . version) ,
375- Style :: default ( ) . fg( Color :: Green ) ,
376- ) ,
377465 ] ) ,
378466 Line :: from( vec![
379467 padding. clone( ) ,
@@ -407,11 +495,11 @@ impl ModrinthAddListItem {
407495impl GithubAddListItem {
408496 pub fn format ( & self ) -> Vec < Line < ' static > > {
409497 let selected_indicator = if self . selected {
410- Span :: styled ( "[x]" , Style :: default ( ) . fg ( Color :: Green ) )
498+ Span :: styled ( "[x] " , Style :: default ( ) . fg ( Color :: Green ) )
411499 } else {
412- Span :: raw ( "[ ]" )
500+ Span :: raw ( "[ ] " )
413501 } ;
414- let padding = Span :: raw ( " " ) ;
502+ let padding = Span :: raw ( " " ) ;
415503 vec ! [
416504 Line :: from( vec![
417505 selected_indicator,
@@ -421,7 +509,7 @@ impl GithubAddListItem {
421509 ) ,
422510 Span :: raw( " " ) ,
423511 Span :: styled(
424- format!( "v{}" , self . version) ,
512+ format!( "v. {}" , self . version) ,
425513 Style :: default ( ) . fg( Color :: Green ) ,
426514 ) ,
427515 ] ) ,
@@ -497,94 +585,7 @@ impl Component for AddComponent {
497585 match key. code {
498586 KeyCode :: Tab | KeyCode :: Esc => self . toggle_state ( ) ,
499587 KeyCode :: Enter => {
500- let version = self . version_input . value ( ) ;
501- if version. is_empty ( ) {
502- return Ok ( None ) ;
503- }
504- let search_term = self . input . value ( ) ;
505- let first_search = self . search_result_list . selected_items . is_empty ( ) ;
506- let search_results = match self . source_list . state . selected ( ) {
507- Some ( selected) => {
508- let selected = self . source_list . list_items [ selected] . clone ( ) ;
509- match selected {
510- Source :: Modrinth => {
511- let mods = futures:: executor:: block_on ( Modrinth :: search_mods (
512- search_term,
513- 100 ,
514- 0 ,
515- ) ) ;
516- debug ! ( search = ?search_term) ;
517- let hits = mods. hits ;
518- debug ! ( search = ?hits) ;
519- hits. into_iter ( )
520- . map ( |mod_| {
521- let mut mod_ = ModrinthAddListItem {
522- name : mod_. title ,
523- source : Source :: Modrinth ,
524- project_id : mod_. project_id ,
525- version : "" . to_string ( ) ,
526- game_version : version. to_string ( ) ,
527- slug : mod_. slug ,
528- selected : true ,
529- } ;
530-
531- let enabled = if first_search {
532- false
533- } else {
534- self . search_result_list . selected_items . contains (
535- & SearchResult :: ModrinthMod ( mod_. clone ( ) ) ,
536- )
537- } ;
538-
539- mod_. selected = enabled;
540- SearchResult :: ModrinthMod ( mod_)
541- } )
542- . collect :: < Vec < SearchResult > > ( )
543- }
544- Source :: Github => {
545- let split = search_term. split ( '/' ) . collect :: < Vec < & str > > ( ) ;
546- let repo = split. last ( ) . unwrap_or ( & "" ) ;
547- let owner = split. first ( ) . unwrap_or ( & "" ) ;
548- let releases = futures:: executor:: block_on (
549- GHReleasesAPI :: new ( ) . get_releases ( owner, repo) ,
550- ) ;
551- if let Ok ( releases) = releases {
552- releases
553- . into_iter ( )
554- . filter_map ( |release| {
555- if !release. name . clone ( ) ?. contains ( version) {
556- return None ;
557- } ;
558- let mut github = GithubAddListItem {
559- name : release. name ?,
560- source : Source :: Github ,
561- repo : search_term. to_string ( ) ,
562- version : release. tag_name . clone ( ) ,
563- game_version : version. to_string ( ) ,
564- selected : false ,
565- } ;
566- let enabled = if first_search {
567- false
568- } else {
569- self . search_result_list . selected_items . contains (
570- & SearchResult :: Github ( github. clone ( ) ) ,
571- )
572- } ;
573- github. selected = enabled;
574- Some ( SearchResult :: Github ( github) )
575- } )
576- . collect :: < Vec < SearchResult > > ( )
577- } else {
578- error ! ( err=?releases. err( ) . unwrap( ) . to_string( ) , "Error finding or downloading mod" ) ;
579- Vec :: new ( )
580- }
581- }
582- }
583- }
584- None => Vec :: new ( ) ,
585- } ;
586- self . search_result_list . list_items = search_results;
587- self . state = State :: SearchResultList ;
588+ self . search ( ) ?;
588589 }
589590 _ => {
590591 self . input . handle_event ( & crossterm:: event:: Event :: Key ( key) ) ;
@@ -599,6 +600,12 @@ impl Component for AddComponent {
599600 KeyCode :: Char ( 'k' ) | KeyCode :: Up => self . source_list . select_previous ( ) ,
600601 KeyCode :: Char ( 'g' ) | KeyCode :: Home => self . source_list . select_first ( ) ,
601602 KeyCode :: Char ( 'G' ) | KeyCode :: End => self . source_list . select_last ( ) ,
603+ KeyCode :: Char ( 'q' ) => return Ok ( Some ( Action :: Quit ) ) ,
604+ KeyCode :: Enter => {
605+ if !self . version_input . value ( ) . is_empty ( ) && !self . input . value ( ) . is_empty ( ) {
606+ self . search ( ) ?;
607+ }
608+ }
602609 KeyCode :: Esc => {
603610 self . state = State :: Normal ;
604611 }
@@ -610,6 +617,11 @@ impl Component for AddComponent {
610617 match key. code {
611618 KeyCode :: Tab | KeyCode :: Esc => self . state = State :: Normal ,
612619 KeyCode :: Enter => {
620+ if !self . version_input . value ( ) . is_empty ( ) && !self . input . value ( ) . is_empty ( ) {
621+ self . search ( ) ?;
622+ return Ok ( None ) ;
623+ }
624+
613625 self . state = State :: Search ;
614626 }
615627 key => {
@@ -708,6 +720,10 @@ impl Component for AddComponent {
708720 KeyCode :: Char ( 'k' ) | KeyCode :: Up => self . selected_list_state . select_previous ( ) ,
709721 KeyCode :: Char ( 'g' ) | KeyCode :: Home => self . selected_list_state . select_first ( ) ,
710722 KeyCode :: Char ( 'G' ) | KeyCode :: End => self . selected_list_state . select_last ( ) ,
723+ KeyCode :: Char ( 'q' ) => return Ok ( Some ( Action :: Quit ) ) ,
724+ KeyCode :: Char ( 'J' ) => {
725+ self . state = State :: VersionInput ;
726+ }
711727 KeyCode :: Esc => {
712728 self . state = State :: Normal ;
713729 }
@@ -881,16 +897,16 @@ impl Component for AddComponent {
881897
882898 let log_widget = TuiLoggerWidget :: default ( )
883899 . style_error ( Style :: default ( ) . fg ( Color :: Red ) )
884- . style_debug ( Style :: default ( ) . fg ( Color :: Green ) )
900+ . style_debug ( Style :: default ( ) . fg ( Color :: Cyan ) )
885901 . style_warn ( Style :: default ( ) . fg ( Color :: Yellow ) )
886902 . style_trace ( Style :: default ( ) . fg ( Color :: Magenta ) )
887- . style_info ( Style :: default ( ) . fg ( Color :: Cyan ) )
903+ . style_info ( Style :: default ( ) . fg ( Color :: Green ) )
888904 . output_separator ( ':' )
889905 . output_timestamp ( Some ( "%H:%M:%S" . to_string ( ) ) )
890- . output_level ( Some ( TuiLoggerLevelOutput :: Abbreviated ) )
891- . output_target ( true )
892- . output_file ( true )
893- . output_line ( true )
906+ . output_level ( Some ( TuiLoggerLevelOutput :: Long ) )
907+ . output_target ( false )
908+ . output_file ( false )
909+ . output_line ( false )
894910 . state ( & self . logger_state )
895911 . block (
896912 Block :: default ( )
@@ -1008,14 +1024,15 @@ async fn get_mods(dir: PathBuf) -> Vec<CurrentModsListItem> {
10081024 let enabled = !path_str. contains ( "disabled" ) ;
10091025 let version_data = VersionData :: from_hash ( hash) . await ;
10101026 if version_data. is_err ( ) {
1011- error ! ( version_data = ?version_data, "Failed to get version data for {}" , path_str) ;
10121027 let metadata = Metadata :: get_all_metadata ( path_str. clone ( ) . into ( ) ) ;
10131028 if metadata. is_err ( ) {
1029+ error ! ( version_data = ?version_data, "Failed to get version data for {}" , path_str) ;
10141030 return None ;
10151031 }
10161032 let metadata = metadata. unwrap ( ) ;
10171033 let source = metadata. get ( "source" ) . unwrap ( ) ;
10181034 if source. is_empty ( ) {
1035+ error ! ( version_data = ?version_data, "Failed to get version data for {}" , path_str) ;
10191036 return None ;
10201037 }
10211038 let repo = metadata. get ( "repo" ) . unwrap ( ) ;
0 commit comments