Skip to content

Commit cdf88bb

Browse files
committed
Add the cache generator subcommand and docs for custom syntaxes
1 parent 29a6006 commit cdf88bb

21 files changed

+2277
-704
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ tests/dummy_book/book/
1212
# Ignore Jetbrains specific files.
1313
.idea/
1414

15+
src/theme/syntaxes.bin
16+
1517
# Ignore Vim temporary and swap files.
1618
*.sw?
1719
*~

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ license = "MPL-2.0"
1414
readme = "README.md"
1515
repository = "https://github.com/rust-lang/mdBook"
1616
description = "Creates a book from markdown files"
17+
build = "build.rs"
18+
19+
[build-dependencies]
20+
syntect = { version = "4.6.0", default-features = false, features = ["regex-onig", "parsing", "html", "dump-load", "yaml-load", "dump-create", "assets"] }
1721

1822
[dependencies]
1923
anyhow = "1.0.28"
@@ -55,10 +59,11 @@ pretty_assertions = "0.6"
5559
walkdir = "2.0"
5660

5761
[features]
58-
default = ["watch", "serve", "search"]
62+
default = ["watch", "serve", "search", "gen-syntax-cache"]
5963
watch = ["notify", "gitignore"]
6064
serve = ["futures-util", "tokio", "warp"]
6165
search = ["elasticlunr-rs", "ammonia"]
66+
gen-syntax-cache = ["syntect/dump-create"]
6267

6368
[[bin]]
6469
doc = false

build.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use std::env;
2+
use std::error::Error;
3+
use syntect::dumps::dump_to_file;
4+
use syntect::parsing::SyntaxSet;
5+
6+
pub fn main() -> Result<(), Box<dyn Error>> {
7+
let src_dir = format!(
8+
"{}/src/theme/syntaxes/",
9+
env::var("CARGO_MANIFEST_DIR").unwrap()
10+
);
11+
let dest = format!("{}/syntaxes.bin", env::var("OUT_DIR").unwrap());
12+
13+
let mut builder = SyntaxSet::load_defaults_newlines().into_builder();
14+
builder.add_from_folder(&src_dir, true)?;
15+
dump_to_file(&builder.build(), dest)?;
16+
17+
Ok(())
18+
}

guide/src/format/theme/syntax-highlighting.md

Lines changed: 93 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Syntax Highlighting
22

