lumis 0.1.2

Syntax highlighter powered by Tree-sitter and Neovim themes.
Documentation

Lumis

Features

  • 70+ languages with Tree-sitter parsing
  • 120+ Neovim themes
  • HTML output with inline styles or CSS classes
  • Multi-theme support for light/dark mode
  • Terminal output with ANSI colors
  • Language auto-detection via file extensions and shebangs
  • Line highlighting with custom styling
  • Custom HTML wrappers for code blocks
  • Streaming-friendly - handles incomplete code gracefully
  • Custom formatters via the Formatter trait

Installation

Add to your Cargo.toml:

[dependencies]
lumis = "0.1"

Or install the CLI:

cargo install lumis

Quick Start

use lumis::{highlight, HtmlInlineBuilder, languages::Language, themes};

let code = r#"fn main() { println!("Hello, world!"); }"#;
let theme = themes::get("dracula").unwrap();

let formatter = HtmlInlineBuilder::new()
    .lang(Language::Rust)
    .theme(Some(theme))
    .build()
    .unwrap();

let html = highlight(code, formatter);

For streaming to files or other writers, use write_highlight():

use lumis::{write_highlight, HtmlInlineBuilder, languages::Language};
use std::fs::File;

let code = "fn main() { }";
let formatter = HtmlInlineBuilder::new()
    .lang(Language::Rust)
    .build()
    .unwrap();

let mut file = File::create("output.html").unwrap();
write_highlight(&mut file, code, formatter).unwrap();

Formatters

Lumis provides four built-in formatters:

Formatter Output Use When
HtmlInlineBuilder HTML with inline styles Standalone HTML, emails, no external CSS
HtmlMultiThemesBuilder HTML with CSS variables Light/dark mode, theme switching
HtmlLinkedBuilder HTML with CSS classes Multiple code blocks, custom styling
TerminalBuilder ANSI escape codes CLI tools, terminal output

HTML Inline

Generates HTML with inline styles for each token:

use lumis::{highlight, HtmlInlineBuilder, languages::Language, themes};

let code = "puts 'Hello from Ruby!'";
let theme = themes::get("catppuccin_mocha").unwrap();

let formatter = HtmlInlineBuilder::new()
    .lang(Language::Ruby)
    .theme(Some(theme))
    .pre_class(Some("code-block".to_string()))  // Custom CSS class for <pre>
    .italic(true)                                // Enable italic styles
    .include_highlights(true)                    // Add data-highlight attributes
    .build()
    .unwrap();

let html = highlight(code, formatter);

HTML Linked

Generates HTML with CSS classes for styling (requires external CSS):

use lumis::{highlight, HtmlLinkedBuilder, languages::Language};

let code = "<div>Hello World</div>";

let formatter = HtmlLinkedBuilder::new()
    .lang(Language::HTML)
    .pre_class(Some("my-code".to_string()))
    .build()
    .unwrap();

let html = highlight(code, formatter);

CSS theme files are available in the css/ directory of the crate.

HTML Multi-Themes

Generates HTML with CSS custom properties for multiple themes, enabling light/dark mode support:

use lumis::{highlight, HtmlMultiThemesBuilder, languages::Language, themes};
use std::collections::HashMap;

let code = "const x = 42;";

let mut themes_map = HashMap::new();
themes_map.insert("light".to_string(), themes::get("github_light").unwrap());
themes_map.insert("dark".to_string(), themes::get("github_dark").unwrap());

let formatter = HtmlMultiThemesBuilder::new()
    .lang(Language::JavaScript)
    .themes(themes_map)
    .default_theme("light")  // or "light-dark()" for CSS function
    .build()
    .unwrap();

let html = highlight(code, formatter);

Use CSS media queries for automatic theme switching:

@media (prefers-color-scheme: dark) {
  .lumis,
  .lumis span {
    color: var(--lumis-dark) !important;
    background-color: var(--lumis-dark-bg) !important;
  }
}

Terminal

Generates ANSI escape codes for terminal output:

use lumis::{highlight, TerminalBuilder, languages::Language, themes};

let code = "puts 'Hello from Ruby!'";
let theme = themes::get("dracula").unwrap();

let formatter = TerminalBuilder::new()
    .lang(Language::Ruby)
    .theme(Some(theme))
    .build()
    .unwrap();

let ansi = highlight(code, formatter);
println!("{}", ansi);

Line Highlighting

Highlight specific lines with custom styling:

use lumis::{highlight, HtmlInlineBuilder, languages::Language, themes};
use lumis::formatter::html_inline::{HighlightLines, HighlightLinesStyle};

let code = "line 1\nline 2\nline 3\nline 4";
let theme = themes::get("catppuccin_mocha").unwrap();

let highlight_lines = HighlightLines {
    lines: vec![1..=1, 3..=4],  // Highlight lines 1, 3, and 4
    style: Some(HighlightLinesStyle::Theme),
    class: None,
};

let formatter = HtmlInlineBuilder::new()
    .lang(Language::PlainText)
    .theme(Some(theme))
    .highlight_lines(Some(highlight_lines))
    .build()
    .unwrap();

let html = highlight(code, formatter);

Custom HTML Wrappers

Wrap the formatted output with custom HTML elements:

use lumis::{highlight, HtmlInlineBuilder, languages::Language, formatter::HtmlElement};

let code = "fn main() { }";

let formatter = HtmlInlineBuilder::new()
    .lang(Language::Rust)
    .header(Some(HtmlElement {
        open_tag: "<div class=\"code-wrapper\">".to_string(),
        close_tag: "</div>".to_string(),
    }))
    .build()
    .unwrap();

let html = highlight(code, formatter);
// Output: <div class="code-wrapper"><pre class="lumis">...</pre></div>

Themes

120+ themes from popular Neovim colorschemes:

use lumis::themes;

// Get a theme by name
let theme = themes::get("dracula").unwrap();

// Parse from string
let theme: themes::Theme = "catppuccin_mocha".parse().unwrap();

// List all available themes
for theme in themes::available_themes() {
    println!("{} ({})", theme.name, theme.appearance);
}

// Filter by appearance
use lumis::themes::Appearance;

let dark_themes: Vec<_> = themes::available_themes()
    .filter(|t| t.appearance == Appearance::Dark)
    .collect();

Custom Themes

Load themes from JSON files or strings:

use lumis::themes;

// From file
let theme = themes::from_file("my_theme.json").unwrap();

// From JSON string
let json = r#"{
    "name": "my_theme",
    "appearance": "dark",
    "revision": "v1.0.0",
    "highlights": {
        "keyword": { "fg": "#ff79c6", "bold": true },
        "string": { "fg": "#f1fa8c" },
        "comment": { "fg": "#6272a4", "italic": true }
    }
}"#;
let theme = themes::from_json(json).unwrap();

Custom Formatters

Implement the Formatter trait to create custom output formats:

use lumis::{
    formatter::Formatter,
    highlight::highlight_iter,
    languages::Language,
    themes,
};
use std::io::{self, Write};

struct CsvFormatter {
    language: Language,
    theme: Option<themes::Theme>,
}

impl Formatter for CsvFormatter {
    fn format(&self, source: &str, output: &mut dyn Write) -> io::Result<()> {
        writeln!(output, "text,start,end,scope,fg")?;

        highlight_iter(source, self.language, self.theme.clone(), |text, range, scope, style| {
            let fg = style.fg.as_deref().unwrap_or("none");
            let escaped = text.replace('"', "\"\"");
            writeln!(output, "\"{}\",{},{},{},{}", escaped, range.start, range.end, scope, fg)
        })
        .map_err(io::Error::other)
    }
}

CLI Usage

# Highlight a file
lumis highlight src/main.rs --theme dracula

# Highlight with a specific language
lumis highlight code.txt --language rust --theme github_dark

# Output to terminal (default)
lumis highlight src/main.rs --theme catppuccin_mocha

# List available themes
lumis themes

# List available languages
lumis languages

Language Feature Flags

By default, Lumis includes all languages. To reduce compile time and binary size, enable only the languages you need:

[dependencies]
lumis = { version = "0.1", default-features = false, features = ["lang-rust", "lang-javascript"] }

Available features:

  • all-languages - Enable all languages (default)
  • lang-rust, lang-javascript, lang-typescript, lang-python, etc.

See the full list of language features in Cargo.toml.

Supported Languages

Language File Extensions
Angular *.angular, component.html
Assembly *.s, *.asm
Astro *.astro
Bash *.bash, *.sh, *.zsh, and more
C *.c
C++ *.cpp, *.cc, *.h, *.hpp
C# *.cs
CSS *.css
Clojure *.clj, *.cljs, *.cljc
Dart *.dart
Dockerfile Dockerfile, *.dockerfile
Elixir *.ex, *.exs
Erlang *.erl, *.hrl
F# *.fs, *.fsx
Gleam *.gleam
Go *.go
GraphQL *.graphql
HTML *.html, *.htm
Haskell *.hs
HCL *.hcl, *.tf
Java *.java
JavaScript *.js, *.mjs, *.cjs
JSON *.json
Kotlin *.kt
LaTeX *.tex
Lua *.lua
Markdown *.md
Nix *.nix
OCaml *.ml, *.mli
PHP *.php
Python *.py
Ruby *.rb
Rust *.rs
SQL *.sql
Scala *.scala
Swift *.swift
TOML *.toml
TypeScript *.ts
TSX *.tsx
Vue *.vue
YAML *.yaml, *.yml
Zig *.zig
...and more See docs for full list

Available Themes

Themes are sourced from popular Neovim colorschemes:

  • Catppuccin: catppuccin_frappe, catppuccin_latte, catppuccin_macchiato, catppuccin_mocha
  • Dracula: dracula, dracula_soft
  • GitHub: github_dark, github_light, github_dark_dimmed, and more
  • Gruvbox: gruvbox_dark, gruvbox_light, and variants
  • Tokyo Night: tokyonight_day, tokyonight_moon, tokyonight_night, tokyonight_storm
  • One Dark: onedark, onedark_cool, onedark_darker, onelight
  • Rose Pine: rosepine_dark, rosepine_dawn, rosepine_moon
  • Nord: nord, nordic, nordfox
  • Material: material_darker, material_oceanic, material_palenight
  • Kanagawa: kanagawa_wave, kanagawa_dragon, kanagawa_lotus
  • ...and 100+ more

Use themes::available_themes() or the CLI lumis themes for the complete list.

Acknowledgements

  • Inkjet for the Rust implementation in early versions
  • The Neovim community for the beautiful colorschemes

License

MIT