How to Create Local Themes with Custom Syntax Highlighting Using .tmTheme Files in tuicr

Add a custom .tmTheme file alongside your local TOML theme and set syntax_theme = "your-theme.tmTheme" to enable bespoke syntax highlighting in tuicr.

tuicr supports fully customizable local themes that combine UI colors with Bat-compatible syntax highlighting. According to the agavra/tuicr source code, the syntax_theme field in your TOML theme file can reference a .tmTheme file that syntect parses at runtime, giving you complete control over how code appears in diffs and source views.

Where Local Themes Are Stored

tuicr discovers local themes in your configuration directory. The path is platform-specific:

  • Linux/macOS: ~/.config/tuicr/themes/
  • Windows: %APPDATA%\tuicr\themes\

This location is returned by config::themes_dir() in src/config/mod.rs, lines 21–23. Place both your .toml theme file and your .tmTheme syntax file in this directory.

Creating a Local Theme with Custom Syntax Highlighting

Step 1: Create the Theme Directory

mkdir -p ~/.config/tuicr/themes

Step 2: Write the TOML Theme File

Create a file like my-theme.toml that defines UI colors and points to your .tmTheme file:


# ~/.config/tuicr/themes/my-theme.toml

# UI colors (optional – omit to use defaults)

panel_bg = "#202020"
bg_highlight = "#2a2a2a"
fg_primary = "#d0d0d0"
fg_secondary = "#a0a0a0"

# Required: reference to your .tmTheme file (relative to this TOML file)

syntax_theme = "my-theme.tmTheme"

The syntax_theme field is the critical configuration key. As documented in docs/CONFIG.md, line 120, this field tells tuicr which .tmTheme to load for syntax highlighting.

Step 3: Create the .tmTheme File

Create a Bat-compatible .tmTheme file in the same directory. The format is JSON-based with TextMate-style scope selectors. Here's a minimal working example:

{
  "name": "My Custom Theme",
  "author": "Your Name",
  "type": "dark",
  "settings": [
    { "scope": "comment", "settings": { "foreground": "#6a9955" } },
    { "scope": "keyword", "settings": { "foreground": "#c586c0" } },
    { "scope": "string",  "settings": { "foreground": "#ce9178" } }
  ]
}

For a complete reference, examine examples/tuicr-teal-syntax.tmTheme in the repository. This bundled example shows all standard scopes: comment, keyword, string, variable, function, type, and more.

Step 4: Activate the Theme in config.toml

Reference your theme (without the .toml extension) in your tuicr configuration:


# ~/.config/tuicr/config.toml

theme = "my-theme"

# Alternatives: theme_dark, theme_light for automatic switching

The theme loading flow works through App::new() → theme detection → UI render. When tuicr starts, it resolves the theme name to a file in your themes directory, then loads the associated .tmTheme using syntect.

How Syntax Theme Loading Works

The loading mechanism is straightforward but precise. In src/theme/mod.rs, lines 50–53, the Theme struct defines:

// From src/theme/mod.rs
pub struct Theme {
    // ... UI color fields ...
    pub syntax_theme: SyntaxTheme,  // Line 50-53 region
}

When processing a local theme, tuicr checks if syntax_theme specifies a custom file path. If so, it loads and parses that .tmTheme using syntect::highlighting::ThemeSet::load_from_reader. The helper function tokyo_night_day_syntax_theme() (lines 442–446) demonstrates this same pattern for bundled themes.

For local themes with custom .tmTheme files, the loader expects:

  • Valid JSON syntax (no trailing commas)
  • Bat-compatible Base16 placeholder support
  • Scope selectors that syntect recognizes

Complete Working Example

Here's a copy-paste ready setup for a custom dark theme:

~/.config/tuicr/themes/custom-dark.toml:

name = "Custom Dark"
author = "Your Name"

# UI Colors

panel_bg = "#1e1e1e"
bg_highlight = "#2d2d2d"
fg_primary = "#d4d4d4"
fg_secondary = "#808080"
accent = "#4ec9b0"
error = "#f44747"
success = "#4ec9b0"

# Syntax highlighting

syntax_theme = "custom-dark.tmTheme"

~/.config/tuicr/themes/custom-dark.tmTheme:

{
  "name": "Custom Dark Syntax",
  "type": "dark",
  "settings": [
    { "scope": "comment", "settings": { "foreground": "#6a9955", "fontStyle": "italic" } },
    { "scope": "keyword, storage.type", "settings": { "foreground": "#569cd6" } },
    { "scope": "string, string.quoted", "settings": { "foreground": "#ce9178" } },
    { "scope": "entity.name.function", "settings": { "foreground": "#dcdcaa" } },
    { "scope": "variable", "settings": { "foreground": "#9cdcfe" } },
    { "scope": "constant.numeric", "settings": { "foreground": "#b5cea8" } }
  ]
}

~/.config/tuicr/config.toml:

theme = "custom-dark"

Common Issues and Resolutions

Issue Cause Fix
Theme not appearing Wrong directory Verify config::themes_dir() path for your OS
Syntax highlighting missing syntax_theme field omitted or misnamed Add exactly syntax_theme = "filename.tmTheme"
Colors wrong or default Invalid .tmTheme JSON Validate JSON, check for trailing commas
tmTheme not found Path not relative to TOML file Keep both files in same directory, use filename only

The .tmTheme parser is strict: a single malformed JSON file will cause the theme to fall back to defaults or fail to load entirely. Test your theme by opening a file with known syntax (Rust, Python, JavaScript) and checking that comments, strings, and keywords display your custom colors.

Summary

  • Location: Place local themes in ~/.config/tuicr/themes/ (or platform equivalent)
  • TOML file: Define UI colors and set syntax_theme = "your-file.tmTheme"
  • .tmTheme file: Create Bat-compatible JSON with scope-based color rules
  • Activation: Reference theme name (without .toml) in config.toml
  • Loading: syntect parses your .tmTheme at startup via Theme struct in src/theme/mod.rs

Frequently Asked Questions

Can I use an existing TextMate or VS Code theme?

Yes, with conversion. VS Code themes use a different JSON structure. Extract the tokenColors array and reformat to the Bat .tmTheme structure—scope names are largely compatible. Test thoroughly as some VS Code-specific scopes may not map directly.

Why must the .tmTheme path be relative to the TOML file?

The loader in src/theme/mod.rs resolves syntax_theme relative to the theme file's directory (line 51 region). This ensures themes are self-contained and portable. Absolute paths are not supported to prevent configuration fragility across different systems.

How do I debug a theme that's not loading correctly?

Start tuicr from a terminal and watch for panic messages. The most common failures are: malformed JSON in the .tmTheme file, missing file extension in syntax_theme, or the .tmTheme file in a different directory than the .toml file. Verify with cat ~/.config/tuicr/themes/*.toml and ls ~/.config/tuicr/themes/.

What's the difference between theme, theme_dark, and theme_light?

theme applies universally. theme_dark and theme_light enable automatic switching based on system appearance detection. Set all three in config.toml if you want tuicr to match your OS dark mode preference.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →