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

> Create local themes with custom syntax highlighting in tuicr using .tmTheme files. Simply add your .tmTheme file and configure the syntax_theme setting for unique code styling.

- Repository: [Almog Gavra/tuicr](https://github.com/agavra/tuicr)
- Tags: how-to-guide
- Published: 2026-08-02

---

**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

```bash
mkdir -p ~/.config/tuicr/themes

```

### Step 2: Write the TOML Theme File

Create a file like [`my-theme.toml`](https://github.com/agavra/tuicr/blob/main/my-theme.toml) that defines UI colors and points to your `.tmTheme` file:

```toml

# ~/.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:

```json
{
  "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:

```toml

# ~/.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:

```rust
// 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:**

```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:**

```json
{
  "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:**

```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`](https://github.com/agavra/tuicr/blob/main/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`](https://github.com/agavra/tuicr/blob/main/config.toml) if you want tuicr to match your OS dark mode preference.