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