Mkdocs search fixers

This commit is contained in:
2026-03-09 16:05:25 -06:00
parent e2a1ac0113
commit 533783bcae
125 changed files with 18507 additions and 11039 deletions

View File

@@ -7,10 +7,10 @@
"stars_count": 0,
"forks_count": 0,
"open_issues_count": 23,
"updated_at": "2026-03-08T18:11:30-06:00",
"updated_at": "2026-03-09T12:23:17-06:00",
"created_at": "2025-05-28T14:54:59-06:00",
"clone_url": "https://gitea.bnkops.com/admin/changemaker.lite.git",
"ssh_url": "git@gitea.bnkops.com:admin/changemaker.lite.git",
"default_branch": "main",
"last_build_update": "2026-03-08T18:11:30-06:00"
"last_build_update": "2026-03-09T12:23:17-06:00"
}

View File

@@ -4,10 +4,10 @@
"description": "Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.",
"html_url": "https://github.com/anthropics/claude-code",
"language": "Shell",
"stars_count": 75344,
"forks_count": 6074,
"open_issues_count": 5793,
"updated_at": "2026-03-09T00:15:16Z",
"stars_count": 75798,
"forks_count": 6114,
"open_issues_count": 5868,
"updated_at": "2026-03-09T21:59:41Z",
"created_at": "2025-02-22T17:41:21Z",
"clone_url": "https://github.com/anthropics/claude-code.git",
"ssh_url": "git@github.com:anthropics/claude-code.git",

View File

@@ -4,13 +4,13 @@
"description": "VS Code in the browser",
"html_url": "https://github.com/coder/code-server",
"language": "TypeScript",
"stars_count": 76540,
"forks_count": 6539,
"stars_count": 76554,
"forks_count": 6541,
"open_issues_count": 169,
"updated_at": "2026-03-08T21:32:19Z",
"updated_at": "2026-03-09T20:21:15Z",
"created_at": "2019-02-27T16:50:41Z",
"clone_url": "https://github.com/coder/code-server.git",
"ssh_url": "git@github.com:coder/code-server.git",
"default_branch": "main",
"last_build_update": "2026-03-06T12:59:10Z"
"last_build_update": "2026-03-09T19:30:51Z"
}

View File

@@ -4,13 +4,13 @@
"description": "A highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.",
"html_url": "https://github.com/gethomepage/homepage",
"language": "JavaScript",
"stars_count": 28793,
"forks_count": 1811,
"stars_count": 28818,
"forks_count": 1812,
"open_issues_count": 1,
"updated_at": "2026-03-08T23:44:14Z",
"updated_at": "2026-03-09T21:38:58Z",
"created_at": "2022-08-24T07:29:42Z",
"clone_url": "https://github.com/gethomepage/homepage.git",
"ssh_url": "git@github.com:gethomepage/homepage.git",
"default_branch": "dev",
"last_build_update": "2026-03-08T12:16:51Z"
"last_build_update": "2026-03-09T17:02:06Z"
}

View File

@@ -4,13 +4,13 @@
"description": "Git with a cup of tea! Painless self-hosted all-in-one software development service, including Git hosting, code review, team collaboration, package registry and CI/CD",
"html_url": "https://github.com/go-gitea/gitea",
"language": "Go",
"stars_count": 54180,
"forks_count": 6438,
"open_issues_count": 2846,
"updated_at": "2026-03-08T23:25:42Z",
"stars_count": 54194,
"forks_count": 6448,
"open_issues_count": 2850,
"updated_at": "2026-03-09T21:55:30Z",
"created_at": "2016-11-01T02:13:26Z",
"clone_url": "https://github.com/go-gitea/gitea.git",
"ssh_url": "git@github.com:go-gitea/gitea.git",
"default_branch": "main",
"last_build_update": "2026-03-08T20:49:59Z"
"last_build_update": "2026-03-09T10:12:24Z"
}

View File

