Skip to content

Commit 42e7dcd

Browse files
committed
table fix
1 parent 56ba2f7 commit 42e7dcd

File tree

1 file changed

+58
-22
lines changed

1 file changed

+58
-22
lines changed

src/autodoc2/render/fern_.py

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,8 @@ def render_package(self, item: ItemData) -> t.Iterable[str]:
179179
for child in children_by_type["class"]:
180180
full_name = child["full_name"]
181181
short_name = full_name.split('.')[-1]
182-
# Create anchor that matches auto-generated markdown anchors from headers
183-
anchor = self._create_anchor(full_name)
184-
name_link = f"[`{short_name}`](#{anchor})"
182+
# Use context-aware linking (same-page anchor vs cross-page)
183+
name_link = self._get_cross_reference_link(full_name, short_name, item["full_name"])
185184
# Get full description (first paragraph, not truncated)
186185
doc_lines = child.get('doc', '').strip().split('\n')
187186
if doc_lines and doc_lines[0]:
@@ -208,9 +207,8 @@ def render_package(self, item: ItemData) -> t.Iterable[str]:
208207
for child in children_by_type["function"]:
209208
full_name = child["full_name"]
210209
short_name = full_name.split('.')[-1]
211-
# Create proper anchor that matches the header (use full name for anchor)
212-
anchor = self._create_anchor(full_name)
213-
name_link = f"[`{short_name}`](#{anchor})"
210+
# Use context-aware linking (same-page anchor vs cross-page)
211+
name_link = self._get_cross_reference_link(full_name, short_name, item["full_name"])
214212
# Get full description (first paragraph, not truncated)
215213
doc_lines = child.get('doc', '').strip().split('\n')
216214
if doc_lines and doc_lines[0]:
@@ -627,32 +625,70 @@ def _generate_slug(self, full_name: str) -> str:
627625
def _generate_anchor_id(self, full_name: str) -> str:
628626
"""Generate anchor ID from full_name for use in <Anchor> components."""
629627
return full_name.replace('.', '').replace('_', '').lower()
628+
629+
def _are_on_same_page(self, item1_name: str, item2_name: str) -> bool:
630+
"""Determine if two items are rendered on the same page."""
631+
item1 = self.get_item(item1_name)
632+
item2 = self.get_item(item2_name)
633+
634+
if not item1 or not item2:
635+
return False
636+
637+
# Each item type gets its own page, except for direct children
638+
item1_page = self._get_page_for_item(item1_name)
639+
item2_page = self._get_page_for_item(item2_name)
640+
641+
return item1_page == item2_page
642+
643+
def _get_page_for_item(self, full_name: str) -> str:
644+
"""Get the page where this item is rendered."""
645+
item = self.get_item(full_name)
646+
if not item:
647+
return full_name
648+
649+
item_type = item['type']
650+
parts = full_name.split('.')
651+
652+
# Only packages, modules, and classes get their own dedicated pages
653+
if item_type in ('package', 'module', 'class'):
654+
return full_name
655+
656+
# Functions, methods, properties, attributes, data are rendered on their parent's page
657+
elif item_type in ('function', 'method', 'property', 'attribute', 'data'):
658+
# Find the parent (class, module, or package)
659+
for i in range(len(parts) - 1, 0, -1):
660+
parent_name = '.'.join(parts[:i])
661+
parent_item = self.get_item(parent_name)
662+
if parent_item and parent_item['type'] in ('package', 'module', 'class'):
663+
return parent_name
664+
665+
# Fallback - shouldn't happen
666+
return full_name
667+
668+
else:
669+
# Unknown type, assume it gets its own page
670+
return full_name
630671

631-
def _get_cross_reference_link(self, target_name: str, display_name: str = None) -> str:
672+
def _get_cross_reference_link(self, target_name: str, display_name: str = None, current_page: str = None) -> str:
632673
"""Generate cross-reference link to another documented object."""
633674
# Check if target exists in our database
634675
target_item = self.get_item(target_name)
635676
if target_item is None:
636677
# Return plain text if target not found
637678
return f"`{display_name or target_name}`"
638679

639-
# Determine the correct page to link to
640-
target_parts = target_name.split('.')
680+
link_text = display_name or target_name.split('.')[-1]
681+
anchor_id = self._generate_anchor_id(target_name)
641682

642-
# For items that get their own pages (packages, modules, classes, functions)
643-
if target_item['type'] in ('package', 'module', 'class', 'function'):
644-
# Link directly to their own page
645-
page_slug = self._generate_slug(target_name)
646-
anchor_id = self._generate_anchor_id(target_name)
647-
link_text = display_name or target_parts[-1]
648-
return f"[`{link_text}`]({page_slug}#{anchor_id})"
683+
# Determine if target is on same page as current page
684+
if current_page and self._are_on_same_page(target_name, current_page):
685+
# Same page - use anchor link only
686+
return f"[`{link_text}`](#{anchor_id})"
649687
else:
650-
# For class members (methods, attributes), link to the class page
651-
parent_name = '.'.join(target_parts[:-1]) # Remove method/attribute name
652-
parent_slug = self._generate_slug(parent_name)
653-
anchor_id = self._generate_anchor_id(target_name)
654-
link_text = display_name or target_parts[-1]
655-
return f"[`{link_text}`]({parent_slug}#{anchor_id})"
688+
# Different page - use cross-page link
689+
target_page = self._get_page_for_item(target_name)
690+
target_page_slug = self._generate_slug(target_page)
691+
return f"[`{link_text}`]({target_page_slug}#{anchor_id})"
656692

657693
def _format_code_block_with_links(self, code: str, language: str = "python") -> str:
658694
"""Format code block with deep linking using CodeBlock component."""

0 commit comments

Comments
 (0)