@@ -36,6 +36,63 @@ class Config: |
| 36 | 36 | """Get the output directory for generated shell files""" |
| 37 | 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 | 96 | def ensure_config_dir(self) -> None: |
| 40 | 97 | """Ensure the config directory exists""" |
| 41 | 98 | config_dir = os.path.dirname(self.config_path) |
@@ -46,42 +103,76 @@ class Config: |
| 46 | 103 | if not os.path.exists(self.config_path): |
| 47 | 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 | 108 | with open(self.config_path, "rb") as f: |
| 50 | 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 | 114 | self.groups = [] |
| 53 | 115 | |
| 54 | | - # Parse groups from TOML structure like [group1.aliases] |
| 55 | | - group_data = {} |
| 56 | | - |
| 57 | | - for key, value in data.items(): |
| 58 | | - if "." in key: |
| 59 | | - group_name, data_type = key.split(".", 1) |
| 60 | | - |
| 61 | | - if group_name not in group_data: |
| 62 | | - group_data[group_name] = { |
| 63 | | - "aliases": {}, |
| 64 | | - "env_vars": {}, |
| 65 | | - "functions": {}, |
| 66 | | - } |
| 67 | | - |
| 68 | | - if data_type == "aliases": |
| 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"], |
| 116 | + # Parse groups from nested TOML structure |
| 117 | + for group_name, group_config in data.items(): |
| 118 | + print(f"Debug: Processing group '{group_name}' with config: {group_config}") |
| 119 | + |
| 120 | + if not isinstance(group_config, dict): |
| 121 | + print(f"Debug: Skipping non-dict value for key '{group_name}'") |
| 122 | + continue |
| 123 | + |
| 124 | + # Initialize group data |
| 125 | + group_data = {"aliases": {}, "env_vars": {}, "functions": {}} |
| 126 | + |
| 127 | + # Extract each section from the group |
| 128 | + for section_name, section_data in group_config.items(): |
| 129 | + print( |
| 130 | + f"Debug: Processing section '{section_name}' in group '{group_name}': {section_data}" |
| 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 | 177 | def save(self) -> None: |
| 87 | 178 | """Save the current configuration back to TOML file""" |