@@ -4,13 +4,13 @@
"description": "High performance, self-hosted, newsletter and mailing list manager with a modern dashboard. Single binary app.",
"html_url": "https://github.com/knadh/listmonk",
"language": "Go",
"stars_count": 19221,
"stars_count": 19236,
"forks_count": 1945,
"open_issues_count": 99,
"updated_at": "2026-03-08T23:08:55Z",
"updated_at": "2026-03-09T21:14:22Z",
"created_at": "2019-06-26T05:08:39Z",
"clone_url": "https://github.com/knadh/listmonk.git",
"ssh_url": "git@github.com:knadh/listmonk.git",
"default_branch": "master",
"last_build_update": "2026-03-08T14:04:45Z"
"last_build_update": "2026-03-09T03:05:44Z"
}

View File

@@ -4,13 +4,13 @@
"description": "Create & scan cute qr codes easily \ud83d\udc7e",
"html_url": "https://github.com/lyqht/mini-qr",
"language": "Vue",
"stars_count": 1898,
"forks_count": 240,
"open_issues_count": 21,
"updated_at": "2026-03-08T15:02:09Z",
"stars_count": 1897,
"forks_count": 241,
"open_issues_count": 22,
"updated_at": "2026-03-09T15:15:51Z",
"created_at": "2023-04-21T14:20:14Z",
"clone_url": "https://github.com/lyqht/mini-qr.git",
"ssh_url": "git@github.com:lyqht/mini-qr.git",
"default_branch": "main",
"last_build_update": "2026-03-05T13:18:42Z"
"last_build_update": "2026-03-09T07:31:47Z"
}

View File

@@ -4,13 +4,13 @@
"description": "Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.",
"html_url": "https://github.com/n8n-io/n8n",
"language": "TypeScript",
"stars_count": 178152,
"forks_count": 55558,
"open_issues_count": 1405,
"updated_at": "2026-03-09T00:14:18Z",
"stars_count": 178343,
"forks_count": 55592,
"open_issues_count": 1414,
"updated_at": "2026-03-09T21:52:13Z",
"created_at": "2019-06-22T09:24:21Z",
"clone_url": "https://github.com/n8n-io/n8n.git",
"ssh_url": "git@github.com:n8n-io/n8n.git",
"default_branch": "master",
"last_build_update": "2026-03-09T00:10:51Z"
"last_build_update": "2026-03-09T21:33:49Z"
}

View File

@@ -4,13 +4,13 @@
"description": "\ud83d\udd25 \ud83d\udd25 \ud83d\udd25 A Free & Self-hostable Airtable Alternative",
"html_url": "https://github.com/nocodb/nocodb",
"language": "TypeScript",
"stars_count": 62384,
"forks_count": 4655,
"open_issues_count": 627,
"updated_at": "2026-03-08T23:36:57Z",
"stars_count": 62431,
"forks_count": 4659,
"open_issues_count": 629,
"updated_at": "2026-03-09T19:42:51Z",
"created_at": "2017-10-29T18:51:48Z",
"clone_url": "https://github.com/nocodb/nocodb.git",
"ssh_url": "git@github.com:nocodb/nocodb.git",
"default_branch": "develop",
"last_build_update": "2026-03-07T10:48:26Z"
"last_build_update": "2026-03-09T12:25:14Z"
}

View File

@@ -4,13 +4,13 @@
"description": "Get up and running with Kimi-K2.5, GLM-5, MiniMax, DeepSeek, gpt-oss, Qwen, Gemma and other models.",
"html_url": "https://github.com/ollama/ollama",
"language": "Go",
"stars_count": 164479,
"forks_count": 14834,
"open_issues_count": 2613,
"updated_at": "2026-03-09T00:13:40Z",
"stars_count": 164642,
"forks_count": 14860,
"open_issues_count": 2609,
"updated_at": "2026-03-09T21:37:49Z",
"created_at": "2023-06-26T19:39:32Z",
"clone_url": "https://github.com/ollama/ollama.git",
"ssh_url": "git@github.com:ollama/ollama.git",
"default_branch": "main",
"last_build_update": "2026-03-08T06:32:28Z"
"last_build_update": "2026-03-09T21:19:34Z"
}

