Fix book links (#1227)
This commit is contained in:
parent
2710df4207
commit
c710d5a685
10
.github/workflows/ci.yaml
vendored
10
.github/workflows/ci.yaml
vendored
@ -80,6 +80,16 @@ jobs:
|
||||
with:
|
||||
mdbook-version: latest
|
||||
|
||||
- name: Install `mdbook-linkcheck`
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
mkdir -p mdbook-linkcheck
|
||||
cd mdbook-linkcheck
|
||||
wget https://github.com/Michael-F-Bryan/mdbook-linkcheck/releases/latest/download/mdbook-linkcheck.x86_64-unknown-linux-gnu.zip
|
||||
unzip mdbook-linkcheck.x86_64-unknown-linux-gnu.zip
|
||||
chmod +x mdbook-linkcheck
|
||||
pwd >> $GITHUB_PATH
|
||||
|
||||
- name: Build book
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,8 @@
|
||||
/.vagrant
|
||||
/README.html
|
||||
/book/en/build
|
||||
/book/en/src
|
||||
/book/zh/build
|
||||
/book/zh/src
|
||||
/fuzz/artifacts
|
||||
/fuzz/corpus
|
||||
@ -9,4 +11,3 @@
|
||||
/test-utilities/Cargo.lock
|
||||
/test-utilities/target
|
||||
/tmp
|
||||
/www/man
|
||||
|
12
README.md
12
README.md
@ -313,7 +313,7 @@ Kakoune supports `justfile` syntax highlighting out of the box, thanks to TeddyD
|
||||
|
||||
### Sublime Text
|
||||
|
||||
A syntax file for Sublime Text written by TonioGela is available in [extras/just.sublime-syntax](extras/just.sublime-syntax).
|
||||
A syntax file for Sublime Text written by TonioGela is available in [extras/just.sublime-syntax](https://github.com/casey/just/blob/master/extras/just.sublime-syntax).
|
||||
|
||||
### Other Editors
|
||||
|
||||
@ -940,7 +940,7 @@ $ just system-info
|
||||
This is an x86_64 machine
|
||||
```
|
||||
|
||||
The `os_family()` function can be used to create cross-platform `justfile`s that work on various operating systems. For an example, see [cross-platform.just](examples/cross-platform.just) file.
|
||||
The `os_family()` function can be used to create cross-platform `justfile`s that work on various operating systems. For an example, see [cross-platform.just](https://github.com/casey/just/blob/master/examples/cross-platform.just) file.
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
@ -1946,7 +1946,7 @@ complete -F _just -o bashdefault -o default j
|
||||
|
||||
### Shell Completion Scripts
|
||||
|
||||
Shell completion scripts for Bash, Zsh, Fish, PowerShell, and Elvish are available in the [completions](completions) directory. Please refer to your shell's documentation for how to install them.
|
||||
Shell completion scripts for Bash, Zsh, Fish, PowerShell, and Elvish are available in the [completions](https://github.com/casey/just/tree/master/completions) directory. Please refer to your shell's documentation for how to install them.
|
||||
|
||||
The `just` binary can also generate the same completion scripts at runtime, using the `--completions` command:
|
||||
|
||||
@ -1956,11 +1956,11 @@ $ just --completions zsh > just.zsh
|
||||
|
||||
### Grammar
|
||||
|
||||
A non-normative grammar of `justfile`s can be found in [GRAMMAR.md](GRAMMAR.md).
|
||||
A non-normative grammar of `justfile`s can be found in [GRAMMAR.md](https://github.com/casey/just/blob/master/GRAMMAR.md).
|
||||
|
||||
### just.sh
|
||||
|
||||
Before `just` was a fancy Rust program it was a tiny shell script that called `make`. You can find the old version in [extras/just.sh](extras/just.sh).
|
||||
Before `just` was a fancy Rust program it was a tiny shell script that called `make`. You can find the old version in [extras/just.sh](https://github.com/casey/just/blob/master/extras/just.sh).
|
||||
|
||||
### User `justfile`s
|
||||
|
||||
@ -2099,7 +2099,7 @@ Some ideas for recipes:
|
||||
|
||||
Even for small, personal projects it's nice to be able to remember commands by name instead of ^Reverse searching your shell history, and it's a huge boon to be able to go into an old project written in a random language with a mysterious build system and know that all the commands you need to do whatever you need to do are in the `justfile`, and that if you type `just` something useful (or at least interesting!) will probably happen.
|
||||
|
||||
For ideas for recipes, check out [this project's `justfile`](justfile), or some of the `justfile`s [out in the wild](https://github.com/search?o=desc&q=filename%3Ajustfile&s=indexed&type=Code).
|
||||
For ideas for recipes, check out [this project's `justfile`](https://github.com/casey/just/blob/master/justfile), or some of the `justfile`s [out in the wild](https://github.com/search?o=desc&q=filename%3Ajustfile&s=indexed&type=Code).
|
||||
|
||||
Anyways, I think that's about it for this incredibly long-winded README.
|
||||
|
||||
|
12
README.中文.md
12
README.中文.md
@ -309,7 +309,7 @@ Kakoune 已经内置支持 `justfile` 语法高亮,这要感谢 TeddyDD。
|
||||
|
||||
### Sublime Text
|
||||
|
||||
由 TonioGela 编写的 Sublime Text 的语法高亮文件在 [extras/just.sublim-syntax](extras/just.sublim-syntax) 中提供。
|
||||
由 TonioGela 编写的 Sublime Text 的语法高亮文件在 [extras/just.sublim-syntax](https://github.com/casey/just/blob/master/extras/just.sublime-syntax) 中提供。
|
||||
|
||||
### 其它编辑器
|
||||
|
||||
@ -936,7 +936,7 @@ $ just system-info
|
||||
This is an x86_64 machine
|
||||
```
|
||||
|
||||
`os_family()` 函数可以用来创建跨平台的 `justfile`,使其可以在不同的操作系统上工作。一个例子,见 [cross-platform.just](examples/cross-platform.just) 文件。
|
||||
`os_family()` 函数可以用来创建跨平台的 `justfile`,使其可以在不同的操作系统上工作。一个例子,见 [cross-platform.just](https://github.com/casey/just/blob/master/examples/cross-platform.just) 文件。
|
||||
|
||||
#### 环境变量
|
||||
|
||||
@ -1941,7 +1941,7 @@ complete -F _just -o bashdefault -o default j
|
||||
|
||||
### Shell 自动补全脚本
|
||||
|
||||
Bash、Zsh、Fish、PowerShell 和 Elvish 的 Shell 自动补全脚本可以在 [自动补全](completions) 目录下找到。关于如何安装它们,请参考你的 Shell 文档。
|
||||
Bash、Zsh、Fish、PowerShell 和 Elvish 的 Shell 自动补全脚本可以在 [自动补全](https://github.com/casey/just/tree/master/completions) 目录下找到。关于如何安装它们,请参考你的 Shell 文档。
|
||||
|
||||
`just` 二进制文件也可以在运行时生成相同的自动补全脚本,使用 `--completions` 命令即可,如下:
|
||||
|
||||
@ -1951,11 +1951,11 @@ $ just --completions zsh > just.zsh
|
||||
|
||||
### 语法
|
||||
|
||||
在 [GRAMMAR.md](GRAMMAR.md) 中可以找到一个非正式的 `justfile` 语法说明。
|
||||
在 [GRAMMAR.md](https://github.com/casey/just/blob/master/GRAMMAR.md) 中可以找到一个非正式的 `justfile` 语法说明。
|
||||
|
||||
### just.sh
|
||||
|
||||
在 `just` 成为一个精致的 Rust 程序之前,它是一个很小的 Shell 脚本,叫 `make`。你可以在 [extras/just.sh](extras/just.sh) 中找到旧版本。
|
||||
在 `just` 成为一个精致的 Rust 程序之前,它是一个很小的 Shell 脚本,叫 `make`。你可以在 [extras/just.sh](https://github.com/casey/just/blob/master/extras/just.sh) 中找到旧版本。
|
||||
|
||||
### 用户 `justfile`
|
||||
|
||||
@ -2094,7 +2094,7 @@ make: `test' is up to date.
|
||||
|
||||
即使是小型的个人项目,能够通过名字记住命令,而不是通过 ^Reverse 搜索你的 Shell 历史,这也是一个巨大的福音,能够进入一个用任意语言编写的旧项目,并知道你需要用到的所有命令都在 `justfile` 中,如果你输入 `just`,就可能会输出一些有用的(或至少是有趣的!)信息。
|
||||
|
||||
关于配方的想法,请查看 [这个项目的 `justfile`](justfile),或一些 [在其他项目里](https://github.com/search?o=desc&q=filename%3Ajustfile&s=indexed&type=Code) 的 `justfile`。
|
||||
关于配方的想法,请查看 [这个项目的 `justfile`](https://github.com/casey/just/blob/master/justfile),或一些 [在其他项目里](https://github.com/search?o=desc&q=filename%3Ajustfile&s=indexed&type=Code) 的 `justfile`。
|
||||
|
||||
总之,我想这个令人难以置信地啰嗦的 README 就到此为止了。
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
use {
|
||||
pulldown_cmark::{
|
||||
Event,
|
||||
HeadingLevel::{H2, H3},
|
||||
Options, Parser, Tag,
|
||||
},
|
||||
pulldown_cmark::{CowStr, Event, HeadingLevel, Options, Parser, Tag},
|
||||
pulldown_cmark_to_cmark::cmark,
|
||||
std::{error::Error, fs},
|
||||
std::{collections::BTreeMap, error::Error, fs, ops::Deref},
|
||||
};
|
||||
|
||||
type Result<T = ()> = std::result::Result<T, Box<dyn Error>>;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum Language {
|
||||
English,
|
||||
Chinese,
|
||||
@ -36,7 +35,61 @@ impl Language {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
#[derive(Debug)]
|
||||
struct Chapter<'a> {
|
||||
level: HeadingLevel,
|
||||
events: Vec<Event<'a>>,
|
||||
index: usize,
|
||||
language: Language,
|
||||
}
|
||||
|
||||
impl<'a> Chapter<'a> {
|
||||
fn title(&self) -> String {
|
||||
if self.index == 0 {
|
||||
return self.language.introduction().into();
|
||||
}
|
||||
|
||||
self
|
||||
.events
|
||||
.iter()
|
||||
.skip_while(|event| !matches!(event, Event::Start(Tag::Heading(..))))
|
||||
.skip(1)
|
||||
.take_while(|event| !matches!(event, Event::End(Tag::Heading(..))))
|
||||
.filter_map(|event| match event {
|
||||
Event::Code(content) | Event::Text(content) => Some(content.deref()),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn number(&self) -> usize {
|
||||
self.index + 1
|
||||
}
|
||||
|
||||
fn markdown(&self) -> Result<String> {
|
||||
let mut markdown = String::new();
|
||||
cmark(self.events.iter(), &mut markdown)?;
|
||||
if self.index == 0 {
|
||||
markdown = markdown.split_inclusive('\n').skip(1).collect::<String>();
|
||||
}
|
||||
Ok(markdown)
|
||||
}
|
||||
}
|
||||
|
||||
fn slug(s: &str) -> String {
|
||||
let mut slug = String::new();
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'A'..='Z' => slug.extend(c.to_lowercase()),
|
||||
' ' => slug.push('-'),
|
||||
'?' | '.' | '?' => {}
|
||||
_ => slug.push(c),
|
||||
}
|
||||
}
|
||||
slug
|
||||
}
|
||||
|
||||
fn main() -> Result {
|
||||
for language in [Language::English, Language::Chinese] {
|
||||
let src = format!("book/{}/src", language.code());
|
||||
fs::remove_dir_all(&src).ok();
|
||||
@ -44,34 +97,88 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let txt = fs::read_to_string(format!("README{}.md", language.suffix()))?;
|
||||
|
||||
let mut chapters = vec![(1usize, Vec::new())];
|
||||
let mut chapters = vec![Chapter {
|
||||
level: HeadingLevel::H1,
|
||||
events: Vec::new(),
|
||||
index: 0,
|
||||
language,
|
||||
}];
|
||||
|
||||
for event in Parser::new_ext(&txt, Options::all()) {
|
||||
if let Event::Start(Tag::Heading(level @ (H2 | H3), ..)) = event {
|
||||
chapters.push((if level == H2 { 2 } else { 3 }, Vec::new()));
|
||||
if let Event::Start(Tag::Heading(level @ (HeadingLevel::H2 | HeadingLevel::H3), ..)) = event {
|
||||
let index = chapters.last().unwrap().index + 1;
|
||||
chapters.push(Chapter {
|
||||
level,
|
||||
events: Vec::new(),
|
||||
index,
|
||||
language,
|
||||
});
|
||||
}
|
||||
chapters.last_mut().unwrap().events.push(event);
|
||||
}
|
||||
|
||||
let mut links = BTreeMap::new();
|
||||
|
||||
for chapter in &chapters {
|
||||
let mut current = None;
|
||||
for event in &chapter.events {
|
||||
match event {
|
||||
Event::Start(Tag::Heading(..)) => current = Some(Vec::new()),
|
||||
Event::End(Tag::Heading(level, ..)) => {
|
||||
let events = current.unwrap();
|
||||
let title = events
|
||||
.iter()
|
||||
.filter_map(|event| match event {
|
||||
Event::Code(content) | Event::Text(content) => Some(content.deref()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<String>();
|
||||
let slug = slug(&title);
|
||||
let link = if let HeadingLevel::H1 | HeadingLevel::H2 | HeadingLevel::H3 = level {
|
||||
format!("chapter_{}.html", chapter.number())
|
||||
} else {
|
||||
format!("chapter_{}.html#{}", chapter.number(), slug)
|
||||
};
|
||||
links.insert(slug, link);
|
||||
current = None;
|
||||
}
|
||||
_ => {
|
||||
if let Some(events) = &mut current {
|
||||
events.push(event.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for chapter in &mut chapters {
|
||||
for event in &mut chapter.events {
|
||||
if let Event::Start(Tag::Link(_, dest, _)) | Event::End(Tag::Link(_, dest, _)) = event {
|
||||
if let Some(anchor) = dest.clone().strip_prefix('#') {
|
||||
*dest = CowStr::Borrowed(&links[anchor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
chapters.last_mut().unwrap().1.push(event);
|
||||
}
|
||||
|
||||
let mut summary = String::new();
|
||||
|
||||
for (i, (level, chapter)) in chapters.into_iter().enumerate() {
|
||||
let mut txt = String::new();
|
||||
cmark(chapter.iter(), &mut txt)?;
|
||||
let title = if i == 0 {
|
||||
txt = txt.split_inclusive('\n').skip(1).collect::<String>();
|
||||
language.introduction()
|
||||
} else {
|
||||
txt.lines().next().unwrap().split_once(' ').unwrap().1
|
||||
for chapter in chapters {
|
||||
let path = format!("{}/chapter_{}.md", src, chapter.number());
|
||||
fs::write(&path, &chapter.markdown()?)?;
|
||||
let indent = match chapter.level {
|
||||
HeadingLevel::H1 => 0,
|
||||
HeadingLevel::H2 => 1,
|
||||
HeadingLevel::H3 => 2,
|
||||
HeadingLevel::H4 => 3,
|
||||
HeadingLevel::H5 => 4,
|
||||
HeadingLevel::H6 => 5,
|
||||
};
|
||||
|
||||
let path = format!("{}/chapter_{}.md", src, i + 1);
|
||||
fs::write(&path, &txt)?;
|
||||
summary.push_str(&format!(
|
||||
"{}- [{}](chapter_{}.md)\n",
|
||||
" ".repeat((level.saturating_sub(1)) * 4),
|
||||
title,
|
||||
i + 1
|
||||
" ".repeat(indent * 4),
|
||||
chapter.title(),
|
||||
chapter.number()
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -5,4 +5,8 @@ src = "src"
|
||||
title = "Just Programmer's Manual"
|
||||
|
||||
[build]
|
||||
build-dir = "../../www/man/en"
|
||||
build-dir = "build"
|
||||
|
||||
[output.html]
|
||||
|
||||
[output.linkcheck]
|
||||
|
@ -5,4 +5,8 @@ src = "src"
|
||||
title = "Just 用户指南"
|
||||
|
||||
[build]
|
||||
build-dir = "../../www/man/zh"
|
||||
build-dir = "build"
|
||||
|
||||
[output.html]
|
||||
|
||||
[output.linkcheck]
|
||||
|
5
justfile
5
justfile
@ -165,6 +165,11 @@ watch-readme:
|
||||
generate-completions:
|
||||
./bin/generate-completions
|
||||
|
||||
build-book:
|
||||
cargo run --package generate-book
|
||||
mdbook build book/en
|
||||
mdbook build book/zh
|
||||
|
||||
# run all polyglot recipes
|
||||
polyglot: _python _js _perl _sh _ruby
|
||||
# (recipes that start with `_` are hidden from --list)
|
||||
|
1
www/man/en
Symbolic link
1
www/man/en
Symbolic link
@ -0,0 +1 @@
|
||||
../../book/en/build/html/
|
1
www/man/zh
Symbolic link
1
www/man/zh
Symbolic link
@ -0,0 +1 @@
|
||||
../../book/zh/build/html/
|
Loading…
Reference in New Issue
Block a user