Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,13 @@ flowchart TD
| `pnpm dev` | 启动 VitePress 开发服务器,支持热更新 |
| `pnpm build` | 生产构建,按分卷并行构建并合并搜索索引 |
| `pnpm build:single` | 使用 VitePress 单体构建 |
| `pnpm check:links` | 检查 Markdown 与组件内部链接有效性 |
| `pnpm preview` | 预览生产构建结果 |
| `pnpm hooks:install` / `scripts/setup_precommit.sh` | 安装提交前 Git hook |
| `pnpm coverage` | 查看英文翻译覆盖率 |
| `pnpm coverage:update` | 更新 `README.md` 中的英文翻译覆盖率徽章 |
| `python3 scripts/validate_frontmatter.py` | 验证文章 frontmatter |
| `python3 scripts/check_links.py` | 检查内部链接有效性 |
| `python3 scripts/check_links.py` | 检查 Markdown 与组件内部链接有效性 |
| `python3 scripts/check_quality.py documents/` | 内容质量检查 |
| `python3 scripts/build_examples.py --host` | 编译主机侧 CMake 示例 |
| `python3 scripts/build_examples.py --stm32` | 编译 STM32 示例工程 |
Expand Down
15 changes: 8 additions & 7 deletions documents/en/vol1-fundamentals/ch03/index.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
---
title: Arrays and Strings
description: The evolution from C-style arrays to std::array and std::string
title: Function
description: Function definition, parameter passing, overloading, and constexpr functions
---
# Arrays and Strings
# Functions

Data needs to live somewhere, and arrays and strings are the most fundamental containers. In this chapter, we first review the underlying mechanics of C-style arrays—understanding exactly why they are so "bare"—and then jump straight to `std::array` to experience how sweet zero-overhead abstraction can be. The string section follows a similar path, transitioning from C-style strings to `std::string`. You will find that handling text in modern C++ is leagues ahead of C.
Functions are the fundamental units of code organization, and they represent our first step from "writing scripts" to "writing engineering code." In this chapter, we start with function definition and invocation, focusing on the different parameter passing mechanisms—by value, by reference, and by pointer. Understanding the differences between them is a prerequisite for writing efficient code. We then look at how function overloading and default parameters work together, and finally, we explore `inline` and `constexpr` functions, two keywords that appear frequently in embedded and performance-sensitive scenarios.

## Chapter Contents

<ChapterNav variant="sub">
<ChapterLink href="01-c-arrays">C-style Arrays</ChapterLink>
<ChapterLink href="02-std-array">std::array</ChapterLink>
<ChapterLink href="03-std-string">std::string</ChapterLink>
<ChapterLink href="01-function-basics">Function Basics</ChapterLink>
<ChapterLink href="02-pass-by-value-ref">Parameter Passing Mechanisms</ChapterLink>
<ChapterLink href="03-overloading-default">Overloading and Default Parameters</ChapterLink>
<ChapterLink href="04-inline-constexpr">inline and constexpr Functions</ChapterLink>
</ChapterNav>
15 changes: 7 additions & 8 deletions documents/en/vol1-fundamentals/ch05/index.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
---
title: Function
description: Function definition, parameter passing, overloading, and constexpr functions
title: Arrays and Strings
description: The evolution from C-style arrays to std::array and std::string
---
# Functions
# Arrays and Strings

Functions are the fundamental units of code organization, and they represent our first step from "writing scripts" to "writing engineering code." In this chapter, we start with function definition and invocation, focusing on the different parameter passing mechanisms—by value, by reference, and by pointer. Understanding the differences between them is a prerequisite for writing efficient code. We then look at how function overloading and default parameters work together, and finally, we explore `inline` and `constexpr` functions, two keywords that appear frequently in embedded and performance-sensitive scenarios.
Data needs to live somewhere, and arrays and strings are the most fundamental containers. In this chapter, we first review the underlying mechanics of C-style arrays—understanding exactly why they are so "bare"—and then jump straight to `std::array` to experience how sweet zero-overhead abstraction can be. The string section follows a similar path, transitioning from C-style strings to `std::string`. You will find that handling text in modern C++ is leagues ahead of C.

## Chapter Contents