View File

@@ -4,10 +4,10 @@
"description": "Documentation that simply works",
"html_url": "https://github.com/squidfunk/mkdocs-material",
"language": "Python",
"stars_count": 26208,
"forks_count": 4048,
"stars_count": 26215,
"forks_count": 4051,
"open_issues_count": 2,
"updated_at": "2026-03-08T17:43:54Z",
"updated_at": "2026-03-09T19:46:16Z",
"created_at": "2016-01-28T22:09:23Z",
"clone_url": "https://github.com/squidfunk/mkdocs-material.git",
"ssh_url": "git@github.com:squidfunk/mkdocs-material.git",

View File

@@ -0,0 +1,199 @@
"""
MkDocs Hook for Wiki-Link Resolution
Converts Obsidian-style [[wiki-links]] to standard Markdown links/images.
Supported syntax:
[[page-name]] → [page-name](../page-name/)
[[page-name|Display Text]] → [Display Text](../page-name/)
[[page-name#heading]] → [page-name](../page-name/#heading)
![[image.png]] → ![image.png](../path/to/image.png)
![[image.png|alt text]] → ![alt text](../path/to/image.png)
Links inside fenced code blocks and inline code are skipped.
Unresolved links are left as-is with a warning logged.
"""
import os
import re
import logging
from typing import Dict, Any, Optional
logger = logging.getLogger(__name__)
# Module-level file index: filename (lowercase) → relative path from docs root
_file_index: Dict[str, str] = {}
# Whether directory URLs are enabled
_use_directory_urls: bool = True
# Image extensions
_IMAGE_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico', '.bmp', '.tiff', '.avif'}
def on_files(files: Any, config: Dict[str, Any]) -> None:
"""Build a file index mapping lowercased filenames to their paths."""
global _file_index, _use_directory_urls
_file_index.clear()
_use_directory_urls = config.get('use_directory_urls', True)
for f in files:
# f.src_path is relative to docs_dir, e.g. "docs/getting-started/installation.md"
src = f.src_path
basename = os.path.basename(src)
# For .md files, also index without extension
name_lower = basename.lower()
_file_index[name_lower] = src
if name_lower.endswith('.md'):
stem = name_lower[:-3]
# Don't overwrite if stem already exists (first wins)
if stem not in _file_index:
_file_index[stem] = src
logger.info(f"[wikilinks] Indexed {len(_file_index)} files for wiki-link resolution")
def _resolve_link(name: str) -> Optional[str]:
"""Look up a filename in the index (case-insensitive). Returns src_path or None."""
key = name.lower().strip()
return _file_index.get(key)
def _compute_relative_path(from_page_src: str, to_src: str, anchor: str = '') -> str:
"""Compute relative URL from one page to another, accounting for directory URLs."""
from_dir = os.path.dirname(from_page_src)
_, ext = os.path.splitext(to_src)
is_image = ext.lower() in _IMAGE_EXTENSIONS
is_md = ext.lower() == '.md'
if is_image:
# Images: direct relative path to the file
rel = os.path.relpath(to_src, from_dir)
return rel.replace(os.sep, '/')
if is_md and _use_directory_urls:
# With directory URLs, pages become page-name/index.html
# So we link to the directory (without .md)
page_dir = to_src[:-3] # strip .md
# Handle index.md → links to the directory itself
if os.path.basename(to_src).lower() == 'index.md':
page_dir = os.path.dirname(to_src)
rel = os.path.relpath(page_dir, from_dir)
url = rel.replace(os.sep, '/') + '/'
elif is_md:
# Without directory URLs, link directly to .md (MkDocs converts to .html)
rel = os.path.relpath(to_src, from_dir)
url = rel.replace(os.sep, '/').replace('.md', '.html')
else:
# Other files: direct path
rel = os.path.relpath(to_src, from_dir)
url = rel.replace(os.sep, '/')
if anchor:
url += '#' + anchor
return url
# Regex to match wiki-links: optional ! prefix, then [[content]]
_WIKILINK_RE = re.compile(r'(!?)\[\[([^\]]+)\]\]')
def _replace_wikilinks(markdown: str, page_src: str) -> str:
"""Replace wiki-links in markdown, skipping code blocks."""
lines = markdown.split('\n')
result_lines = []
in_fenced_block = False
for line in lines:
# Track fenced code blocks (``` or ~~~)
stripped = line.lstrip()
if stripped.startswith('```') or stripped.startswith('~~~'):
in_fenced_block = not in_fenced_block
result_lines.append(line)
continue
if in_fenced_block:
result_lines.append(line)
continue
# Process wiki-links in this line, but skip inline code
# Strategy: split by inline code spans, only process non-code parts
parts = re.split(r'(`[^`]+`)', line)
processed_parts = []
for part in parts:
if part.startswith('`') and part.endswith('`'):
# Inside inline code — leave as-is
processed_parts.append(part)
else:
# Process wiki-links in this segment
processed_parts.append(_WIKILINK_RE.sub(
lambda m: _resolve_wikilink(m, page_src),
part
))
result_lines.append(''.join(processed_parts))
return '\n'.join(result_lines)
def _resolve_wikilink(match: re.Match, page_src: str) -> str:
"""Resolve a single wiki-link match to markdown."""
is_embed = match.group(1) == '!'
inner = match.group(2).strip()
# Parse: name|display and name#anchor
display = None
anchor = ''
if '|' in inner:
name_part, display = inner.split('|', 1)
display = display.strip()
name_part = name_part.strip()
else:
name_part = inner
if '#' in name_part:
name_part, anchor = name_part.split('#', 1)
anchor = anchor.strip()
name_part = name_part.strip()
# Resolve the target file
target_src = _resolve_link(name_part)
if target_src is None:
# Try with .md appended
target_src = _resolve_link(name_part + '.md')
if target_src is None:
# Try common image extensions
for ext in ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp']:
target_src = _resolve_link(name_part + ext)
if target_src:
break
if target_src is None:
logger.warning(f"[wikilinks] Unresolved wiki-link: [[{inner}]] in {page_src}")
return match.group(0) # Leave as-is
url = _compute_relative_path(page_src, target_src, anchor)
if is_embed:
# Image embed: ![[image.png]] or ![[image.png|alt text]]
alt = display or name_part
return f'![{alt}]({url})'
else:
# Document link: [[page]] or [[page|Display Text]]
label = display or (name_part + (f'#{anchor}' if anchor else ''))
return f'[{label}]({url})'
def on_page_markdown(markdown: str, page: Any, config: Dict[str, Any], files: Any) -> str:
"""Process wiki-links in page markdown content."""
# Quick check — skip pages without wiki-links
if '[[' not in markdown:
return markdown
return _replace_wikilinks(markdown, page.file.src_path)

View File

@@ -5,3 +5,10 @@ hide:
- toc
title: "Test Page"
---
---
template: test-page.html
hide:
- navigation
- toc
title: "Test Page"
---

View File

@@ -2,6 +2,8 @@
Testing page.
[[test-page]]]]
<div class="photo-block" data-photo-id="1" data-size="large" data-caption="" data-link-to-gallery="true" data-alignment="center">Loading...</div>

View File

@@ -1,2 +1,19 @@
# testing
# testing
## Wiki-Link Tests
- Doc link: [[installation]]
- Doc link with display text: [[installation|Install Guide]]
- Doc link with anchor: [[installation#prerequisites]]
- Image embed: ![[logo.png]]
- Image with alt: ![[logo.png|Site Logo]]
- Code block (should NOT be converted):
```
[[this-should-stay-as-is]]
```
- Inline code (should NOT be converted): `[[not-a-link]]`
- Unresolved link (should stay as-is): [[nonexistent-page]]