Repository: mkdocs/mkdocs

Issue:
Wrong example for `!relative` option
The Configuration page lists an example using `pymdownx.snippets` for the `!relative` YAML tag.

The issue with this example is, that the `base_path` option of snippets is expecting a list and not a single String, which breaks the configuration itself.
In fact, the relative option cannot be used by snippets at all it seems.

This error in the documentation should be fixed, as it will otherwise give people the idea, that it can be used with snippets like that...
Or IF it can be used, there should be more clarification on this.

Below is a collection of stacktraces thrown by MkDocs when using `!relative` in different setups:

```yaml
markdown_extensions:
  # ...
  - pymdownx.snippets:
      base_path: !relative
```

<details><summary>Stacktrace</summary>
<p>

```
ERROR   -  Config value 'markdown_extensions': Failed to load extension 'pymdownx.snippets'.
  File "C:\Users\Andreas\AppData\Local\Programs\Python\Python311\Lib\site-packages\mkdocs\config\config_options.py", line 1021, in run_validation
    md.registerExtensions((ext,), self.configdata)
  File "C:\Users\Andreas\AppData\Local\Programs\Python\Python311\Lib\site-packages\markdown\core.py", line 115, in registerExtensions
    ext.extendMarkdown(self)
  File "C:\Users\Andreas\AppData\Local\Programs\Python\Python311\Lib\site-packages\pymdownx\snippets.py", line 402, in extendMarkdown
    snippet = SnippetPreprocessor(config, md)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Andreas\AppData\Local\Programs\Python\Python311\Lib\site-packages\pymdownx\snippets.py", line 85, in __init__
    self.base_path = [os.path.abspath(b) for b in base]
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'RelativeDirPlaceholder' object is not iterable
Aborted with 1 configuration errors!
ERROR   -  [21:51:48] An error happened during the rebuild. The server will appear stuck until build errors are resolved.
```

</p>
</details>

```yaml
markdown_extensions:
  # ...
  - pymdownx.snippets:
      base_path:
        - !relative
```

<details><summary>Stacktrace</summary>
<p>

```
ERROR   -  Config value 'markdown_extensions': Failed to load extension 'pymdownx.snippets'.
  File "C:\Users\Andreas\AppData\Local\Programs\Python\Python311\Lib\site-packages\mkdocs\utils\yaml.py", line 52, in __fspath__
    return os.path.join(self.value(), self.suffix)
                        ^^^^^^^^^^^^
  File "C:\Users\Andreas\AppData\Local\Programs\Python\Python311\Lib\site-packages\mkdocs\utils\yaml.py", line 98, in value
    raise exceptions.ConfigurationError(
ConfigurationError: The current file is not set for the '!relative' tag. It cannot be used in this context; the intended usage is within `markdown_extensions`.
Aborted with 1 configuration errors!
ERROR   -  [21:52:36] An error happened during the rebuild. The server will appear stuck until build errors are resolved.
```

</p>
</details> 

Discussion:

Patch:
diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py
index aacff403..9b16e302 100644
--- a/mkdocs/config/config_options.py
+++ b/mkdocs/config/config_options.py
@@ -10,6 +10,7 @@ import traceback
 import types
 import warnings
 from collections import Counter, UserString
+from types import SimpleNamespace
 from typing import (
     Any,
     Callable,
@@ -993,6 +994,12 @@ class MarkdownExtensions(OptionallyRequired[List[str]]):
             raise ValidationError(f"Invalid config options for Markdown Extension '{ext}'.")
         self.configdata[ext] = cfg
 
+    def pre_validation(self, config, key_name):
+        # To appease validation in case it involves the `!relative` tag.
+        config._current_page = current_page = SimpleNamespace()  # type: ignore[attr-defined]
+        current_page.file = SimpleNamespace()
+        current_page.file.src_path = ''
+
     def run_validation(self, value: object) -> list[str]:
         self.configdata: dict[str, dict] = {}
         if not isinstance(value, (list, tuple, dict)):
@@ -1037,6 +1044,7 @@ class MarkdownExtensions(OptionallyRequired[List[str]]):
         return extensions
 
     def post_validation(self, config: Config, key_name: str):
+        config._current_page = None  # type: ignore[attr-defined]
         config[self.configkey] = self.configdata
 
 
diff --git a/mkdocs/utils/yaml.py b/mkdocs/utils/yaml.py
index b0c0e7ad..46745eec 100644
--- a/mkdocs/utils/yaml.py
+++ b/mkdocs/utils/yaml.py
@@ -97,12 +97,13 @@ class RelativeDirPlaceholder(_DirPlaceholder):
         super().__init__(config, suffix)
 
     def value(self) -> str:
-        if self.config._current_page is None:
+        current_page = self.config._current_page
+        if current_page is None:
             raise exceptions.ConfigurationError(
                 "The current file is not set for the '!relative' tag. "
                 "It cannot be used in this context; the intended usage is within `markdown_extensions`."
             )
-        return os.path.dirname(self.config._current_page.file.abs_src_path)
+        return os.path.dirname(os.path.join(self.config.docs_dir, current_page.file.src_path))
 
 
 def get_yaml_loader(loader=yaml.Loader, config: MkDocsConfig | None = None):


Test patch:
diff --git a/mkdocs/tests/build_tests.py b/mkdocs/tests/build_tests.py
index 275aad37..4b7596bf 100644
--- a/mkdocs/tests/build_tests.py
+++ b/mkdocs/tests/build_tests.py
@@ -814,7 +814,7 @@ class _TestPreprocessor(markdown.preprocessors.Preprocessor):
 
 class _TestExtension(markdown.extensions.Extension):
     def __init__(self, base_path: str) -> None:
-        self.base_path = base_path
+        self.base_path = str(base_path)
 
     def extendMarkdown(self, md: markdown.Markdown) -> None:
         md.preprocessors.register(_TestPreprocessor(self.base_path), "mkdocs_test", priority=32)