<ChapterNav variant="sub">
<ChapterLink href="01-function-basics">Function Basics</ChapterLink>
<ChapterLink href="02-pass-by-value-ref">Parameter Passing Mechanisms</ChapterLink>
<ChapterLink href="03-overloading-default">Overloading and Default Parameters</ChapterLink>
<ChapterLink href="04-inline-constexpr">inline and constexpr Functions</ChapterLink>
<ChapterLink href="01-c-arrays">C-style Arrays</ChapterLink>
<ChapterLink href="02-std-array">std::array</ChapterLink>
<ChapterLink href="03-std-string">std::string</ChapterLink>
</ChapterNav>
11 changes: 6 additions & 5 deletions documents/vol1-fundamentals/ch11/index.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
---
title: "内存模型基础"
title: "STL 初见"
---

# 内存模型基础
# STL 初见

## 本章内容

<ChapterNav variant="sub">
<ChapterLink href="01-memory-layout">内存布局</ChapterLink>
<ChapterLink href="02-new-delete">动态内存管理</ChapterLink>
<ChapterLink href="03-alignment-padding">内存对齐与填充</ChapterLink>
<ChapterLink href="01-vector">std::vector 快速上手</ChapterLink>
<ChapterLink href="02-map-set">关联容器快速上手</ChapterLink>
<ChapterLink href="03-algorithms-intro">算法库初见</ChapterLink>
<ChapterLink href="04-stl-patterns">STL 常用模式</ChapterLink>
</ChapterNav>
11 changes: 5 additions & 6 deletions documents/vol1-fundamentals/ch12/index.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
---
title: "STL 初见"
title: "内存模型基础"
---

# STL 初见
# 内存模型基础

## 本章内容

