syntect-py
High-quality syntax highlighting for Python using Sublime Text grammars, powered by the syntect Rust crate. syntect-py 5.3.1 · PyO3 0.29 · Python ≥ 3.9 · Pure Rust regex (no C dependencies)
Features
- 190+ built-in syntaxes — Rust, Python, JavaScript, TypeScript, Go, C, C++, Java, HTML, CSS, YAML, TOML, Markdown, and more
- 55 bundled themes — Dracula, Nord, Monokai Extended, OneDark, Solarized, and more, loaded automatically
- Syntax lookup primitives — token/alias lookup and first-line detection for shebangs, modelines, and XML
- Theme authoring — construct themes with
ThemeSettings,ThemeItem,ScopeSelectors, andStyleModifier - VS Code theme support — parse JSON/JSONC themes and register custom plist/VS Code themes
- Assets compatibility API —
Assets/HighlightingAssetsfallback API for future expanded grammar data - Multiple output formats — inline HTML, class-based HTML, ANSI terminal escapes (24-bit color), LaTeX
- Stateful highlighting — incremental re-highlighting with save/restore for editor integration
- Real parse state — context-sensitive parsing across lines with scope stack introspection
- Metadata access —
.tmPreferencesmetadata (indent rules, comment patterns, shell variables) - Serialization — dump/load syntax sets and themes as binary
.packdump/.themedumpfiles - Zero C dependencies — uses
regex-fancy(pure Rust), no Oniguruma - Full type stubs — comprehensive
.pyistubs for IDE autocomplete and type checking - 360 tests — covering syntax/theme parity, JSONC themes, CSS selectors, bundled themes, assets fallback, stub conformance, and golden outputs
Installation
pip install syntect-py
From source
# From the repository root
python -m pip install maturin
maturin build --release --out pyext/dist -m pyext/Cargo.toml
python -m pip install --force-reinstall pyext/dist/*.whl
Prebuilt wheels are published for Linux x86_64/ARM64, macOS ARM64,
and Windows x86_64. Source distributions are also published to PyPI from
v* Git tags.
Quick Start
import syntect
# Load syntax definitions and themes (once at startup)
ss = syntect.SyntaxSet.load_defaults(True)
ts = syntect.ThemeSet.load_defaults()
# Get a syntax and theme
rust = ss.find_syntax_by_name("Rust")
theme = ts.get_theme("base16-ocean.dark")
# Create a highlighter
hl = syntect.Highlighter(rust, theme)
# Highlight a single line
tokens = hl.highlight_line("fn main() {}", ss, ts)
for style, text in tokens:
print(f"{style.foreground.to_hex()} {text}")
# Or use the high-level convenience function
result = syntect.highlight_string(
code='fn main() { println!("Hello"); }',
syntax="Rust",
theme="base16-ocean.dark",
syntax_set=ss,
theme_set=ts
)
print(result.html) # HTML output
print(result.as_terminal_escaped(True)) # ANSI terminal output
print(result.as_latex_escaped()) # LaTeX output
Incremental Highlighting
For editors that need to re-highlight after changes:
hl = syntect.Highlighter(rust, theme)
state = hl.save_state(ss, ts) # Save highlighting state
# ... some time later ...
hl2 = syntect.Highlighter.from_state(state, theme) # Resume from state
# Or use the stateful HighlightLines API (upstream behavior)
hl_lines = syntect.HighlightLines(rust, ss, ts, "base16-ocean.dark")
for line in code.split("\n"):
tokens = hl_lines.highlight_line(line, ss) # 2 args: (line, ss)
# Or construct directly from a Theme object:
hl_direct = syntect.HighlightLines.with_theme(rust, ss, theme)
HTML Output
Inline HTML (single tokens)
tokens = hl.highlight_line("fn main() {}", ss, ts)
html = syntect.as_html(tokens, "if_different", None)
# <span style="color:#B48EAD;">fn</span><span style="color:#C0C5CE;"> </span>...
Class-based HTML (compact, CSS-externally styled)
class_style = syntect.ClassStyle.spaced_prefixed("syn-")
html = syntect.tokens_to_classed_spans(tokens, class_style)
# <span class="syn-keyword">fn</span><span class="syn-punctuation"> </span>...
Streaming HTML generator
gen = syntect.ClassedHTMLGenerator(rust, ss, class_style)
for line in code.split("\n"):
gen.parse_html_for_line_which_includes_newline(line)
html = gen.finalize() # Closes any open spans
Full HTML with line numbers
html = syntect.highlighted_html_at_line_and_column_number(
code, rust, theme, ss, ts, start_line=1
)
# <pre><span data-line="1">...</span>\n<span data-line="2">...</span></pre>
CSS generation
css = syntect.css_for_theme(theme, "spaced")
# .keyword { color: #B48EAD; }
# .function { color: #8FA1B3; }
cs = syntect.ClassStyle.spaced_prefixed("syn-")
css = syntect.css_for_theme_class(theme, cs)
CSS generation preserves comma-separated selectors and emits combined font styles such as bold + italic + underline.
Theme Authoring and VS Code Themes
settings = syntect.ThemeSettings()
settings.background = syntect.Color.from_hex("#1E1E1E")
item = syntect.ThemeItem(
syntect.ScopeSelectors.from_string("variable, constant"),
syntect.StyleModifier(
foreground=syntect.Color.from_hex("#FFD700"),
font_style=syntect.FontStyle.from_string("bold italic underline"),
),
)
theme = syntect.Theme(
name="Custom Theme", author="me", settings=settings, scopes=[item]
)
ts = syntect.ThemeSet()
ts.add_theme("custom", theme)
# VS Code JSON/JSONC or plist XML
content = open("theme.json", encoding="utf-8").read()
syntect.add_custom_theme("vscode-theme", content)
print(syntect.list_themes())
The process-wide add_custom_theme() registry is separate from caller-owned
ThemeSet instances. Use ThemeSet.add_theme() for an isolated set.
Assets Compatibility API
assets = syntect.Assets.from_binary()
assets.set_fallback_theme("Monokai Extended")
asset_syntaxes = assets.get_syntax_set()
asset_themes = assets.get_theme_set()
theme = assets.get_theme("unknown-theme") # configured fallback
The API is ready for expanded bat grammar data. The current implementation
uses fork-compatible default syntax/theme data because the published
syntect-assets binary dump is not compatible with this fork's serialization.
Terminal Output (24-bit color)
tokens = hl.highlight_line("fn main() {}", ss, ts)
escaped = syntect.as_terminal_escaped(tokens, include_bg=True)
print(escaped, end="") # \x1b[38;2;180;142;173mfn\x1b[38;2;192;197;206m ...
Alpha transparency is handled automatically — foreground colors are blended with the background.
LaTeX Output
tokens = hl.highlight_line("fn main() {}", ss, ts)
latex = syntect.as_latex_escaped(tokens)
# \textcolor[RGB]{180,142,173}{fn}\textcolor[RGB]{192;197;206}{ }...
Spaces and newlines are elided when the style doesn't change.
Metadata Access (.tmPreferences)
ss = syntect.SyntaxSet.load_defaults(True)
meta = ss.metadata
if meta:
for mset in meta.sets:
print(mset.selector_string) # "source.python"
item = mset.items
print(item.line_comment) # "//"
print(item.indent_parens) # True/False
print(item.shell_variables) # List[Tuple[str, str]]
print(item.increase_indent_pattern)
Parsing Introspection
ps = syntect.ParseState("Rust", ss)
output = ps.parse_line("fn main() {", ss)
for pos, op in output.ops:
print(f" {pos}: {op}")
# 0: Push(source.rust)
# 1: Push(keyword.declaration)
is_speculative = ps.is_speculative() # True during backtracking
print(ps.syntax_name) # "Rust"
Dump / Serialization
# Save to binary dump (fast loading)
syntect.dump_syntax_set(ss, "syntaxes.packdump")
syntect.dump_theme_set(ts, "themes.themedump")
# Load from dump
ss = syntect.load_syntax_set("syntaxes.packdump")
ts = syntect.load_theme_set("themes.themedump")
Utility Functions
# Split tokens at a character position
left, right = syntect.split_at(tokens, 5)
# Modify style in a character range
modified = syntect.modify_range(tokens, 0, 5, new_style)
# Iterate lines with their endings
for line, ending in syntect.lines_with_endings("hello\nworld\r\n"):
print(repr(line), repr(ending))
# 'hello' '\n' 'world' '\r\n'
Error Handling
import syntect
try:
ss = syntect.SyntaxSet.load_from_folder("/missing", True)
except (syntect.LoadingError, OSError) as e:
print(f"Load error: {e}")
theme = ts.get_theme("nonexistent")
if theme is None: # Returns None when no fallback is supplied
print("Theme not found")
fallback = ts.get_theme("nonexistent", "base16-ocean.dark")
Exception types: LoadingError, ParsingError, DumpError, ParseSyntaxError, ValueError, OSError, RuntimeError, IndexError
API Gotchas
| Issue | Solution |
|---|---|
Highlighter.highlight_line() takes 3 args (line, ss, ts) |
HighlightLines.highlight_line() takes 2 args (line, ss) |
as_html() requires default_bg parameter |
Pass None for no default |
rust.variables is List[Tuple[str, str]] |
Not a Dict[str, str] |
MatchPower.value is a property |
Not a method: use mp.value, not mp.value() |
save_state() requires ss, ts arguments |
Not no-arg: hl.save_state(ss, ts) |
get_theme() returns None for missing |
Pass fallback="theme-name" for fallback lookup |
HighlightLines unknown theme |
Falls back to InspiredGitHub when available |
add_custom_theme() registry |
Process-wide; use ThemeSet.add_theme() for an isolated set |
Color.to_hex() returns uppercase |
#FF0000, not #ff0000 |
is_prefix_of() semantics |
parent.is_prefix_of(child) — parent checks if child starts with it |
Project Structure
syntect-py/
├── ARCHITECTURE.md # Architecture documentation
├── QUICKREF.md # Quick reference guide
├── CHANGELOG.md # Version history
├── DESIGN.md # Design decisions
├── Readme.md # This file
├── .github/workflows/CI.yml # Multiplatform CI
├── .github/workflows/Release.yml # Wheel/sdist build and PyPI publish
├── pyext/
│ ├── Cargo.toml # PyO3 + syntect dependencies
│ ├── pyproject.toml # maturin build configuration and theme inclusion
│ ├── README.md # Python package metadata readme
│ ├── syntect.pyi # Type stubs (complete)
│ ├── syntect/
│ │ ├── __init__.py # Mixed-package wrapper
│ │ ├── __init__.pyi
│ │ └── themes/ # 55 bundled mordant themes
│ ├── src/
│ │ ├── lib.rs # Module entry point
│ │ ├── style.rs # Color, FontStyle, Style, StyleModifier
│ │ ├── syntax_set.rs # SyntaxSet, SyntaxReference, SyntaxSetBuilder
│ │ ├── theme_set.rs # ThemeSet, Theme, ThemeSettings, ThemeItem, ScopeSelectors
│ │ ├── vscode_theme.rs# VS Code JSON/JSONC conversion and registry
│ │ ├── assets.rs # Assets/HighlightingAssets compatibility API
│ │ ├── metadata.rs # Metadata, MetadataSet, MetadataItem
│ │ ├── highlighter.rs# Highlighter, HighlightState, HighlightLines
│ │ ├── highlighting.rs# ScoredStyle, ScopeRangeIterator
│ │ ├── parse_state.rs# ParseState, Scope, ScopeStack, etc.
│ │ ├── html.rs # ClassedHTMLGenerator, CSS/HTML functions
│ │ ├── util.rs # LinesWithEndings, split_at, modify_range
│ │ ├── convenience.rs# HighlightResult
│ │ ├── dumps.rs # dump/load syntax/theme sets
│ │ ├── converters.rs # Py↔Rust conversion helpers
│ │ └── errors.rs # Exception types
│ ├── examples/ # 9 example scripts
│ ├── benches/ # Benchmark scripts (highlighting, loading, parsing)
│ └── tests/ # Python, parity, stub, and golden-output tests
Examples
| Example | Description |
|---|---|
basic_highlight.py |
Single-line highlighting with all output formats |
incremental.py |
Stateful highlighting with save/restore |
highlight_file.py |
Multi-line file highlighting with CRLF support |
advanced_highlight.py |
Classed HTML, scope stack, split/modify |
highlight_html.py |
Full HTML file generation with CSS |
css_generator.py |
CSS generation for themes |
benchmark.py |
Performance benchmarking |
metadata_example.py |
Metadata access from .tmPreferences |
error_handling.py |
Error handling patterns |
Run any example from the repository root after installing the wheel:
python pyext/examples/basic_highlight.py
Documentation
| Document | Contents |
|---|---|
ARCHITECTURE.md |
Architecture, module map, type mapping, design decisions |
QUICKREF.md |
Complete API reference with examples and gotchas |
syntect.pyi |
Type stubs for IDE autocomplete |
docs/IMPROVEMENT_PLAN.md |
Remediation & improvement plan with phased execution |
Tests
python -m pytest pyext/tests/ -v
346 tests passing. The suite includes stub conformance, JSONC theme conversion, CSS selector preservation, bundled-theme loading, assets fallback, LaTeX escaping, HTML/terminal output, and golden outputs.
Built On
syntect-py is a Python binding layer over the syntect Rust crate, which provides:
- 190+ built-in syntax definitions from Sublime Text Packages
- 55 bundled mordant themes plus syntect's built-in themes
- JSON/JSONC VS Code theme conversion and custom theme registration
- Pure Rust
fancy-regexengine (no C dependencies) - 24-bit color ANSI terminal output, HTML, and LaTeX support
346 tests passing · syntect-py 5.3.1 · PyO3 0.29 · Python ≥ 3.9 · P1–P4.5 parity implemented · PyPI CI/release configured · expanded bat grammar data remains outstanding
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file syntect_py-5.3.1.tar.gz.
File metadata
- Download URL: syntect_py-5.3.1.tar.gz
- Upload date:
- Size: 4.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d637f76d824ccf335eb23fda36a127218a4f4fe6fd329803b63377db8c4b51b7
|
|
| MD5 |
744644d4f55514be62c453311537f65c
|
|
| BLAKE2b-256 |
f94084e55e4a61ecd2b4e758c4592819ee130d1d1da54231b74c8151340aa07c
|
Provenance
The following attestation bundles were made for syntect_py-5.3.1.tar.gz:
Publisher:
Release.yml on opticsWolf/syntect-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
syntect_py-5.3.1.tar.gz -
Subject digest:
d637f76d824ccf335eb23fda36a127218a4f4fe6fd329803b63377db8c4b51b7 - Sigstore transparency entry: 2392124889
- Sigstore integration time:
-
Permalink:
opticsWolf/syntect-py@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Branch / Tag:
refs/tags/v5.3.1 - Owner: https://github.com/opticsWolf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
Release.yml@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file syntect_py-5.3.1-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: syntect_py-5.3.1-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 5.6 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8177891a8258467d51844078b681af16274c936844b2ba3df8ee82c74067edfa
|
|
| MD5 |
ac9666cacbe5d8d362de4b2584f0abb0
|
|
| BLAKE2b-256 |
bd2813edeffd4c4e1fc064aa23f5d2115ba49fb3f57a7b1470eca57960ac6518
|
Provenance
The following attestation bundles were made for syntect_py-5.3.1-cp39-abi3-win_amd64.whl:
Publisher:
Release.yml on opticsWolf/syntect-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
syntect_py-5.3.1-cp39-abi3-win_amd64.whl -
Subject digest:
8177891a8258467d51844078b681af16274c936844b2ba3df8ee82c74067edfa - Sigstore transparency entry: 2392125609
- Sigstore integration time:
-
Permalink:
opticsWolf/syntect-py@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Branch / Tag:
refs/tags/v5.3.1 - Owner: https://github.com/opticsWolf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
Release.yml@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file syntect_py-5.3.1-cp39-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: syntect_py-5.3.1-cp39-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 6.0 MB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4cb7e69629091a204ede5595494651b8892238c145b01f9a95c0450758869c6b
|
|
| MD5 |
7fe477d95256efec442c121318408af0
|
|
| BLAKE2b-256 |
c90ebe7bdbc6b94149d5a9b21a79dc02773aee5ced86f57ac4990f24fb42b720
|
Provenance
The following attestation bundles were made for syntect_py-5.3.1-cp39-abi3-manylinux_2_28_x86_64.whl:
Publisher:
Release.yml on opticsWolf/syntect-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
syntect_py-5.3.1-cp39-abi3-manylinux_2_28_x86_64.whl -
Subject digest:
4cb7e69629091a204ede5595494651b8892238c145b01f9a95c0450758869c6b - Sigstore transparency entry: 2392127171
- Sigstore integration time:
-
Permalink:
opticsWolf/syntect-py@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Branch / Tag:
refs/tags/v5.3.1 - Owner: https://github.com/opticsWolf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
Release.yml@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file syntect_py-5.3.1-cp39-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: syntect_py-5.3.1-cp39-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 6.0 MB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
505785b8941c46d7cb777c12c782e0936861b09beb39e40f315210f88af6faed
|
|
| MD5 |
372fc1ad2906672bb9333af5330d04e6
|
|
| BLAKE2b-256 |
02ebaface7083ab31a93da6cf8845e33d2f53c23675254ff7cf58ff3386d9a36
|
Provenance
The following attestation bundles were made for syntect_py-5.3.1-cp39-abi3-manylinux_2_28_aarch64.whl:
Publisher:
Release.yml on opticsWolf/syntect-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
syntect_py-5.3.1-cp39-abi3-manylinux_2_28_aarch64.whl -
Subject digest:
505785b8941c46d7cb777c12c782e0936861b09beb39e40f315210f88af6faed - Sigstore transparency entry: 2392127923
- Sigstore integration time:
-
Permalink:
opticsWolf/syntect-py@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Branch / Tag:
refs/tags/v5.3.1 - Owner: https://github.com/opticsWolf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
Release.yml@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file syntect_py-5.3.1-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: syntect_py-5.3.1-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 5.8 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
589615468cfc7a52e41b45a4b64234b42d6e7d2882941479a8a7db31321d8a01
|
|
| MD5 |
ac1e4d66bb26c70e8a89b12be02a545f
|
|
| BLAKE2b-256 |
1039b07358ca444526840a744436c8da5149d876e593f5852d87ff53f02a9059
|
Provenance
The following attestation bundles were made for syntect_py-5.3.1-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
Release.yml on opticsWolf/syntect-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
syntect_py-5.3.1-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
589615468cfc7a52e41b45a4b64234b42d6e7d2882941479a8a7db31321d8a01 - Sigstore transparency entry: 2392126328
- Sigstore integration time:
-
Permalink:
opticsWolf/syntect-py@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Branch / Tag:
refs/tags/v5.3.1 - Owner: https://github.com/opticsWolf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
Release.yml@351da6d1ef3d9e4ce11c96400232e987db9fbdd0 -
Trigger Event:
push
-
Statement type: