@@ -379,7 +379,7 @@ def stage(self) -> dict:
379379 Returns a dict containing the final symlinks that would be installed.
380380 """
381381 # { destination: (mod_name, source), ... }
382- result : dict [str , tuple [str , Path ]] = {}
382+ result : dict [Path , tuple [str , Path ]] = {}
383383 # Iterate through enabled mods in order.
384384 for mod in self .mods :
385385 mod .conflict = False
@@ -496,32 +496,32 @@ def has_extra_folder(self, path: Path) -> bool:
496496 ui = UI (prompt_controller )
497497 return ui .repl ()
498498
499+ def activate_mod_all (self ) -> None :
500+ warnings = []
501+ for i , mod in enumerate (self .mods ):
502+ if not mod .visible :
503+ continue
504+ try :
505+ # Activate the mod, unless it's an unconfigured fomod.
506+ self .set_mod_state (i , True )
507+ except Warning as e :
508+ warnings .append (e )
509+ self .stage ()
510+ if warnings :
511+ raise Warning ("\n " .join (set ([i .args [0 ] for i in warnings ])))
512+
499513 def activate_mod (self , index : Union [int , str ]) -> None :
500514 """
501515 Enabled mods will be loaded by game.
502516 """
503- try :
504- int (index )
505- except ValueError as e :
506- if index != "all" :
507- raise Warning (e )
508-
509- warnings = []
510-
511517 if index == "all" :
512- for i in range (len (self .mods )):
513- if self .mods [i ].visible :
514- try :
515- # Activate the mod, unless it's an unconfigured fomod.
516- self .set_mod_state (i , True )
517- except Warning as e :
518- warnings .append (e )
519- else :
520- self .set_mod_state (index , True )
518+ return self .activate_mod_all ()
521519
522- self .stage ()
523- if warnings :
524- raise Warning ("\n " .join (set ([i .args [0 ] for i in warnings ])))
520+ try :
521+ self .set_mod_state (int (index ), True )
522+ self .stage ()
523+ except ValueError as e :
524+ raise Warning (e )
525525
526526 def do_activate (self , component : ComponentMove , index : Union [int , str ]) -> None :
527527 """
@@ -535,24 +535,25 @@ def do_activate(self, component: ComponentMove, index: Union[int, str]) -> None:
535535 f"Expected one of { list (ComponentMove )} but got '{ component } '"
536536 )
537537
538+ def deactivate_mod_all (self ) -> None :
539+ for i , mod in enumerate (self .mods ):
540+ if not mod .visible :
541+ continue
542+ self .set_mod_state (i , False )
543+ self .stage ()
544+
538545 def deactivate_mod (self , index : Union [int , str ]) -> None :
539546 """
540547 Diabled mods will not be loaded by the game.
541548 """
542- try :
543- int (index )
544- except ValueError as e :
545- if index != "all" :
546- raise Warning (e )
547-
548549 if index == "all" :
549- for i in range (len (self .mods )):
550- if self .mods [i ].visible :
551- self .set_mod_state (i , False )
552- else :
553- self .set_mod_state (index , False )
550+ return self .deactivate_mod_all ()
554551
555- self .stage ()
552+ try :
553+ self .set_mod_state (int (index ), False )
554+ self .stage ()
555+ except ValueError as e :
556+ raise Warning (e )
556557
557558 def do_deactivate (self , component : ComponentMove , index : Union [int , str ]) -> None :
558559 """
@@ -633,6 +634,16 @@ def remove_tag(self, mod: Mod, tag: str) -> None:
633634 if mod .tags != original_tags :
634635 self .changes = True
635636
637+ def tag_all (self , command : TagOperation , tag_name : str ) -> None :
638+ for mod in self .mods :
639+ if not mod .visible :
640+ continue
641+ match command :
642+ case TagOperation .ADD :
643+ self .add_tag (mod , tag_name )
644+ case TagOperation .REMOVE :
645+ self .remove_tag (mod , tag_name )
646+
636647 def do_tag (
637648 self , command : TagOperation , index : Union [int , str ], tag_name : str
638649 ) -> None :
@@ -642,29 +653,22 @@ def do_tag(
642653 self .interface_mode = InterfaceMode .TAGS
643654
644655 if index == "all" :
645- for mod in self .mods :
646- if not mod .visible :
647- continue
648- match command :
649- case TagOperation .ADD :
650- self .add_tag (mod , tag_name )
651- case TagOperation .REMOVE :
652- self .remove_tag (mod , tag_name )
653- else :
654- try :
655- mod = self .mods [index ]
656- except ValueError as e :
657- raise Warning (e )
656+ return self .tag_all (command , tag_name )
658657
659- if not mod .visible :
660- raise Warning ("You can only tag against visible mods." )
658+ try :
659+ mod = self .mods [int (index )]
660+ except (ValueError , IndexError ) as e :
661+ raise Warning (e )
661662
662- match command :
663- case TagOperation .ADD :
664- self .add_tag (mod , tag_name )
663+ if not mod .visible :
664+ raise Warning ("You can only tag against visible mods." )
665665
666- case TagOperation .REMOVE :
667- self .remove_tag (mod , tag_name )
666+ match command :
667+ case TagOperation .ADD :
668+ self .add_tag (mod , tag_name )
669+
670+ case TagOperation .REMOVE :
671+ self .remove_tag (mod , tag_name )
668672
669673 def do_display (self , interface_mode : InterfaceMode ) -> None :
670674 """
@@ -956,64 +960,66 @@ def do_rename(self, component: ComponentWrite, index: int, name: str) -> None:
956960 f"Expected one of { list (ComponentWrite )} , got '{ component } '"
957961 )
958962
963+ def delete_mod_all (self ) -> None :
964+ deleted_mods = ""
965+ visible_mods = [i for i in self .mods if i .visible ]
966+ # Don't allow deleting mods with "all" unless they're inactive.
967+ for mod in visible_mods :
968+ if mod .enabled :
969+ raise Warning (
970+ "You can only delete all visible components if they are all deactivated."
971+ )
972+ for target_mod in visible_mods :
973+ # Deactivate the mod here in case set_mod_state is overridden and
974+ # provides any cleanup to the child (like removing plugins).
975+ # Then we don't have to override this in children which use plugins.
976+ self .set_mod_state (self .mods .index (target_mod ), False )
977+ self .mods .remove (target_mod )
978+ with ignored (FileNotFoundError ):
979+ log .info (f"Deleting MOD: { target_mod .name } " )
980+ if target_mod .location .is_symlink ():
981+ target_mod .location .unlink ()
982+ else :
983+ shutil .rmtree (target_mod .location )
984+ deleted_mods += f"{ target_mod .name } \n "
985+ self .do_commit ()
986+
959987 @requires_sync
960988 def delete_mod (self , index : Union [int , str ]) -> None :
961989 """
962990 Removes specified mod from the filesystem.
963991 """
964992 try :
965- index = int (index )
993+ int (index )
966994 except ValueError as e :
967995 if index != "all" :
968996 raise Warning (e )
969997
970998 if index == "all" :
971- deleted_mods = ""
972- visible_mods = [i for i in self .mods if i .visible ]
973- # Don't allow deleting mods with "all" unless they're inactive.
974- for mod in visible_mods :
975- if mod .enabled :
976- raise Warning (
977- "You can only delete all visible components if they are all deactivated."
978- )
979- for target_mod in visible_mods :
980- # Deactivate the mod here in case set_mod_state is overridden and
981- # provides any cleanup to the child (like removing plugins).
982- # Then we don't have to override this in children which use plugins.
983- self .set_mod_state (self .mods .index (target_mod ), False )
984- self .mods .remove (target_mod )
985- with ignored (FileNotFoundError ):
986- log .info (f"Deleting MOD: { target_mod .name } " )
987- if target_mod .location .is_symlink ():
988- target_mod .location .unlink ()
989- else :
990- shutil .rmtree (target_mod .location )
991- deleted_mods += f"{ target_mod .name } \n "
992- self .do_commit ()
993- else :
994- try :
995- target_mod = self .mods [index ]
999+ return self .delete_mod_all ()
9961000
997- except IndexError as e :
998- raise Warning (e )
1001+ try :
1002+ target_mod = self .mods [int (index )]
1003+ except (ValueError , IndexError ) as e :
1004+ raise Warning (e )
9991005
1000- if not target_mod .visible :
1001- raise Warning ("You can only delete visible components." )
1006+ if not target_mod .visible :
1007+ raise Warning ("You can only delete visible components." )
10021008
1003- originally_active = target_mod .enabled
1009+ originally_active = target_mod .enabled
10041010
1005- # Remove the mod from the controller then delete it.
1006- self .set_mod_state (self .mods .index (target_mod ), False )
1007- self .mods .pop (index )
1008- with ignored (FileNotFoundError ):
1009- log .info (f"Deleting MOD: { target_mod .name } " )
1010- if target_mod .location .is_symlink ():
1011- target_mod .location .unlink ()
1012- else :
1013- shutil .rmtree (target_mod .location )
1011+ # Remove the mod from the controller then delete it.
1012+ self .set_mod_state (self .mods .index (target_mod ), False )
1013+ self .mods .pop (int ( index ) )
1014+ with ignored (FileNotFoundError ):
1015+ log .info (f"Deleting MOD: { target_mod .name } " )
1016+ if target_mod .location .is_symlink ():
1017+ target_mod .location .unlink ()
1018+ else :
1019+ shutil .rmtree (target_mod .location )
10141020
1015- if originally_active :
1016- self .do_commit ()
1021+ if originally_active :
1022+ self .do_commit ()
10171023
10181024 @requires_sync
10191025 def delete_download (self , index : Union [int , str ]) -> None :
0 commit comments