<ChapterNav variant="sub">
<ChapterLink href="01-vector">std::vector 快速上手</ChapterLink>
<ChapterLink href="02-map-set">关联容器快速上手</ChapterLink>
<ChapterLink href="03-algorithms-intro">算法库初见</ChapterLink>
<ChapterLink href="04-stl-patterns">STL 常用模式</ChapterLink>
<ChapterLink href="01-memory-layout">内存布局</ChapterLink>
<ChapterLink href="02-new-delete">动态内存管理</ChapterLink>
<ChapterLink href="03-alignment-padding">内存对齐与填充</ChapterLink>
</ChapterNav>
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"type": "module",
"scripts": {
"dev": "vitepress dev site",
"build": "tsx scripts/build.ts",
"build:single": "vitepress build site",
"check:links": "python3 scripts/check_links.py",
"build": "pnpm check:links && tsx scripts/build.ts",
"build:single": "pnpm check:links && vitepress build site",
"preview": "vitepress preview site",
"hooks:install": "scripts/setup_precommit.sh",
"coverage": "python3 scripts/coverage.py",
Expand Down
156 changes: 81 additions & 75 deletions scripts/check_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class LinkChecker:
# Image extensions to check against filesystem
IMAGE_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.svg', '.bmp', '.webp', '.ico'}

# Files to skip from checking
SKIP_FILES = {'index.md', 'tags.md'}
# Files to skip from checking
SKIP_FILES = {'tags.md'}

def __init__(self, tutorial_dir: Path, fix: bool = False):
self.tutorial_dir = tutorial_dir
Expand Down Expand Up @@ -56,8 +56,13 @@ def extract_links(self, content: str, filepath: Path) -> List[Tuple[int, str, st
Returns: List of (line_number, link_text, link_url)
"""
links = []
# Match [text](url) and [text](<url>)
pattern = r'\[([^\]]+)\]\(([^)]+)\)|\[([^\]]+)\]\(<([^>]+)>\)'
# Match [text](url) and [text](<url>)
markdown_pattern = r'\[([^\]]+)\]\(([^)]+)\)|\[([^\]]+)\]\(<([^>]+)>\)'
# Match Vue components with literal href attributes, such as
# <ChapterLink href="01-vector">Title</ChapterLink>.
component_href_pattern = (
r'<([A-Z][\w.]*)\b[^>]*\bhref=(["\'])([^"\']+)\2'
)

in_code_block = False
for line_num, line in enumerate(content.split('\n'), 1):
Expand All @@ -72,34 +77,52 @@ def extract_links(self, content: str, filepath: Path) -> List[Tuple[int, str, st
# Strip inline code spans to avoid matching C++ syntax like `[&](args)`
cleaned = re.sub(r'`[^`]+`', '', line)

for match in re.finditer(pattern, cleaned):
groups = match.groups()
if groups[1]: # Regular link
link_text, link_url = groups[0], groups[1]
else: # Angle bracket link
link_text, link_url = groups[2], groups[3]

links.append((line_num, link_text, link_url))

return links

def normalize_path(self, link_url: str, source_file: Path) -> str:
"""Normalize a relative link path."""
# Remove fragments/anchors
link_url = link_url.split('#')[0]
if not link_url:
return ''

# Get source directory
source_dir = source_file.parent

# Resolve relative path
try:
resolved = (source_dir / link_url).resolve()
# Convert back to relative path from tutorial_dir
return str(resolved.relative_to(self.tutorial_dir))
except (ValueError, RuntimeError):
return link_url
for match in re.finditer(markdown_pattern, cleaned):
groups = match.groups()
if groups[1]: # Regular link
link_text, link_url = groups[0], groups[1]
else: # Angle bracket link
link_text, link_url = groups[2], groups[3]

links.append((line_num, link_text, link_url))

for match in re.finditer(component_href_pattern, cleaned):
component_name = match.group(1)
link_url = match.group(3)
links.append((line_num, component_name, link_url))

return links

def candidate_paths(self, link_url: str, source_file: Path) -> List[str]:
"""Return possible markdown targets for a link path."""
# Remove fragments/anchors
link_url = link_url.split('#')[0]
if not link_url:
return []

# VitePress treats a trailing slash as an index page.
link_url = link_url.rstrip('/')

if not link_url:
link_url = 'index'

if link_url.startswith('/'):
target = self.tutorial_dir / link_url.lstrip('/')
else:
target = source_file.parent / link_url

try:
resolved = target.resolve()
rel = resolved.relative_to(self.tutorial_dir)
except (ValueError, RuntimeError):
return [link_url]

candidates = [rel]
if rel.suffix != '.md':
candidates.append(rel.with_suffix('.md'))
candidates.append(rel / 'index.md')

return [str(candidate) for candidate in candidates]

def check_file(self, filepath: Path):
"""Check links in a single file."""
Expand All @@ -121,49 +144,32 @@ def check_file(self, filepath: Path):
continue

# Check image links against filesystem
link_ext = Path(link_url.split('#')[0]).suffix.lower()
if link_ext in self.IMAGE_EXTENSIONS:
normalized = self.normalize_path(link_url, filepath)
if normalized:
resolved = self.tutorial_dir / normalized
if not resolved.exists():
self.errors.append(
f"{rel_path}:{line_num} - Broken image: [{link_text}]({link_url})"
)
continue

# Normalize the link path
normalized = self.normalize_path(link_url, filepath)

if not normalized:
continue

# Check if file exists
if normalized not in self.all_files:
# Try with .md extension if missing
if not normalized.endswith('.md'):
normalized_with_md = normalized + '.md'
if normalized_with_md not in self.all_files:
self.errors.append(
f"{rel_path}:{line_num} - Broken link: [{link_text}]({link_url})"
)
else:
# Track for potential fix
self.warnings.append(
f"{rel_path}:{line_num} - Missing .md extension: [{link_text}]({link_url})"
)
if self.fix:
self.suggest_fix(filepath, line_num, link_url, link_url + '.md')
else:
self.errors.append(
f"{rel_path}:{line_num} - Broken link: [{link_text}]({link_url})"
)
else:
# Track valid link for reverse index
key = str(normalized)
if key not in self.link_map:
self.link_map[key] = []
self.link_map[key].append((filepath, link_text))
link_ext = Path(link_url.split('#')[0]).suffix.lower()
if link_ext in self.IMAGE_EXTENSIONS:
candidates = self.candidate_paths(link_url, filepath)
if candidates and not any((self.tutorial_dir / candidate).exists() for candidate in candidates):
self.errors.append(
f"{rel_path}:{line_num} - Broken image: [{link_text}]({link_url})"
)
continue

candidates = self.candidate_paths(link_url, filepath)

if not candidates:
continue

# Check if file exists
existing = next((candidate for candidate in candidates if candidate in self.all_files), None)
if existing is None:
self.errors.append(
f"{rel_path}:{line_num} - Broken link: [{link_text}]({link_url})"
)
else:
# Track valid link for reverse index
key = str(existing)
if key not in self.link_map:
self.link_map[key] = []
self.link_map[key].append((filepath, link_text))

def suggest_fix(self, filepath: Path, line_num: int, old_link: str, new_link: str):
"""Suggest a fix for a link."""
Expand Down
Loading