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