|
9 | 9 | from gitingest.schemas import FileSystemNode |
10 | 10 | from gitingest.utils.compat_func import readlink |
11 | 11 | from functools import singledispatchmethod |
12 | | -from gitingest.schemas import Source, FileSystemFile, FileSystemDirectory, FileSystemSymlink |
13 | | -from gitingest.schemas.filesystem import SEPARATOR |
| 12 | +from gitingest.schemas import Source, FileSystemFile, FileSystemDirectory, FileSystemSymlink, FileSystemTextFile |
| 13 | +from gitingest.schemas.filesystem import SEPARATOR, FileSystemNodeType |
14 | 14 | from jinja2 import Environment, BaseLoader |
15 | 15 |
|
| 16 | + |
| 17 | +class OverridableDispatcher: |
| 18 | + """Custom dispatcher that allows later registrations to override earlier ones, even for parent types.""" |
| 19 | + |
| 20 | + def __init__(self, default_func): |
| 21 | + self.default_func = default_func |
| 22 | + self.registry = [] # List of (type, func) in registration order |
| 23 | + |
| 24 | + def register(self, type_): |
| 25 | + def decorator(func): |
| 26 | + # Remove any existing registration for this exact type |
| 27 | + self.registry = [(t, f) for t, f in self.registry if t != type_] |
| 28 | + # Add new registration at the end (highest priority) |
| 29 | + self.registry.append((type_, func)) |
| 30 | + return func |
| 31 | + return decorator |
| 32 | + |
| 33 | + def __call__(self, instance, *args, **kwargs): |
| 34 | + # Check registrations in reverse order (most recent first) |
| 35 | + for type_, func in reversed(self.registry): |
| 36 | + if isinstance(instance, type_): |
| 37 | + return func(instance, *args, **kwargs) |
| 38 | + # Fall back to default |
| 39 | + return self.default_func(instance, *args, **kwargs) |
| 40 | + |
16 | 41 | if TYPE_CHECKING: |
17 | 42 | from gitingest.schemas import IngestionQuery |
18 | 43 |
|
@@ -169,59 +194,90 @@ def _format_token_count(text: str) -> str | None: |
169 | 194 |
|
170 | 195 | class DefaultFormatter: |
171 | 196 | def __init__(self): |
| 197 | + self.separator = SEPARATOR |
172 | 198 | self.env = Environment(loader=BaseLoader()) |
173 | 199 |
|
174 | | - @singledispatchmethod |
175 | | - def format(self, node: Source, query): |
176 | | - return f"{getattr(node, 'content', '')}" |
| 200 | + # Set up custom dispatchers |
| 201 | + def _default_format(node: Source, query): |
| 202 | + return f"{getattr(node, 'content', '')}" |
| 203 | + |
| 204 | + def _default_summary(node: Source, query): |
| 205 | + return f"{getattr(node, 'name', '')}" |
177 | 206 |
|
178 | | - @singledispatchmethod |
179 | | - def summary(self, node: Source, query): |
180 | | - # Default summary: just the name |
181 | | - return f"{getattr(node, 'name', '')}" |
| 207 | + self.format = OverridableDispatcher(_default_format) |
| 208 | + self.summary = OverridableDispatcher(_default_summary) |
182 | 209 |
|
183 | | - @format.register |
184 | | - def _(self, node: FileSystemFile, query): |
185 | | - template = \ |
| 210 | + # Register the default implementations |
| 211 | + self._register_defaults() |
| 212 | + |
| 213 | + def _register_defaults(self): |
| 214 | + @self.format.register(FileSystemFile) |
| 215 | + def _(node: FileSystemFile, query): |
| 216 | + template = \ |
186 | 217 | """ |
187 | 218 | {{ SEPARATOR }} |
188 | 219 | {{ node.name }} |
189 | 220 | {{ SEPARATOR }} |
190 | 221 |
|
191 | 222 | {{ node.content }} |
192 | 223 | """ |
193 | | - file_template = self.env.from_string(template) |
194 | | - return file_template.render(SEPARATOR=SEPARATOR, node=node, query=query, formatter=self) |
| 224 | + file_template = self.env.from_string(template) |
| 225 | + return file_template.render(SEPARATOR=SEPARATOR, node=node, query=query, formatter=self) |
195 | 226 |
|
196 | | - @format.register |
197 | | - def _(self, node: FileSystemDirectory, query): |
198 | | - template = \ |
| 227 | + @self.format.register(FileSystemDirectory) |
| 228 | + def _(node: FileSystemDirectory, query): |
| 229 | + template = \ |
199 | 230 | """ |
200 | 231 | {% for child in node.children %} |
201 | 232 | {{ formatter.format(child, query) }} |
202 | 233 | {% endfor %} |
203 | 234 | """ |
204 | | - dir_template = self.env.from_string(template) |
205 | | - return dir_template.render(node=node, query=query, formatter=self) |
| 235 | + dir_template = self.env.from_string(template) |
| 236 | + return dir_template.render(node=node, query=query, formatter=self) |
206 | 237 |
|
207 | | - @summary.register |
208 | | - def _(self, node: FileSystemDirectory, query): |
209 | | - template = \ |
| 238 | + @self.summary.register(FileSystemDirectory) |
| 239 | + def _(node: FileSystemDirectory, query): |
| 240 | + template = \ |
210 | 241 | """ |
211 | 242 | Directory structure: |
212 | 243 | {{ node.tree }} |
213 | 244 | """ |
214 | | - summary_template = self.env.from_string(template) |
215 | | - return summary_template.render(node=node, query=query, formatter=self) |
216 | | - |
| 245 | + summary_template = self.env.from_string(template) |
| 246 | + return summary_template.render(node=node, query=query, formatter=self) |
217 | 247 |
|
218 | | - @format.register |
219 | | - def _(self, node: FileSystemSymlink, query): |
220 | | - template = \ |
| 248 | + @self.format.register(FileSystemSymlink) |
| 249 | + def _(node: FileSystemSymlink, query): |
| 250 | + template = \ |
221 | 251 | """ |
222 | 252 | {{ SEPARATOR }} |
223 | 253 | {{ node.name }}{% if node.target %} -> {{ node.target }}{% endif %} |
224 | 254 | {{ SEPARATOR }} |
225 | 255 | """ |
226 | | - symlink_template = self.env.from_string(template) |
227 | | - return symlink_template.render(SEPARATOR=SEPARATOR, node=node, query=query, formatter=self) |
| 256 | + symlink_template = self.env.from_string(template) |
| 257 | + return symlink_template.render(SEPARATOR=SEPARATOR, node=node, query=query, formatter=self) |
| 258 | + |
| 259 | +class StupidFormatter(DefaultFormatter): |
| 260 | + def __init__(self): |
| 261 | + super().__init__() |
| 262 | + |
| 263 | + @self.summary.register(FileSystemTextFile) |
| 264 | + def _(node: FileSystemTextFile, query): |
| 265 | + template = \ |
| 266 | +""" |
| 267 | +{{ SEPARATOR }} |
| 268 | +{{ node.name }} |
| 269 | +{{ SEPARATOR }} |
| 270 | +FileSystemTextFile |
| 271 | +""" |
| 272 | + |
| 273 | + @self.format.register(FileSystemFile) |
| 274 | + def _(node: FileSystemFile, query): |
| 275 | + template = \ |
| 276 | +""" |
| 277 | +{{ SEPARATOR }} |
| 278 | +{{ node.name }} |
| 279 | +{{ SEPARATOR }} |
| 280 | +FileSystemFile |
| 281 | +""" |
| 282 | + file_template = self.env.from_string(template) |
| 283 | + return file_template.render(SEPARATOR=SEPARATOR, node=node, query=query, formatter=self) |
0 commit comments