3-
mdBook uses [Highlight.js](https://highlightjs.org) with a custom theme
3+
mdBook uses [syntect](https://docs.rs/syntect/4.6.0/syntect/) with a custom theme
44
for syntax highlighting.
55

66
Automatic language detection has been turned off, so you will probably want to
@@ -17,65 +17,103 @@ fn main() {
1717
## Supported languages
1818

1919
These languages are supported by default, but you can add more by supplying
20-
your own `highlight.js` file:
21-
22-
- apache
23-
- armasm
24-
- bash
25-
- c
26-
- coffeescript
27-
- cpp
28-
- csharp
29-
- css
30-
- d
31-
- diff
32-
- go
33-
- handlebars
34-
- haskell
35-
- http
36-
- ini
37-
- java
38-
- javascript
39-
- json
40-
- julia
41-
- kotlin
42-
- less
43-
- lua
44-
- makefile
45-
- markdown
46-
- nginx
47-
- objectivec
48-
- perl
49-
- php
50-
- plaintext
51-
- properties
52-
- python
53-
- r
54-
- ruby
55-
- rust
56-
- scala
57-
- scss
58-
- shell
59-
- sql
60-
- swift
61-
- typescript
62-
- x86asm
63-
- xml
64-
- yaml
20+
your own `.sublime-syntax` file:
21+
22+
<!-- this list is generated by running `cargo run -- gen-syntax-cache --syntaxes-only` -->
23+
<!-- which outputs a list of names -->
24+
25+
Name | Extensions
26+
-----|-----------
27+
Plain Text | txt
28+
ASP | asa
29+
HTML (ASP) | asp
30+
ActionScript | as
31+
AppleScript | applescript script editor
32+
Batch File | bat cmd
33+
NAnt Build File | build
34+
C# | cs csx
35+
C++ | cpp cc cp cxx c++ C h hh hpp hxx h++ inl ipp
36+
C | c h
37+
CSS | css css.erb css.liquid
38+
Clojure | clj
39+
D | d di
40+
Diff | diff patch
41+
Erlang | erl hrl Emakefile emakefile
42+
HTML (Erlang) | yaws
43+
Go | go
44+
Graphviz (DOT) | dot DOT gv
45+
Groovy | groovy gvy gradle
46+
HTML | html htm shtml xhtml inc tmpl tpl
47+
Haskell | hs
48+
Literate Haskell | lhs
49+
Java Server Page (JSP) | jsp
50+
Java | java bsh
51+
JavaDoc |
52+
Java Properties | properties
53+
JSON | json sublime-settings sublime-menu sublime-keymap sublime-mousemap sublime-theme sublime-build sublime-project sublime-completions sublime-commands sublime-macro sublime-color-scheme
54+
JavaScript | js htc
55+
Regular Expressions (Javascript) |
56+
BibTeX | bib
57+
LaTeX Log |
58+
LaTeX | tex ltx
59+
TeX | sty cls
60+
Lisp | lisp cl clisp l mud el scm ss lsp fasl
61+
Lua | lua
62+
Make Output |
63+
Makefile | make GNUmakefile makefile Makefile OCamlMakefile mak mk
64+
Markdown | md mdown markdown markdn
65+
MultiMarkdown |
66+
MATLAB | matlab
67+
OCaml | ml mli
68+
OCamllex | mll
69+
OCamlyacc | mly
70+
camlp4 |
71+
Objective-C++ | mm M h
72+
Objective-C | m h
73+
PHP Source |
74+
PHP | php php3 php4 php5 php7 phps phpt phtml
75+
Pascal | pas p dpr
76+
Perl | pl pm pod t PL
77+
Python | py py3 pyw pyi pyx pyx.in pxd pxd.in pxi pxi.in rpy cpy SConstruct Sconstruct sconstruct SConscript gyp gypi Snakefile script
78+
Regular Expressions (Python) |
79+
R Console |
80+
R | R r s S Rprofile
81+
Rd (R Documentation) | rd
82+
HTML (Rails) | rails rhtml erb html.erb
83+
JavaScript (Rails) | js.erb
84+
Ruby Haml | haml sass
85+
Ruby on Rails | rxml builder
86+
SQL (Rails) | erbsql sql.erb
87+
Regular Expression | re
88+
reStructuredText | rst rest
89+
Ruby | rb Appfile Appraisals Berksfile Brewfile capfile cgi Cheffile config.ru Deliverfile Fastfile fcgi Gemfile gemspec Guardfile irbrc jbuilder podspec prawn rabl rake Rakefile Rantfile rbx rjs ruby.rail Scanfile simplecov Snapfile thor Thorfile Vagrantfile
90+
Cargo Build Results |
91+
Rust | rs
92+
SQL | sql ddl dml
93+
Scala | scala sbt
94+
Bourne Again Shell (bash) | sh bash zsh fish .bash_aliases .bash_completions .bash_functions .bash_login .bash_logout .bash_profile .bash_variables .bashrc .profile .textmate_init
95+
Shell-Unix-Generic |
96+
commands-builtin-shell-bash |
97+
HTML (Tcl) | adp
98+
Tcl | tcl
99+
Textile | textile
100+
XML | xml xsd xslt tld dtml rss opml svg
101+
YAML | yaml yml sublime-syntax
102+
Handlebars | handlebars handlebars.html hbr hbrs hbs hdbs hjs mu mustache rac stache template tmpl]
65103

66104
## Custom theme
67-
Like the rest of the theme, the files used for syntax highlighting can be
68-
overridden with your own.
69105

70-
- ***highlight.js*** normally you shouldn't have to overwrite this file, unless
71-
you want to use a more recent version.
72-
- ***highlight.css*** theme used by highlight.js for syntax highlighting.
106+
Use the `gen-syntax-cache` command to compile sublime text syntax definitions and textmate theme files for mdbook.
73107

74-
If you want to use another theme for `highlight.js` download it from their
75-
website, or make it yourself, rename it to `highlight.css` and put it in
76-
the `theme` folder of your book.
108+
mdbook gen-syntax-cache --dest-dir=./theme ./syntax
77109

78-
Now your theme will be used instead of the default theme.
110+
The `gen-syntax-cache` will process every `tmTheme` file, and generate a similarly-named file in `[dest-dir]/css/syntax`,
111+
and will also process every `sublime-syntax` file and add it to the `syntaxes.bin` cache. When building your book,
112+
mdBook will look in the ./theme directory for the `syntaxes.bin` cache and use it, and will also copy across the generated
113+
CSS files.
114+
115+
mdBook includes, by default, the above standard syntax definitions when generating the `syntaxes.bin` cache. If you want to
116+
override all of the syntax definitions, pass the `--no-default-syntaxes` option.
79117

80118
## Hiding code lines
81119

src/cmd/gen_syntax_cache.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use clap::{App, ArgMatches, SubCommand};
2+
use mdbook::errors::Result;
3+
use std::env;
4+
use std::io::Cursor;
5+
use syntect::dumps::dump_to_file;
6+
use syntect::highlighting::ThemeSet;
7+
use syntect::html::css_for_theme_with_class_style;
8+
use syntect::html::ClassStyle;
9+
use syntect::parsing::{SyntaxSet, SyntaxSetBuilder};
10+
11+
// Create clap subcommand arguments
12+
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
13+
SubCommand::with_name("gen-syntax-cache")
14+
.about("Generate syntaxes.bin and css/syntax")
15+
.arg_from_usage(
16+
"-d, --dest-dir=[dir] 'Output directory for the syntax cache{n}\
17+
Relative paths are interpreted relative to the current working directory.{n}\
18+
If omitted, mdBook uses `.`.
19+
This command outputs files [dir]/syntaxes.bin and [dir]/css/syntax/*.css'",
20+
)
21+
.arg_from_usage("--syntaxes-only 'Only generate syntaxes.bin, not css/syntax/*.css.'")
22+
.arg_from_usage(
23+
"--no-default-syntaxes 'Don't include Sublime Text's default open source syntaxes{n}\
24+
If included, only syntaxes from [dir] are used.'",
25+
)
26+
.arg_from_usage("--themes-only 'Only generate themes, not syntaxes.bin.'")
27+
.arg_from_usage(
28+
"--no-default-themes 'Don't include mdbook's default light, dark, and ayu themes{n}\
29+
If included, only themes from [dir] are used.'",
30+
)
31+
.arg_from_usage(
32+
"[dir] 'Root directory for the syntax sources{n}\
33+
(Defaults to the Current Directory when omitted)'",
34+
)
35+
}
36+
37+
// Generate Syntax Cache command implementation
38+
pub fn execute(args: &ArgMatches) -> Result<()> {
39+
let src_dir = env::current_dir()
40+
.unwrap()
41+
.join(&format!("{}/", args.value_of("dir").unwrap_or(".")));
42+
let dest_dir = env::current_dir()
43+
.unwrap()
44+
.join(&format!("{}/", args.value_of("dest-dir").unwrap_or(".")));
45+
46+
if !args.is_present("themes-only") {
47+
let mut builder = if args.is_present("no-default-syntaxes") {
48+
SyntaxSetBuilder::new()
49+
} else {
50+
syntect::dumps::from_binary::<SyntaxSet>(mdbook::theme::SYNTAXES_BIN).into_builder()
51+
};
52+
builder.add_from_folder(&src_dir, true)?;
53+
let set = builder.build();
54+
for syntax in set.syntaxes() {
55+
info!(
56+
"supports syntax: {} [{}]",
57+
syntax.name,
58+
syntax.file_extensions.join(" ")
59+
);
60+
}
61+
dump_to_file(&set, dest_dir.join("syntaxes.bin"))?;
62+
}
63+
64+
if !args.is_present("syntaxes-only") {
65+
let mut builder = ThemeSet::load_from_folder(&src_dir)?;
66+
if !args.is_present("no-default-themes") {
67+
if !builder.themes.contains_key("light") {
68+
let light = ThemeSet::load_from_reader(&mut Cursor::new(
69+
mdbook::theme::SYNTAX_THEME_LIGHT,
70+
))?;
71+
builder.themes.insert(String::from("light"), light);
72+
}
73+
if !builder.themes.contains_key("dark") {
74+
let dark =
75+
ThemeSet::load_from_reader(&mut Cursor::new(mdbook::theme::SYNTAX_THEME_DARK))?;
76+
builder.themes.insert(String::from("dark"), dark);
77+
}
78+
if !builder.themes.contains_key("ayu") {
79+
let ayu =
80+
ThemeSet::load_from_reader(&mut Cursor::new(mdbook::theme::SYNTAX_THEME_AYU))?;
81+
builder.themes.insert(String::from("ayu"), ayu);
82+
}
83+
}
84+
for (name, theme) in builder.themes.iter() {
85+
info!("supports theme: {}", name);
86+
std::fs::write(
87+
dest_dir.join(format!("css/syntax/{}.css", name)),
88+
css_for_theme_with_class_style(
89+
theme,
90+
ClassStyle::SpacedPrefixed { prefix: "syn-" },
91+
),
92+
)?;
93+
}
94+
}
95+
96+
Ok(())
97+
}

src/cmd/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
pub mod build;
44
pub mod clean;
5+
#[cfg(feature = "gen-syntax-cache")]
6+
pub mod gen_syntax_cache;
57
pub mod init;
68
#[cfg(feature = "serve")]
79
pub mod serve;

src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ fn main() {
3333
#[cfg(feature = "serve")]
3434
("serve", Some(sub_matches)) => cmd::serve::execute(sub_matches),
3535
("test", Some(sub_matches)) => cmd::test::execute(sub_matches),
36+
#[cfg(feature = "gen_syntax_cache")]
37+
("gen-syntax-cache", Some(sub_matches)) => cmd::gen_syntax_cache::execute(sub_matches),
3638
("completions", Some(sub_matches)) => (|| {
3739
let shell: Shell = sub_matches
3840
.value_of("shell")
@@ -87,6 +89,8 @@ fn create_clap_app<'a, 'b>() -> App<'a, 'b> {
8789
let app = app.subcommand(cmd::watch::make_subcommand());
8890
#[cfg(feature = "serve")]
8991
let app = app.subcommand(cmd::serve::make_subcommand());
92+
#[cfg(feature = "gen-syntax-cache")]
93+
let app = app.subcommand(cmd::gen_syntax_cache::make_subcommand());
9094

9195
app
9296
}

0 commit comments

Comments
 (0)