Skip to content

Commit

Permalink
Add cross page reference text resolving mechanism
Browse files Browse the repository at this point in the history
This commit adds a feature that allows the resolving of reference
texts across pages.
  • Loading branch information
tobiasah committed Jun 20, 2024
1 parent a548871 commit 0a62b1b
Show file tree
Hide file tree
Showing 20 changed files with 839 additions and 207 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Version 1.2.0

* Allow automatic link text generation across different pages.

## Version 1.1.0

* Allow markdown syntax within the caption element.
Expand Down
4 changes: 4 additions & 0 deletions demo/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ and it goes on for multiple lines

Inline images should not be converted ![Hello](assets/demo.png){width="30"}, even if they have a alt text. :smile:

### Cross page reference

See local [](#my_id) or cross page [](second_page.md#my_id) in that page. The same with a text [Test](second_page.md#my_id)

## Tables

Table: Table **bold** caption
Expand Down
5 changes: 5 additions & 0 deletions demo/docs/second_page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Just A Second Page

Figure: This uses a Figure identifier as caption {.my_class #my_id}

![](assets/demo.png){width="200"}
4 changes: 4 additions & 0 deletions demo/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ plugins:
additional_identifier: ["List", "Code"]
custom:
enable: true

nav:
- Home: 'index.md'
- Second: 'second_page.md'
1 change: 1 addition & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The default configuration is as follows:
plugins:
- caption:
additional_identifier: [] # (1)!
cross_reference_text: '{page_title}/{local_ref}'
table: # (2)!
enable: true
start_index: 1
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enable the plugin and you are good to go.
* Dynamic link text generation for references
* Highly configurable
* Extendable to support captions for all element types
* Cross page referencing

## Installation

Expand Down
44 changes: 43 additions & 1 deletion docs/references.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,46 @@ figure/table id and not specifying a link text.

!!! note
The link text can be customized by using the `reference_text` option in the
configuration. See the [config chapter](#config.md) for more details.
configuration. See the [config chapter](#config.md) for more details.

## Cross Page referencing

The automatic link text generation also works across pages. The mechanism is the
same as for local references. If no link text is specified the plugin tries to
replace it with the autogenerated link text.

=== "Markdown"

**`page_a.md`**

```Markdown
![Caption text](assets/demo.png)
```

**`page_b.md`**

```Markdown
See [](page_a.md#_figure-1) for more details.
```

=== "HTML"

**`page_a.html`**

```html
<figure id=_figure-1>
<img src="assets/demo.png" alt="This uses the alt as caption" />
<figcaption>Figure 1. Caption</figcaption>
</figure>
```

**`page_b.html`**

```html
<p>See <a href="page_a.html#_figure-1">A/Figure 1</a> for more details.</p>
```

!!! note

The config parameter `cross_reference_text` can be used to customize the
link text for cross references. The default is `{page_title}/{local_ref}`
16 changes: 8 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ dependencies = [
]
[tool.hatch.envs.lint.scripts]
typing = "mypy --install-types --non-interactive {args:src/mkdocs_caption}"
style = ["ruff {args:.}", "black --check --diff {args:.}"]
fmt = ["black {args:.}", "ruff --fix {args:.}", "style"]
style = ["ruff check {args:.}", "black --check --diff {args:.}"]
fmt = ["black {args:.}", "ruff check --fix {args:.}", "style"]
all = ["style", "typing"]

[tool.hatch.envs.doc]
Expand All @@ -106,8 +106,8 @@ target-version = ["py38"]

[tool.ruff]
target-version = "py38"
select = ["ALL"]
ignore = [
lint.select = ["ALL"]
lint.ignore = [
# Using `xml` to parse untrusted data
"S320",
# Too many arguments to function call
Expand All @@ -122,16 +122,16 @@ ignore = [
"ANN003",
]

[tool.ruff.pydocstyle]
[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.isort]
[tool.ruff.lint.isort]
known-first-party = ["mkdocs_caption"]

[tool.ruff.flake8-tidy-imports]
[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "all"

[tool.ruff.per-file-ignores]
[tool.ruff.lint.per-file-ignores]
# Tests can use magic values, assertions, and relative imports
"tests/**/*" = [
"PLR2004",
Expand Down
2 changes: 2 additions & 0 deletions src/mkdocs_caption/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class CaptionConfig(base.Config):
Args:
additional_identifier: The additional identifiers to use.
(e.g. ["List"])
cross_reference_text: The text to use for cross-references.
table: The configuration options for tables.
figure: The configuration options for figures.
custom: The configuration options for custom elements.
Expand All @@ -133,6 +134,7 @@ class CaptionConfig(base.Config):
config_options.Type(str),
default=[],
)
cross_reference_text = config_options.Type(str, default="{page_title}/{local_ref}")
table = config_options.SubConfig(IdentifierCaption)
figure = config_options.SubConfig(FigureCaption)
custom = config_options.SubConfig(IdentifierCaption)
Expand Down
32 changes: 19 additions & 13 deletions src/mkdocs_caption/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
CaptionInfo,
TreeElement,
iter_caption_elements,
update_references,
wrap_md_captions,
)

if TYPE_CHECKING:
from mkdocs.structure.pages import Page

from mkdocs_caption.config import IdentifierCaption
from mkdocs_caption.logger import PluginLogger
from mkdocs_caption.post_processor import PostProcessor

CAPTION_TAG = "custom-caption"

Expand Down Expand Up @@ -56,11 +58,10 @@ def preprocess_markdown(
def _wrap_in_figure(
caption_info: CaptionInfo,
*,
tree: TreeElement,
index: int,
config: IdentifierCaption,
logger: PluginLogger,
) -> None:
) -> str | None:
"""Wrap an element in a figure element with a custom caption.
This function takes an XML tree, a target element, a caption element, an
Expand All @@ -69,14 +70,13 @@ def _wrap_in_figure(
Args:
caption_info: The caption info.
tree: The root element of the XML tree.
index: The index of the figure element.
config: The plugin configuration.
logger: Current plugin logger.
"""
if caption_info.target_element is None:
logger.error("Custom caption does not semm to have a element that follows it")
return
return None

figure_element = etree.Element("figure", None, None)
figure_element.attrib.update(caption_info.attributes)
Expand All @@ -99,7 +99,7 @@ def _wrap_in_figure(
caption_prefix,
caption_info.caption,
)
return
return None
if config.position == "top":
figure_element.append(fig_caption_element)
figure_element.append(caption_info.target_element)
Expand All @@ -112,17 +112,15 @@ def _wrap_in_figure(
config.get_default_id(identifier=caption_info.identifier, index=index),
)
figure_element.attrib["id"] = figure_id
update_references(
tree,
figure_id,
config.get_reference_text(identifier=caption_info.identifier, index=index),
)
return figure_id


def postprocess_html(
*,
tree: TreeElement,
config: IdentifierCaption,
page: Page,
post_processor: PostProcessor,
logger: PluginLogger,
) -> None:
"""Handle custom captions in an XML tree.
Expand All @@ -133,6 +131,8 @@ def postprocess_html(
Args:
tree: The root element of the XML tree.
config: The plugin configuration.
page: The current page.
post_processor: The post processor to register targets.
logger: Current plugin logger.
"""
if not config.enable:
Expand All @@ -141,10 +141,16 @@ def postprocess_html(
for caption_info in iter_caption_elements(CAPTION_TAG, tree):
index = index_dict.get(caption_info.identifier, config.start_index)
index_dict[caption_info.identifier] = index + config.increment_index
_wrap_in_figure(
figure_id = _wrap_in_figure(
caption_info,
tree=tree,
index=index,
config=config,
logger=logger,
)
if figure_id is None:
continue
post_processor.register_target(
figure_id,
config.get_reference_text(index=index, identifier=caption_info.identifier),
page,
)
17 changes: 0 additions & 17 deletions src/mkdocs_caption/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,6 @@
TreeElement = etree._Element # noqa: SLF001


def update_references(root: TreeElement, custom_id: str, text: str) -> None:
"""Update references to a custom caption in an XML tree.
This function takes an XML tree, a custom caption identifier, and a new
caption text, and updates all references to the custom caption in the tree
to use the new caption text.
Args:
root: The root element of the XML tree.
custom_id: The identifier of the custom caption to update.
text: The new caption text to use.
"""
for ref in root.xpath(f"//a[@href='#{custom_id}']"):
if not ref.text:
ref.text = text


def _parse_extended_markdown(options: str | None) -> str:
"""Parse special extended markdown syntax.
Expand Down
27 changes: 18 additions & 9 deletions src/mkdocs_caption/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
from mkdocs_caption.helper import (
TreeElement,
iter_caption_elements,
update_references,
wrap_md_captions,
)

if TYPE_CHECKING:
from mkdocs.structure.pages import Page

from mkdocs_caption.config import FigureCaption
from mkdocs_caption.logger import PluginLogger
from mkdocs_caption.post_processor import PostProcessor

IMG_CAPTION_TAG = "figure-caption"

Expand Down Expand Up @@ -82,11 +84,12 @@ def postprocess_image(
*,
img_element: TreeElement,
title: str,
tree: TreeElement,
config: FigureCaption,
logger: PluginLogger,
index: int,
figure_attrib: dict[str, str] | None,
page: Page,
post_processor: PostProcessor,
) -> None:
"""Postprocess an image element to handle custom image captions.
Expand All @@ -97,29 +100,30 @@ def postprocess_image(
Args:
img_element: The image element to postprocess.
title: The title of the image.
tree: The root element of the XML tree.
config: The plugin configuration.
logger: Current plugin logger.
index: The index of the image element.
figure_attrib: Additional attributes for the figure element.
page: The current page.
post_processor: The post processor to register targets.
"""
# Its a bit of a tricky situation here. The used can specify a custom id
# Its a bit of a tricky situation here. The user can specify a custom id
# both on the figure element and the image element. The references to both
# of these elements needs to be updated.
if "id" in img_element.attrib:
update_references(
tree,
post_processor.register_target(
img_element.attrib["id"],
config.get_reference_text(index=index, identifier="figure"),
page,
)
if not figure_attrib:
figure_attrib = {}
if "id" not in figure_attrib:
figure_attrib["id"] = config.get_default_id(index=index, identifier="figure")
update_references(
tree,
post_processor.register_target(
figure_attrib["id"],
config.get_reference_text(index=index, identifier="figure"),
page,
)
# assemble the caption element
caption_prefix = config.get_caption_prefix(
Expand All @@ -146,6 +150,8 @@ def postprocess_html(
*,
tree: TreeElement,
config: FigureCaption,
page: Page,
post_processor: PostProcessor,
logger: PluginLogger,
) -> None:
"""Postprocess an XML tree to handle custom image captions.
Expand All @@ -158,6 +164,8 @@ def postprocess_html(
Args:
tree: The root element of the XML tree.
config: The plugin configuration.
page: The current page.
post_processor: The post processor to register targets.
logger: Current plugin logger.
"""
if not config.enable:
Expand Down Expand Up @@ -197,10 +205,11 @@ def postprocess_html(
postprocess_image(
img_element=img_element,
title=title,
tree=tree,
config=config,
logger=logger,
index=index,
figure_attrib=figure_attrib,
page=page,
post_processor=post_processor,
)
index += config.increment_index
Loading

0 comments on commit 0a62b1b

Please sign in to comment.