@@ -36,6 +36,63 @@ class Config: |
| 36 | """Get the output directory for generated shell files""" | 36 | """Get the output directory for generated shell files""" |
| 37 | return os.path.expanduser("~/.config/shtick") | 37 | return os.path.expanduser("~/.config/shtick") |
| 38 | | 38 | |
| | 39 | + @staticmethod |
| | 40 | + def get_active_groups_file() -> str: |
| | 41 | + """Get the active groups state file path""" |
| | 42 | + return os.path.expanduser("~/.config/shtick/active_groups") |
| | 43 | + |
| | 44 | + def load_active_groups(self) -> List[str]: |
| | 45 | + """Load list of currently active groups""" |
| | 46 | + active_file = self.get_active_groups_file() |
| | 47 | + if not os.path.exists(active_file): |
| | 48 | + return [] |
| | 49 | + |
| | 50 | + with open(active_file, "r") as f: |
| | 51 | + return [line.strip() for line in f if line.strip()] |
| | 52 | + |
| | 53 | + def save_active_groups(self, active_groups: List[str]) -> None: |
| | 54 | + """Save list of active groups to state file""" |
| | 55 | + self.ensure_config_dir() |
| | 56 | + active_file = self.get_active_groups_file() |
| | 57 | + |
| | 58 | + with open(active_file, "w") as f: |
| | 59 | + for group in active_groups: |
| | 60 | + f.write(f"{group}\n") |
| | 61 | + |
| | 62 | + def activate_group(self, group_name: str) -> bool: |
| | 63 | + """Activate a group. Returns True if successful.""" |
| | 64 | + # Check if group exists |
| | 65 | + if not self.get_group(group_name): |
| | 66 | + return False |
| | 67 | + |
| | 68 | + active_groups = self.load_active_groups() |
| | 69 | + if group_name not in active_groups: |
| | 70 | + active_groups.append(group_name) |
| | 71 | + self.save_active_groups(active_groups) |
| | 72 | + |
| | 73 | + return True |
| | 74 | + |
| | 75 | + def deactivate_group(self, group_name: str) -> bool: |
| | 76 | + """Deactivate a group. Returns True if was active.""" |
| | 77 | + active_groups = self.load_active_groups() |
| | 78 | + if group_name in active_groups: |
| | 79 | + active_groups.remove(group_name) |
| | 80 | + self.save_active_groups(active_groups) |
| | 81 | + return True |
| | 82 | + return False |
| | 83 | + |
| | 84 | + def is_group_active(self, group_name: str) -> bool: |
| | 85 | + """Check if a group is currently active""" |
| | 86 | + return group_name in self.load_active_groups() |
| | 87 | + |
| | 88 | + def get_persistent_group(self) -> Optional[GroupData]: |
| | 89 | + """Get the special 'persistent' group if it exists""" |
| | 90 | + return self.get_group("persistent") |
| | 91 | + |
| | 92 | + def get_regular_groups(self) -> List[GroupData]: |
| | 93 | + """Get all groups except 'persistent'""" |
| | 94 | + return [group for group in self.groups if group.name != "persistent"] |
| | 95 | + |
| 39 | def ensure_config_dir(self) -> None: | 96 | def ensure_config_dir(self) -> None: |
| 40 | """Ensure the config directory exists""" | 97 | """Ensure the config directory exists""" |
| 41 | config_dir = os.path.dirname(self.config_path) | 98 | config_dir = os.path.dirname(self.config_path) |
@@ -46,42 +103,76 @@ class Config: |
| 46 | if not os.path.exists(self.config_path): | 103 | if not os.path.exists(self.config_path): |
| 47 | raise FileNotFoundError(f"Config file not found: {self.config_path}") | 104 | raise FileNotFoundError(f"Config file not found: {self.config_path}") |
| 48 | | 105 | |
| | 106 | + print(f"Debug: Loading config from: {self.config_path}") |
| | 107 | + |
| 49 | with open(self.config_path, "rb") as f: | 108 | with open(self.config_path, "rb") as f: |
| 50 | data = tomllib.load(f) | 109 | data = tomllib.load(f) |
| 51 | | 110 | |
| | 111 | + print(f"Debug: Raw TOML data keys: {list(data.keys())}") |
| | 112 | + print(f"Debug: Raw TOML data structure: {data}") |
| | 113 | + |
| 52 | self.groups = [] | 114 | self.groups = [] |
| 53 | | 115 | |
| 54 | - # Parse groups from TOML structure like [group1.aliases] | 116 | + # Parse groups from nested TOML structure |
| 55 | - group_data = {} | 117 | + for group_name, group_config in data.items(): |
| 56 | - | 118 | + print(f"Debug: Processing group '{group_name}' with config: {group_config}") |
| 57 | - for key, value in data.items(): | 119 | + |
| 58 | - if "." in key: | 120 | + if not isinstance(group_config, dict): |
| 59 | - group_name, data_type = key.split(".", 1) | 121 | + print(f"Debug: Skipping non-dict value for key '{group_name}'") |
| 60 | - | 122 | + continue |
| 61 | - if group_name not in group_data: | 123 | + |
| 62 | - group_data[group_name] = { | 124 | + # Initialize group data |
| 63 | - "aliases": {}, | 125 | + group_data = {"aliases": {}, "env_vars": {}, "functions": {}} |
| 64 | - "env_vars": {}, | 126 | + |
| 65 | - "functions": {}, | 127 | + # Extract each section from the group |
| 66 | - } | 128 | + for section_name, section_data in group_config.items(): |
| 67 | - | 129 | + print( |
| 68 | - if data_type == "aliases": | 130 | + f"Debug: Processing section '{section_name}' in group '{group_name}': {section_data}" |
| 69 | - group_data[group_name]["aliases"] = value | | |
| 70 | - elif data_type == "env_vars": | | |
| 71 | - group_data[group_name]["env_vars"] = value | | |
| 72 | - elif data_type == "functions": | | |
| 73 | - group_data[group_name]["functions"] = value | | |
| 74 | - | | |
| 75 | - # Convert to GroupData objects | | |
| 76 | - for group_name, data in group_data.items(): | | |
| 77 | - self.groups.append( | | |
| 78 | - GroupData( | | |
| 79 | - name=group_name, | | |
| 80 | - aliases=data["aliases"], | | |
| 81 | - env_vars=data["env_vars"], | | |
| 82 | - functions=data["functions"], | | |
| 83 | ) | 131 | ) |
| | 132 | + |
| | 133 | + if section_name == "aliases" and isinstance(section_data, dict): |
| | 134 | + group_data["aliases"] = section_data |
| | 135 | + print(f"Debug: Added {len(section_data)} aliases to '{group_name}'") |
| | 136 | + elif section_name == "env_vars" and isinstance(section_data, dict): |
| | 137 | + group_data["env_vars"] = section_data |
| | 138 | + print( |
| | 139 | + f"Debug: Added {len(section_data)} env_vars to '{group_name}'" |
| | 140 | + ) |
| | 141 | + elif section_name == "functions" and isinstance(section_data, dict): |
| | 142 | + group_data["functions"] = section_data |
| | 143 | + print( |
| | 144 | + f"Debug: Added {len(section_data)} functions to '{group_name}'" |
| | 145 | + ) |
| | 146 | + else: |
| | 147 | + print( |
| | 148 | + f"Debug: Unknown or invalid section '{section_name}' in group '{group_name}'" |
| | 149 | + ) |
| | 150 | + |
| | 151 | + # Create GroupData object if group has any items |
| | 152 | + total_items = ( |
| | 153 | + len(group_data["aliases"]) |
| | 154 | + + len(group_data["env_vars"]) |
| | 155 | + + len(group_data["functions"]) |
| 84 | ) | 156 | ) |
| | 157 | + print(f"Debug: Group '{group_name}' has {total_items} total items") |
| | 158 | + |
| | 159 | + if total_items > 0: |
| | 160 | + new_group = GroupData( |
| | 161 | + name=group_name, |
| | 162 | + aliases=group_data["aliases"], |
| | 163 | + env_vars=group_data["env_vars"], |
| | 164 | + functions=group_data["functions"], |
| | 165 | + ) |
| | 166 | + self.groups.append(new_group) |
| | 167 | + print( |
| | 168 | + f"Debug: Created group '{group_name}' with {len(group_data['aliases'])} aliases, {len(group_data['env_vars'])} env_vars, {len(group_data['functions'])} functions" |
| | 169 | + ) |
| | 170 | + else: |
| | 171 | + print(f"Warning: Group '{group_name}' has no items, skipping") |
| | 172 | + |
| | 173 | + print( |
| | 174 | + f"Debug: Final groups loaded: {[g.name for g in self.groups]} (total: {len(self.groups)})" |
| | 175 | + ) |
| 85 | | 176 | |
| 86 | def save(self) -> None: | 177 | def save(self) -> None: |
| 87 | """Save the current configuration back to TOML file""" | 178 | """Save the current configuration back to TOML file""" |