Skip to content

Commit 9143494

Browse files
authored
Merge pull request #7 from copper-project/nico/script-insert-chapters
Add script to insert a chapter
2 parents 14f297a + aad62d5 commit 9143494

2 files changed

Lines changed: 170 additions & 9 deletions

File tree

CONTRIBUTING.md

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,51 @@ Thanks for your interest in improving the Copper Book! Contributions of all kind
66

77
- [Rust](https://rust-lang.org/tools/install/)
88
- [mdBook](https://rust-lang.github.io/mdBook/)
9+
- [just](https://github.com/casey/just) (command runner)
910

10-
Install mdBook:
11+
Install the tools:
1112

1213
```bash
13-
cargo install mdbook
14+
cargo install mdbook just
1415
```
1516

1617
## Building locally
1718

19+
Run `just` to see all available commands:
20+
21+
```bash
22+
just
23+
```
24+
1825
Build the book:
1926

2027
```bash
21-
cd book
22-
mdbook build
28+
just build
2329
```
2430

25-
The HTML output is generated in `book/output/`.
31+
Serve locally with live-reload:
32+
33+
```bash
34+
just serve
35+
```
36+
37+
This starts a local server (default: `http://localhost:3000`) and opens the book in your browser. Edits to files in `book/src/` trigger an automatic rebuild.
38+
39+
## Inserting a new chapter
40+
41+
To insert a chapter and automatically renumber everything (files, SUMMARY.md, cross-references):
42+
43+
```bash
44+
just insert-chapter <number> <slug> [title]
45+
```
2646

27-
To serve the book locally with live-reload:
47+
For example, to insert a new chapter 6:
2848

2949
```bash
30-
cd book
31-
mdbook serve --open
50+
just insert-chapter 6 my-new-topic "My New Topic"
3251
```
3352

34-
This starts a local development server (default: `http://localhost:3000`) and opens the book in your browser. Any edits to the Markdown source files in `book/src/` will automatically trigger a rebuild and refresh.
53+
This creates `book/src/ch06-my-new-topic.md` and bumps all subsequent chapters up by one.
3554

3655
## How to contribute
3756

justfile

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Default recipe: list available commands
2+
default:
3+
@just --list
4+
5+
# Build the book
6+
build:
7+
cd book && mdbook build
8+
9+
# Serve the book locally with live-reload
10+
serve:
11+
cd book && mdbook serve --open
12+
13+
# Insert a new chapter at the given number and renumber the rest
14+
[doc("insert-chapter <number> <slug> [title] e.g. just insert-chapter 6 my-new-topic \"My New Topic\"")]
15+
insert-chapter number slug title="":
16+
#!/usr/bin/env bash
17+
set -euo pipefail
18+
19+
SRC_DIR="book/src"
20+
NEW_NUM="{{ number }}"
21+
SLUG="{{ slug }}"
22+
23+
# Derive title: use the explicit argument, or generate from slug
24+
if [[ -n "{{ title }}" ]]; then
25+
TITLE="{{ title }}"
26+
else
27+
TITLE=$(echo "$SLUG" | sed 's/-/ /g; s/\b\(.\)/\u\1/g')
28+
fi
29+
30+
# Validate NEW_NUM is a positive integer
31+
if ! [[ "$NEW_NUM" =~ ^[0-9]+$ ]] || [[ "$NEW_NUM" -eq 0 ]]; then
32+
echo "Error: chapter number must be a positive integer, got '$NEW_NUM'" >&2
33+
exit 1
34+
fi
35+
36+
# ── Discover highest chapter number ──────────────────────────────
37+
HIGHEST=$(ls "$SRC_DIR"/ch[0-9][0-9]-*.md 2>/dev/null \
38+
| sed 's|.*/ch\([0-9]*\)-.*|\1|' \
39+
| sort -n \
40+
| tail -1)
41+
42+
if [[ -z "$HIGHEST" ]]; then
43+
echo "Error: no chapter files found in $SRC_DIR" >&2
44+
exit 1
45+
fi
46+
47+
HIGHEST=$((10#$HIGHEST))
48+
49+
if [[ $NEW_NUM -gt $((HIGHEST + 1)) ]]; then
50+
echo "Error: chapter $NEW_NUM is too high; highest existing chapter is $HIGHEST." >&2
51+
echo " Use $((HIGHEST + 1)) to append at the end." >&2
52+
exit 1
53+
fi
54+
55+
NEW_FILE=$(printf "ch%02d-%s.md" "$NEW_NUM" "$SLUG")
56+
57+
echo "Inserting new chapter: $SRC_DIR/$NEW_FILE (chapter $NEW_NUM)"
58+
if [[ $NEW_NUM -le $HIGHEST ]]; then
59+
echo "Renumbering chapters $NEW_NUM..$HIGHEST$((NEW_NUM + 1))..$((HIGHEST + 1))"
60+
fi
61+
echo ""
62+
63+
# ── Phase 1: Rename files (highest → lowest to avoid collisions) ─
64+
for (( i=HIGHEST; i>=NEW_NUM; i-- )); do
65+
OLD_PREFIX=$(printf "ch%02d" "$i")
66+
NEW_PREFIX=$(printf "ch%02d" "$((i + 1))")
67+
68+
OLD_FILE=$(ls "$SRC_DIR"/${OLD_PREFIX}-*.md 2>/dev/null | head -1)
69+
if [[ -z "$OLD_FILE" ]]; then
70+
echo "Warning: no file found for $OLD_PREFIX, skipping rename" >&2
71+
continue
72+
fi
73+
74+
OLD_BASENAME=$(basename "$OLD_FILE")
75+
NEW_BASENAME="${NEW_PREFIX}${OLD_BASENAME#${OLD_PREFIX}}"
76+
77+
echo " rename: $OLD_BASENAME$NEW_BASENAME"
78+
mv "$SRC_DIR/$OLD_BASENAME" "$SRC_DIR/$NEW_BASENAME"
79+
done
80+
81+
# ── Phase 2: Update references in all .md files ──────────────────
82+
# Process from highest down to avoid double-replacing
83+
echo ""
84+
echo "Updating cross-references in .md files..."
85+
86+
for (( i=HIGHEST; i>=NEW_NUM; i-- )); do
87+
OLD_PREFIX=$(printf "ch%02d" "$i")
88+
NEW_PREFIX=$(printf "ch%02d" "$((i + 1))")
89+
90+
find "$SRC_DIR" -name '*.md' -exec \
91+
sed -i "s|${OLD_PREFIX}-|${NEW_PREFIX}-|g" {} +
92+
93+
find "$SRC_DIR" -name '*.md' -exec \
94+
sed -i "s|Chapter ${i}\\b|Chapter $((i + 1))|g" {} +
95+
done
96+
97+
# ── Phase 3: Create the new chapter file ─────────────────────────
98+
echo ""
99+
echo "Creating $SRC_DIR/$NEW_FILE"
100+
101+
cat > "$SRC_DIR/$NEW_FILE" << EOF
102+
# $TITLE
103+
104+
<!-- TODO: Write chapter content -->
105+
EOF
106+
107+
# ── Phase 4: Insert into SUMMARY.md ──────────────────────────────
108+
SUMMARY="$SRC_DIR/SUMMARY.md"
109+
PREV=$((NEW_NUM - 1))
110+
111+
if [[ "$PREV" -eq 0 ]]; then
112+
# Inserting as ch01: place before what is now ch02
113+
ANCHOR_PREFIX=$(printf "ch%02d" "$((NEW_NUM + 1))")
114+
ANCHOR_LINE=$(grep -n "${ANCHOR_PREFIX}-" "$SUMMARY" | head -1 | cut -d: -f1)
115+
if [[ -n "$ANCHOR_LINE" ]]; then
116+
NEW_ENTRY="- [$TITLE](./$NEW_FILE)"
117+
sed -i "${ANCHOR_LINE}i\\${NEW_ENTRY}" "$SUMMARY"
118+
echo "Inserted into SUMMARY.md before line $ANCHOR_LINE"
119+
else
120+
echo "Warning: could not find anchor in SUMMARY.md to insert new entry" >&2
121+
fi
122+
else
123+
# Insert after the previous chapter
124+
ANCHOR_PREFIX=$(printf "ch%02d" "$PREV")
125+
ANCHOR_LINE=$(grep -n "${ANCHOR_PREFIX}-" "$SUMMARY" | head -1 | cut -d: -f1)
126+
if [[ -n "$ANCHOR_LINE" ]]; then
127+
NEW_ENTRY="- [$TITLE](./$NEW_FILE)"
128+
sed -i "${ANCHOR_LINE}a\\${NEW_ENTRY}" "$SUMMARY"
129+
echo "Inserted into SUMMARY.md after line $ANCHOR_LINE"
130+
else
131+
echo "Warning: could not find anchor in SUMMARY.md to insert new entry" >&2
132+
fi
133+
fi
134+
135+
# ── Done ─────────────────────────────────────────────────────────
136+
echo ""
137+
echo "Done! New chapter $NEW_NUM created at $SRC_DIR/$NEW_FILE"
138+
echo ""
139+
echo "Next steps:"
140+
echo " 1. Edit $SRC_DIR/$NEW_FILE with your content"
141+
echo " 2. Review SUMMARY.md to make sure the entry is in the right section"
142+
echo " 3. Check cross-references with: grep -rn 'ch[0-9]' $SRC_DIR/*.md"

0 commit comments

Comments
 (0)