Native TextMate syntax highlighting with Shiki-compatible language and theme bundles.
Grammars are compiled into numeric runtime structures and matched with Oniguruma.
Bundled definitions live in the companion shiki-langs and shiki-themes crates;
runtime TextMate JSON is supported through [HighlighterBuilder::json_language] and
[HighlighterBuilder::json_theme]. Reuse a [Highlighter] or [HighlighterEngine]
because compiled scanners and scope/style transitions are cached on demand.
Basic highlighting
use shiki::{Highlighter, LanguageBundle};
static LANGUAGES: LanguageBundle = shiki_langs::languages![rust];
let mut highlighter = Highlighter::builder()
.bundle(&LANGUAGES)
.languages(["rust"])
.theme(&shiki_themes::CATPPUCCIN_MOCHA)
.build()?;
let html = highlighter.code_to_html("fn main() {}", "rust")?;
assert!(html.contains("fn"));
# Ok::<(), shiki::Error>(())
Enabling every bundled language
shiki_langs::all() provides the convenient all-language bundle. Building it is
intentionally more expensive, so applications should normally create one shared engine.
use shiki::Highlighter;
let languages = shiki_langs::all();
let engine = Highlighter::builder()
.bundle(&languages)
.theme(&shiki_themes::CATPPUCCIN_MOCHA)
.build_engine()?;
let mut highlighter = engine.highlighter();
let html = highlighter.code_to_html("const value = 1", "javascript")?;
# Ok::<(), shiki::Error>(())
Incremental documents and parallel sessions
An engine shares immutable grammar IR and themes. Each session owns its dynamic scanner, scope and style caches, so documents can advance independently.
use shiki::{Highlighter, LanguageBundle};
static LANGUAGES: LanguageBundle = shiki_langs::languages![rust];
let engine = Highlighter::builder()
.bundle(&LANGUAGES)
.languages(["rust"])
.theme(&shiki_themes::GITHUB_DARK)
.build_engine()?;
let mut session = engine.session("rust")?;
let mut state = session.initial_state();
let tokens = session.tokenize_line("/* open", &mut state, true)?;
assert!(!tokens.is_empty());
# Ok::<(), shiki::Error>(())