two_face/lib.rs
1//! Dedicated to chasing the [`bat` man](https://github.com/sharkdp)
2//!
3//! Extra syntax and theme definitions for
4//! [`syntect`] including many common ones
5//! that are missing from the default set like TOML, TypeScript, and Dockerfile.
6//! Curated by the [`bat` Project](https://github.com/sharkdp/bat)
7//!
8//! You can think of this crate like a bundle `bat`'s `syntaxes.bin` and
9//! `themes.bin` files, but with proper versioning, dependency tracking, and
10//! feature flags with some extra functionality sprinkled in too
11//!
12//! ## Example
13//!
14//! The following
15//!
16//! ```cmd
17//! $ cargo add two-face --features syntect-default-onig
18//! ```
19//!
20//! ```
21//! use two_face::re_exports::syntect;
22//!
23//! const TOML_TEXT: &str = "\
24//! [section]
25//! key = 123
26//! ";
27//!
28//! fn main() {
29//! let syn_set = two_face::syntax::extra_newlines();
30//! let theme_set = two_face::theme::extra();
31//!
32//! let syn_ref = syn_set.find_syntax_by_extension("toml").unwrap();
33//! let theme = &theme_set[two_face::theme::EmbeddedThemeName::Nord];
34//! let htmlified = syntect::html::highlighted_html_for_string(
35//! TOML_TEXT,
36//! &syn_set,
37//! syn_ref,
38//! theme
39//! ).unwrap();
40//!
41//! // Where `htmlified` displays as vv
42//! # assert_eq!(htmlified, "<pre style=\"background-color:#2e3440;\">\n<span style=\"color:#d8dee9;\">[section]\n</span><span style=\"color:#81a1c1;\">key </span><span style=\"color:#d8dee9;\">= </span><span style=\"color:#b48ead;\">123\n</span></pre>\n");
43//! }
44//! ```
45//!
46//! where `htmlified` is
47//!
48//! ```html
49//! <pre style="background-color:#2e3440;">
50//! <span style="color:#d8dee9;">[section]
51//! </span><span style="color:#81a1c1;">key </span><span style="color:#d8dee9;">= </span><span style="color:#b48ead;">123
52//! </span></pre>
53//! ```
54//!
55//! which renders as
56//!
57//! <pre style="background-color:#2e3440;">
58//! <span style="color:#d8dee9;">[section]
59//! </span><span style="color:#81a1c1;">key </span><span style="color:#d8dee9;">= </span><span style="color:#b48ead;">123
60//! </span></pre>
61//!
62//!
63//! ## Feature Flags
64//!
65//! The feature flags are divided by `syntect`'s underlying regex implementation
66//! with [`Oniguruma`](https://github.com/kkos/oniguruma) aka `onig` being the
67//! default and [`fancy-regex`](https://github.com/fancy-regex/fancy-regex) aka
68//! `fancy` as an alternative pure-Rust implementation. `fancy`: however, doesn't
69//! support all of the features used by some of the syntax definitions, so some of
70//! the definitions are excluded when `fancy` is selected\* to keep the regex
71//! compilation infallible. This means that it's important to match whichever regex
72//! implementation `syntect` is using
73//!
74//! _\* This is also why fancy's bundled syntax definitions are smaller than onig's_
75//!
76//! default: `syntect-onig`
77//!
78//! | Feature | Desc. |
79//! | :---: | :--- |
80//! | `syntect-onig` / `syntect-fancy` | Enables the minimal feature set that we require from `syntect` |
81//! | `syntect-default-onig` / `syntect-default-fancy` | The minimal feature sets along with `syntect`'s default feature set (useful when using the `syntect` re-export) |
82//!
83//! ## Embedded Asset Sizes
84//!
85//! This crate embeds some reasonably large assets in the final binary in order to
86//! work. Luckily the linker is smart enough to discard unused assets, so you
87//! generally only pay for what you use
88//!
89//! For reference here are the sizes associated with their different functions
90//!
91//! | function | `two-face` (KiB) | `syntect` (KiB) |
92//! | ---: | ---: | ---: |
93//! | [`acknowledgement::listing()`] | 11 | - |
94//! | [`syntax::extra_newlines()`] (onig) | 961 | 360 |
95//! | ^^ (fancy) | 937 | ^^ |
96//! | [`syntax::extra_no_newlines()`] (onig) | 959 | 359 |
97//! | ^^ (fancy) | 935 | ^^ |
98//! | [`theme::extra()`] | 61 | 5 |
99//!
100//! In short the syntax definitions are the real chonky part, and if you're
101//! switching from `syntect` to `two-face`, then you can expect a ~0.6MiB increase
102//! in binary size from them (in exchange for _a lot_ of syntax definitions)
103//!
104//! ## Syntaxes
105//!
106//! The full listing of all syntaxes included in [`syntax`]
107//!
108//! - \* Excluded when using the `fancy-regex` implementation
109//! - † Included in `syntect`'s bundled defaults
110//!
111//! | | Syntax Definition |
112//! | :---: | :---: |
113//! | A | ActionScript†, Ada, Apache Conf, AppleScript†, AsciiDoc, ASP†, ARM Assembly\*, Assembly (x86\_64), AWK |
114//! | B | Bash†, Batch File†, BibTeX† |
115//! | C | C†, C#†, C++†, Cabal, CFML, Clojure†, CMake, CoffeeScript, Crontab, Crystal, CSS†, CSV† |
116//! | D | D†, Dart, debsources, Dockerfile, DotENV, Diff† |
117//! | E | Elixir, Elm, Email, Erlang† |
118//! | F | F#, Fish, Fortran |
119//! | G | GDScript (Godot Engine), Git (commit, config, ignore, etc.)†, GLSL, Go†, GraphQL, Graphviz (DOT)†, Groff/troff†, Groovy† |
120//! | H | Haskell†, HTML† |
121//! | I | Idris, INI |
122//! | J | Java†, Javadoc†, Java Server Page (JSP)†, JavaScript†, JavaScript (Babel)\*, Jinja2, JQ, JSON†, Julia |
123//! | K | Kotlin |
124//! | L | LaTeX†, LaTeX Log†, Lean, LESS, Lisp†, Literate Haskell†, LiveScript\*, LLVM, Lua† |
125//! | M | Makefile†, Manpage, Markdown†, MATLAB†, Mediawiki, MultiMarkdown† |
126//! | N | NAnt Build File†, Nginx, Nim, Ninja, Nix, NSIS |
127//! | O | Objective-C†, Objective-C++†, OCaml†, OCamllex†, OCamlyacc†, Odin, Org Mode |
128//! | P | Pascal†, Perl†, PHP†, PowerShell\*, Protobuf, Puppet, PureScript, Python† |
129//! | Q | QML |
130//! | R | R†, Racket, Rd†, Rego, Regular Expression†, Requirements.txt, reStructuredText†, Robot Framework, Ruby†, Ruby Haml†, Ruby on Rails†, Ruby Slim, Rust† |
131//! | S | Sass\*, Scala†, SCSS, Salt State SLS\*, SML, Solidity, SQL†, Strace, Stylus, Svelte, Swift, SystemVerilog |
132//! | T | Tcl†, Terraform, TeX†, Textile†, Todo.txt, TOML, TypeScript, TypescriptReact, Typst |
133//! | V | Varlink, Verilog, VHDL, VimL, Vue, Vyper |
134//! | W | WGSL |
135//! | X | XML† |
136//! | Y | YAML† |
137//! | Z | Zig |
138//!
139//! ## Themes
140//!
141//! _Note: For visual examples of all of the embedded themes look at the docs for
142//! [`theme::EmbeddedThemeName`]_
143//!
144//! The full listing of themes provided by [`theme`]. Many of these themes
145//! only make sense situationally, so you'll likely want to only expose a subset
146//!
147//! - † Included in `syntect`'s bundled defaults
148//!
149//! | | Theme |
150//! | :---: | :---: |
151//! | 1 | 1337 (aka leet) |
152//! | A | Ansi |
153//! | B | Base16, Base16-256, Base16-Eighties (dark)†, Base16-Mocha (dark)†, Base16-Ocean (light/dark)† |
154//! | C | Catppuccin (frappe, latte, macchiato, mocha), Coldark (cold/dark aka light/dark) |
155//! | D | DarkNeon, Dracula |
156//! | G | GitHub, gruvbox (light/dark) |
157//! | I | InspiredGitHub† |
158//! | M | Monokai Extended (plain, bright, light, and origin) |
159//! | N | Nord |
160//! | O | One Half (light/dark) |
161//! | S | Solarized (light/dark)†, Sublime Snazzy |
162//! | T | TwoDark |
163//! | Z | Zenburn |
164//!
165//! ## Legal
166//!
167//! The embedded syntax definitions and assets also have their own licenses which
168//! are compiled into
169//! [this markdown file](https://codeberg.org/CosmicHarper/two-face/src/branch/main/generated/acknowledgements_full.md)
170//! along with programmatic in the [`acknowledgement`] module
171
172#[cfg(doctest)]
173#[doc = include_str!("../README.md")]
174pub struct ReadmeDoctests;
175
176pub mod acknowledgement;
177pub mod syntax;
178pub mod theme;
179
180/// Dependency re-exports for user's convenience
181///
182/// # `syntect`
183///
184/// By default `two-face` uses the minimal feature set from `syntect` required for things to work,
185/// but the default features can be toggled on with the `syntect-default-onig` and
186/// `syntect-default-fancy` feature flags (depending on which syntect regex implementation you're
187/// using). If you need more granular features than the ones provided then you should probably
188/// depend directly on `syntect` instead
189pub mod re_exports {
190 pub use syntect;
191}
192
193// Compile error if we're using syntaxes without setting fancy vs onig
194#[cfg(not(any(feature = "syntect-onig", feature = "syntect-fancy")))]
195compile_error!(
196 r#"You must set either the `syntect-onig` or `syntect-fancy` feature matching the regex
197implementation that you're using for `syntect`. `syntect` and `two-face` both default to onig along
198with using it if both are present, so you have to use `default-features = false` if you want to use
199`fancy-regex`. E.g.
200
201# `onig` based
202[dependencies]
203syntect = ...
204two-face = ...
205
206or
207
208# `fancy-regex` based
209[dependencies]
210syntect = { version = ..., default-features = false, features = ["default-fancy"]
211two-face = { version = ..., default-features = false, features = ["syntect-fancy"] }"#
212);
213
214// TODO: add more extensive tests later
215#[cfg(test)]
216mod tests {
217 // The serialized data is in the right structure
218 #[test]
219 fn sanity() {
220 super::acknowledgement::listing();
221 super::syntax::extra_newlines();
222 super::syntax::extra_no_newlines();
223 super::theme::extra();
224 }
225}