diff --git a/.gitignore b/.gitignore
index 82c80cc9..59b44428 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@ node_modules
*.vsix
*.zip
.env
-dist/vscode
+dist
+.claude/
diff --git a/AGENTS.md b/AGENTS.md
index 7a1dad04..a52aea30 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -4,7 +4,7 @@ This document provides guidelines and best practices for AI agents working on th
## Project Overview
-Bearded Theme is a color theme extension for **VS Code** and **Zed** editors. It features 60+ theme variants including dark, light, high-contrast, and accessibility-focused options.
+Bearded Theme is a color theme extension for **VS Code**, **Zed**, and **JetBrains IDEs** (WebStorm, IntelliJ IDEA, PyCharm, PhpStorm, GoLand, Rider, etc.). It features 60+ theme variants including dark, light, high-contrast, and accessibility-focused options.
### Key Technologies
@@ -33,13 +33,33 @@ bearded-theme/
│ │ │ ├── prog.ts
│ │ │ ├── markup.ts
│ │ │ └── styling.ts
-│ │ └── zed/ # Zed theme generator
+│ │ ├── zed/ # Zed theme generator
+│ │ │ ├── index.ts # Zed build script
+│ │ │ ├── types.ts # Zed specific type definitions
+│ │ │ ├── ui.ts # Zed UI color mappings
+│ │ │ └── syntax.ts # Zed syntax highlighting
+│ │ └── jetbrains/ # JetBrains theme generator
+│ │ ├── index.ts # JetBrains build script (generates full plugin)
+│ │ ├── ui.ts # JetBrains UI color mappings
+│ │ ├── types.ts # JetBrains specific type definitions
+│ │ ├── theme.ts # Theme JSON builder
+│ │ ├── editor-scheme.ts # Editor color scheme XML generator
+│ │ ├── plugin.ts # Plugin manifest (plugin.xml) generator
+│ │ ├── utils.ts # Color utility functions
+│ │ └── README.md # Installation instructions
│ ├── variations/ # Theme color definitions (shared)
│ ├── helper.ts # Color utility functions
│ └── build.ts # Build orchestrator
├── dist/ # Generated output (DO NOT edit manually)
│ ├── vscode/themes/
-│ └── zed/themes/
+│ ├── zed/themes/
+│ └── jetbrains/ # Complete JetBrains plugin structure
+│ ├── resources/META-INF/plugin.xml # Plugin manifest
+│ ├── themes/*.theme.json # UI theme files
+│ ├── themes/*.xml # Editor color schemes
+│ ├── build.gradle.kts # Gradle build file
+│ ├── settings.gradle.kts # Gradle settings
+│ └── gradle.properties # Gradle properties
├── releases/ # VSIX packages and release notes
└── assets/ # Icons and images
```
@@ -51,10 +71,12 @@ bearded-theme/
| `src/shared/theme-registry.ts` | **Single source of truth** for all theme variants |
| `src/shared/types.ts` | Shared TypeScript interfaces (Theme, ThemeColors, ThemeUi, etc.) |
| `src/generators/vscode/types.ts` | VS Code specific type definitions (ActivityBarColors, EditorColors, etc.) |
+| `src/generators/jetbrains/types.ts` | JetBrains specific type definitions (JetBrainsTheme, JetBrainsUiColors) |
| `src/helper.ts` | Color manipulation utilities (`makeMainColorsDark`, `makeMainColorsLight`) |
| `src/variations/*.ts` | Individual theme color palettes |
| `src/generators/vscode/ui.ts` | VS Code UI color mappings |
| `src/generators/vscode/scopes/*.ts` | VS Code syntax highlighting scopes |
+| `src/generators/jetbrains/ui.ts` | JetBrains UI color mappings |
| `package.json` | Extension manifest with theme contributions |
## Coding Standards
@@ -246,32 +268,128 @@ interface ThemeOptions {
- `styling.ts` - CSS/SCSS tokens
- `semanticTokens.ts` - Semantic token colors
-- **Zed**: Edit `buildSyntax()` function in `src/generators/zed/index.ts`
+- **Zed**: Edit `buildSyntax()` function in `src/generators/zed/syntax.ts`
+
+- **JetBrains**: Edit `buildAttributeOptions()` in `src/generators/jetbrains/editor-scheme.ts`
### Modifying UI Colors
- **VS Code**: Edit `src/generators/vscode/ui.ts`
-- **Zed**: Edit `buildZedThemeStyle()` in `src/generators/zed/index.ts`
+- **Zed**: Edit `buildZedThemeStyle()` in `src/generators/zed/ui.ts`
+- **JetBrains**: Edit `src/generators/jetbrains/ui.ts`
## Build Commands
-| Command | Description |
-| ---------------------- | ------------------------------------ |
-| `npm run build` | Build all themes (VS Code + Zed) |
-| `npm run build:vscode` | Build VS Code themes only |
-| `npm run build:zed` | Build Zed themes only |
-| `npm run dev:vscode` | Watch mode for VS Code |
-| `npm run dev:zed` | Watch mode for Zed |
-| `npm run lint` | Check code with ESLint (no auto-fix) |
-| `npm run fix` | Format and fix code with ESLint |
+| Command | Description |
+| --------------------------------- | ------------------------------------------------------- |
+| `npm run clean` | Clean all dist folders |
+| `npm run clean:vscode` | Clean dist/vscode folder only |
+| `npm run clean:zed` | Clean dist/zed folder only |
+| `npm run clean:jetbrains` | Clean dist/jetbrains folder only |
+| `npm run build` | Build all themes + JetBrains plugin (requires Java 11+) |
+| `npm run build:vscode` | Build VS Code themes only (auto-cleans first) |
+| `npm run build:zed` | Build Zed themes only (auto-cleans first) |
+| `npm run build:jetbrains` | Build JetBrains themes only (auto-cleans first) |
+| `npm run build:ext:jetbrains` | Build JetBrains plugin package (requires Java 11+) |
+| `npm run install:jetbrains:local` | Install JetBrains themes to local IDE (for testing) |
+| `npm run dev:jetbrains:install` | Build + install JetBrains themes in one command |
+| `npm run dev:vscode` | Watch mode for VS Code |
+| `npm run dev:zed` | Watch mode for Zed |
+| `npm run dev:jetbrains` | Watch mode for JetBrains |
+| `npm run lint` | Check code with ESLint (no auto-fix) |
+| `npm run fix` | Format and fix code with ESLint |
+
+### JetBrains Plugin Build
+
+The main `npm run build` command will:
+
+1. Build all VS Code, Zed, and JetBrains themes
+2. Download the Gradle wrapper automatically
+3. Attempt to build the JetBrains plugin package (`.zip` file)
+
+**Requirements for plugin build:**
+
+- Java 11 or higher (download from [adoptium.net](https://adoptium.net/))
+- If Java is not installed, the build will skip the plugin packaging step but still succeed
+- Theme files will still be generated and can be installed manually
+
+**To build the plugin manually:**
+
+```bash
+npm run build:ext:jetbrains
+```
+
+### JetBrains Editor Color Schemes - IMPORTANT
+
+**Critical: Always use the official JetBrains method for editor schemes to avoid IDE crashes.**
+
+Per [official JetBrains documentation](https://plugins.jetbrains.com/docs/intellij/themes-extras.html#adding-a-custom-editor-scheme):
+
+#### ✅ Correct Method (Currently Used)
+
+1. **File Extension**: Generate editor schemes as `.xml` files (not `.icls`)
+ - While IDEs export schemes as `.icls`, they must be renamed to `.xml` for bundling
+2. **Reference Location**: Reference schemes **ONLY** in `.theme.json` files:
+
+ ```json
+ {
+ "name": "My Theme",
+ "editorScheme": "/my-theme.xml",
+ "ui": { ... }
+ }
+ ```
+
+3. **NO plugin.xml Declaration**: Do NOT use `` in `plugin.xml`
+ - This causes `NullPointerException` crashes in WebStorm and other IDEs
+
+4. **Color Format**: Always use 6-digit hex RGB (e.g., `0187A6`) without `#` prefix
+ - Pre-mix alpha transparency using `colord().mix()` before generating values
+
+#### ❌ Incorrect Method (DO NOT USE)
+
+```xml
+
+
+
+
+```
+
+```json
+// my-theme.theme.json - WRONG EXTENSION
+{
+ "editorScheme": "/themes/my-theme.icls" // ❌ WRONG
+}
+```
+
+#### Implementation Files
+
+- **Generator**: `src/generators/jetbrains/editor-scheme.ts` - Generates `.xml` files
+- **Theme Builder**: `src/generators/jetbrains/theme.ts` - References schemes in JSON
+- **Color Utility**: `src/generators/jetbrains/utils.ts` - `toHex()` function
+
+#### Testing Editor Schemes
+
+After modifying editor scheme generation:
+
+1. Build: `npm run build:jetbrains`
+2. Verify `.xml` files exist: `ls dist/jetbrains/themes/*.xml`
+3. Check theme JSON references: `grep editorScheme dist/jetbrains/themes/*.theme.json`
+4. Confirm NO bundledColorScheme: `grep bundledColorScheme dist/jetbrains/resources/META-INF/plugin.xml`
+5. Install and test: `npm run install:jetbrains:local`
+6. Restart IDE and verify no crashes
+
+**See `JETBRAINS-EDITOR-SCHEMES-FIX.md` for detailed troubleshooting history.**
## Testing Guidelines
-1. **Always run build after changes**: `npm run build`
+1. **Always run build after changes**: `npm run build` (automatically cleans dist folder and builds plugin)
2. **Test in VS Code**: Press F5 to launch Extension Development Host
-3. **Test multiple themes**: Check at least one dark, one light, and one HC theme
-4. **Check syntax highlighting**: Open files in JS, TS, Python, Markdown, CSS
-5. **Verify UI elements**: Sidebar, tabs, status bar, panels, notifications
+3. **Test in JetBrains**:
+ - For quick testing: Run `npm run install:jetbrains:local` and restart IDE
+ - For plugin testing: Install the built `.zip` from `dist/jetbrains/build/distributions/`
+4. **Test multiple themes**: Check at least one dark, one light, and one HC theme
+5. **Check syntax highlighting**: Open files in JS, TS, Python, Markdown, CSS
+6. **Verify UI elements**: Sidebar, tabs, status bar, panels, notifications
## Do's and Don'ts
@@ -281,7 +399,7 @@ interface ThemeOptions {
- ✅ Follow the established pattern when creating new themes
- ✅ Register new themes in `theme-registry.ts` (single source of truth)
- ✅ Run `npm run fix` before committing (uses ESLint Stylistic)
-- ✅ Test both VS Code and Zed output when modifying shared code
+- ✅ Test VS Code, Zed, and JetBrains output when modifying shared code
- ✅ Use meaningful, descriptive theme names
- ✅ Maintain color accessibility (contrast ratios)
@@ -293,6 +411,7 @@ interface ThemeOptions {
- ❌ Don't use RGB/HSL directly - always use hex with colord conversions
- ❌ Don't break existing theme slugs (used as identifiers)
- ❌ Don't create new documentation files (README.md, CONTRIBUTING.md, etc.) unless explicitly requested
+- ❌ Don't use unsupported JetBrains color keys (check IntelliJ Platform SDK docs)
## Accessibility Considerations
@@ -318,11 +437,94 @@ When creating or modifying themes:
## Version and Release
-1. Update version in `package.json`
-2. Create release notes: `npm run create:release-notes`
-3. Edit `releases/{version}.md` with changes
-4. Build extension: `npm run build:ext:vscode`
-5. Publish: `npm run publish:all`
+Each IDE is versioned and released independently. Versions are stored in `versions.json`.
+
+### Commit Convention
+
+Use IDE prefixes to target specific platforms in changelogs:
+
+```bash
+# VS Code specific
+[vscode] feat: add new color token
+[vscode] fix: correct bracket highlighting
+
+# Zed specific
+[zed] feat: add panel styling
+[zed] fix: correct status bar colors
+
+# JetBrains specific
+[jetbrains] feat: add bookmark UI support
+[jetbrains] fix: correct editor gutter colors
+
+# Global changes (included in ALL IDEs)
+feat: update syntax colors
+fix: improve contrast ratios
+```
+
+### Commit Types
+
+- `feat:` / `add:` - New features
+- `fix:` / `bug:` - Bug fixes
+- `improve:` / `enhancement:` - Improvements
+- `chore:` - Maintenance tasks
+- `docs:` - Documentation
+- `refactor:` - Code refactoring
+
+### Release Workflow
+
+**For VS Code:**
+
+```bash
+npm run bump:version vscode minor
+npm run build:vscode
+npm run create:release-notes vscode
+# Edit releases/vscode/{version}.md
+npm run build:ext:vscode
+./publish.sh vscode
+```
+
+**For Zed:**
+
+```bash
+npm run bump:version zed patch
+npm run build:zed
+npm run create:release-notes zed
+# Edit releases/zed/{version}.md
+# Commit and push, then open PR to zed-industries/extensions
+./publish.sh zed
+```
+
+**For JetBrains:**
+
+```bash
+npm run bump:version jetbrains patch
+npm run build:jetbrains
+npm run create:release-notes jetbrains
+# Edit releases/jetbrains/{version}.md
+npm run build:ext:jetbrains
+./publish.sh jetbrains
+```
+
+### Git Tags
+
+Each IDE has its own tag format:
+
+- VS Code: `vscode-v11.0.1`
+- Zed: `zed-v1.0.1`
+- JetBrains: `jetbrains-v1.0.1`
+
+### Release Notes Structure
+
+```
+releases/
+├── vscode/
+│ ├── 11.0.0.md
+│ └── 11.0.0.vsix
+├── zed/
+│ └── 1.0.0.md
+└── jetbrains/
+ └── 1.0.0.md
+```
## Dependencies
diff --git a/VERSIONING.md b/VERSIONING.md
index b98df9a5..17da3653 100644
--- a/VERSIONING.md
+++ b/VERSIONING.md
@@ -6,6 +6,7 @@ Bearded Theme uses **independent versions** for each IDE:
- **VS Code**: Version **11.0.0** (continues historical numbering)
- **Zed**: Version **1.0.0** (fresh start)
+- **JetBrains**: Version **1.0.0** (fresh start)
## Configuration
@@ -14,7 +15,8 @@ All versions are stored in `versions.json`:
```json
{
"vscode": "11.0.0",
- "zed": "1.0.0"
+ "zed": "1.0.0",
+ "jetbrains": "1.0.0"
}
```
@@ -29,13 +31,16 @@ cat versions.json
### Update versions
```bash
+# Bump VS Code: 11.0.0 → 11.1.0
+npm run bump:version vscode minor
+
# Bump Zed: 1.0.0 → 1.0.1
npm run bump:version zed patch
-# Bump VS Code: 11.0.0 → 11.1.0
-npm run bump:version vscode minor
+# Bump JetBrains: 1.0.0 → 1.0.1
+npm run bump:version jetbrains patch
-# Bump both
+# Bump all IDEs
npm run bump:version all patch
```
@@ -45,39 +50,134 @@ npm run bump:version all patch
- `minor` - New features (1.0.0 → 1.1.0)
- `major` - Breaking changes (1.0.0 → 2.0.0)
+## Release Notes
+
+Each IDE has its own release notes folder:
+
+```
+releases/
+├── vscode/
+│ ├── 11.0.0.md
+│ └── 11.0.0.vsix
+├── zed/
+│ └── 1.0.0.md
+└── jetbrains/
+ └── 1.0.0.md
+```
+
+### Create release notes
+
+```bash
+npm run create:release-notes vscode
+npm run create:release-notes zed
+npm run create:release-notes jetbrains
+```
+
+## Commit Convention
+
+Use IDE prefixes to target specific platforms in release notes:
+
+```bash
+# VS Code specific
+[vscode] feat: add new color token
+[vscode] fix: correct bracket highlighting
+
+# Zed specific
+[zed] feat: add panel styling
+[zed] fix: correct status bar colors
+
+# JetBrains specific
+[jetbrains] feat: add bookmark UI support
+[jetbrains] fix: correct editor gutter colors
+
+# Global (included in ALL IDEs)
+feat: update syntax colors
+fix: improve contrast ratios
+```
+
+### Commit types
+
+- `feat:` / `add:` - New features
+- `fix:` / `bug:` - Bug fixes
+- `improve:` / `enhancement:` - Improvements
+- `chore:` - Maintenance tasks
+- `docs:` - Documentation
+- `refactor:` - Code refactoring
+
## Workflows
+### For VS Code
+
+```bash
+npm run bump:version vscode minor
+npm run build:vscode
+npm run create:release-notes vscode
+# Edit releases/vscode/{version}.md
+npm run build:ext:vscode
+./publish.sh vscode
+```
+
### For Zed
```bash
npm run bump:version zed patch
npm run build:zed
-# Version appears in dist/zed/extension.toml
+npm run create:release-notes zed
+# Edit releases/zed/{version}.md
+# Commit and push changes
+# Open PR to zed-industries/extensions
+./publish.sh zed
```
-### For VS Code
+### For JetBrains
```bash
-npm run bump:version vscode minor
-npm run build:vscode
-npm run create:release-notes
-# Version synced to both versions.json and package.json
+npm run bump:version jetbrains patch
+npm run build:jetbrains
+npm run create:release-notes jetbrains
+# Edit releases/jetbrains/{version}.md
+npm run build:ext:jetbrains
+./publish.sh jetbrains
+```
+
+## Git Tags
+
+Each IDE has its own tag format:
+
+- VS Code: `vscode-v11.0.1`
+- Zed: `zed-v1.0.1`
+- JetBrains: `jetbrains-v1.0.1`
+
+Tags are created via the `publish.bat` script or manually:
+
+```bash
+npm run release:vscode
+npm run release:zed
+npm run release:jetbrains
```
## Important Notes
1. **VS Code**: The bump script automatically syncs `versions.json` and `package.json`
2. **Zed**: Only uses `versions.json`, no need to touch `package.json`
-3. Each IDE follows its own semantic versioning independently
-4. The system includes automatic fallbacks if `versions.json` is missing
+3. **JetBrains**: Only uses `versions.json`, plugin.xml version is generated
+4. Each IDE follows its own semantic versioning independently
+5. The system includes automatic fallbacks if `versions.json` is missing
## Code API
```typescript
-import { getVSCodeVersion, getZedVersion } from "./version-manager";
+import {
+ getVSCodeVersion,
+ getZedVersion,
+ getJetBrainsVersion,
+ getAllVersions,
+} from "./version-manager";
-const zedVersion = getZedVersion(); // "1.0.0"
const vscodeVersion = getVSCodeVersion(); // "11.0.0"
+const zedVersion = getZedVersion(); // "1.0.0"
+const jetbrainsVersion = getJetBrainsVersion(); // "1.0.0"
+const allVersions = getAllVersions(); // { vscode: "11.0.0", zed: "1.0.0", jetbrains: "1.0.0" }
```
## Benefits
@@ -85,3 +185,4 @@ const vscodeVersion = getVSCodeVersion(); // "11.0.0"
- **Independent releases** for each IDE
- **Clear versioning** that reflects platform-specific changes
- **Flexibility** to evolve each platform at its own pace
+- **Filtered changelogs** showing only relevant changes per IDE
diff --git a/package.json b/package.json
index c9404ad7..26d1e4a1 100644
--- a/package.json
+++ b/package.json
@@ -9,24 +9,29 @@
},
"type": "module",
"scripts": {
- "build": "vite-node src/build.ts all",
- "build:vscode": "vite-node src/generators/vscode/index.ts",
- "build:zed": "vite-node src/generators/zed/index.ts",
- "build:ext:vscode": "npm run build:vscode && vsce package --out ./releases/%npm_package_version%.vsix",
+ "clean": "node -e \"const fs=require('fs');['dist/vscode','dist/zed','dist/jetbrains'].forEach(d=>{if(fs.existsSync(d))fs.rmSync(d,{recursive:true})});console.log('Cleaned dist folders')\"",
+ "clean:vscode": "node -e \"const fs=require('fs');if(fs.existsSync('dist/vscode'))fs.rmSync('dist/vscode',{recursive:true});console.log('Cleaned dist/vscode')\"",
+ "clean:zed": "node -e \"const fs=require('fs');if(fs.existsSync('dist/zed'))fs.rmSync('dist/zed',{recursive:true});console.log('Cleaned dist/zed')\"",
+ "clean:jetbrains": "node -e \"const fs=require('fs');if(fs.existsSync('dist/jetbrains'))fs.rmSync('dist/jetbrains',{recursive:true});console.log('Cleaned dist/jetbrains')\"",
+ "build": "npm run clean && vite-node src/build.ts all",
+ "build:vscode": "npm run clean:vscode && vite-node src/generators/vscode/index.ts",
+ "build:zed": "npm run clean:zed && vite-node src/generators/zed/index.ts",
+ "build:jetbrains": "npm run clean:jetbrains && vite-node src/generators/jetbrains/index.ts",
+ "build:ext:vscode": "npm run build:vscode && vsce package --out ./releases/vscode/%npm_package_version%.vsix",
"build:ext:zed": "npm run build:zed",
- "publish:zed": "echo 'To publish Zed extension: 1) Push changes to GitHub 2) Open PR to zed-industries/extensions repo'",
- "zed:dev": "echo 'Install as dev extension: Open Zed > Extensions > Install Dev Extension > Select dist/zed folder'",
- "build:env": "tsc load-env.ts --esModuleInterop",
+ "build:ext:jetbrains": "npm run build:jetbrains && node -e \"const{execSync}=require('child_process');const{existsSync,mkdirSync,copyFileSync,readdirSync}=require('fs');const{join}=require('path');const dir=join(process.cwd(),'dist','jetbrains');const jar=join(dir,'gradle','wrapper','gradle-wrapper.jar');if(!existsSync(jar)){console.log('Downloading gradle-wrapper.jar...');execSync('powershell -Command \\\"Invoke-WebRequest -Uri https://github.com/gradle/gradle/raw/v8.13.0/gradle/wrapper/gradle-wrapper.jar -OutFile gradle/wrapper/gradle-wrapper.jar\\\"',{cwd:dir,stdio:'inherit'})}const isWin=process.platform==='win32';const cmd=isWin?'gradlew.bat':'./gradlew';execSync(cmd+' buildPlugin',{cwd:dir,stdio:'inherit'});const distDir=join(dir,'build','distributions');const releaseDir=join(process.cwd(),'releases','jetbrains');if(!existsSync(releaseDir))mkdirSync(releaseDir,{recursive:true});const zips=readdirSync(distDir).filter(f=>f.endsWith('.zip'));zips.forEach(z=>{copyFileSync(join(distDir,z),join(releaseDir,z));console.log('Copied to releases/jetbrains/'+z)})\"",
"dev:vscode": "nodemon --exec \"vite-node src/generators/vscode/index.ts\"",
"dev:zed": "nodemon --exec \"vite-node src/generators/zed/index.ts\"",
+ "dev:jetbrains": "nodemon --exec \"vite-node src/generators/jetbrains/index.ts\"",
"lint": "eslint src/**/*.{js,ts}",
"fix": "eslint src/**/*.{js,ts} --fix",
- "release": "gh release create v%npm_package_version% --notes-file ./releases/%npm_package_version%.md --generate-notes",
- "create:release-notes": "vite-node src/create-release-notes.ts",
"bump:version": "vite-node src/bump-version.ts",
- "publish:vscode": "bash -c \"read -p 'Enter your VS Code Marketplace token: ' TOKEN && vsce publish --packagePath ./releases/%npm_package_version%.vsix -p $TOKEN\"",
- "publish:ovsx": "bash -c \"read -p 'Enter your OVSX token: ' TOKEN && ovsx publish ./releases/%npm_package_version%.vsix -p $TOKEN\"",
- "publish:all": "npm run build:ext:vscode && npm run publish:vscode && npm run publish:ovsx"
+ "create:release-notes": "vite-node src/create-release-notes.ts",
+ "release:vscode": "node -e \"const v=require('./versions.json').vscode;const{execSync}=require('child_process');execSync('gh release create vscode-v'+v+' --notes-file ./releases/vscode/'+v+'.md --generate-notes',{stdio:'inherit'})\"",
+ "release:zed": "node -e \"const v=require('./versions.json').zed;const{execSync}=require('child_process');execSync('gh release create zed-v'+v+' --notes-file ./releases/zed/'+v+'.md --generate-notes',{stdio:'inherit'})\"",
+ "release:jetbrains": "node -e \"const v=require('./versions.json').jetbrains;const{execSync}=require('child_process');execSync('gh release create jetbrains-v'+v+' --notes-file ./releases/jetbrains/'+v+'.md --generate-notes',{stdio:'inherit'})\"",
+ "publish:vscode": "bash -c \"read -p 'Enter your VS Code Marketplace token: ' TOKEN && vsce publish --packagePath ./releases/vscode/%npm_package_version%.vsix -p $TOKEN\"",
+ "publish:ovsx": "bash -c \"read -p 'Enter your OVSX token: ' TOKEN && ovsx publish ./releases/vscode/%npm_package_version%.vsix -p $TOKEN\""
},
"__metadata": {
"id": "dffaf5a1-2219-434b-9d87-cb586fd59260",
diff --git a/publish.bat b/publish.bat
deleted file mode 100644
index 4816bfc9..00000000
--- a/publish.bat
+++ /dev/null
@@ -1,114 +0,0 @@
-@echo off
-setlocal enabledelayedexpansion
-
-REM Colors for better readability
-set "GREEN=[0;32m"
-set "BLUE=[0;34m"
-set "YELLOW=[1;33m"
-set "RED=[0;31m"
-set "NC=[0m"
-
-REM Get version from package.json using node
-for /f "tokens=*" %%a in ('node -p "require('./package.json').version"') do set VERSION=%%a
-set RELEASE_NOTES=./releases/%VERSION%.md
-
-echo !BLUE!^=== Bearded Theme Release Process ===!NC!
-echo !BLUE!Version: !GREEN!v%VERSION%!NC!
-
-REM Check if VSIX version already exists
-if exist "./releases/%VERSION%.vsix" (
- echo !YELLOW!VSIX file for v%VERSION% already exists.!NC!
- set /p REBUILD="Do you want to rebuild the package? (y/n) "
- echo.
- if /i "!REBUILD!"=="y" (
- echo !BLUE!Building VSIX package...!NC!
- call npm run build:ext
- )
-) else (
- echo !BLUE!Building VSIX package...!NC!
- call npm run build:ext
-)
-
-REM Check if release notes file exists
-if not exist "%RELEASE_NOTES%" (
- echo !YELLOW!Release notes file not found.!NC!
- set /p CREATE_NOTES="Do you want to create a release notes template? (y/n) "
- echo.
- if /i "!CREATE_NOTES!"=="y" (
- echo !BLUE!Creating release notes file...!NC!
- call npm run create:release-notes
- echo !GREEN!✓ Release notes file created: %RELEASE_NOTES%!NC!
- echo !YELLOW!Please edit the release notes file before continuing.!NC!
- echo Press Enter when you have finished editing...
- pause > nul
- echo.
- )
-) else (
- echo !GREEN!✓ Release notes file found: %RELEASE_NOTES%!NC!
-)
-
-REM Publish to VS Code Marketplace
-echo !BLUE!Publishing to VS Code Marketplace...!NC!
-if defined VSCE_PAT (
- echo !GREEN!✓ VSCE token found in environment variables!NC!
- call npm run publish:vscode
-) else (
- echo !YELLOW!VSCE token not found in environment variables!NC!
- set /p HAS_TOKEN="Do you have a VSCE token? (y/n) "
- echo.
- if /i "!HAS_TOKEN!"=="y" (
- set /p VSCE_TOKEN="Enter your VS Code Marketplace token: "
- echo.
- if defined VSCE_TOKEN (
- set "VSCE_PAT=!VSCE_TOKEN!"
- call npm run publish:vscode
- ) else (
- echo !RED!Empty token, VS Code Marketplace publication cancelled.!NC!
- )
- ) else (
- set /p TRY_PUBLISH="Do you still want to try publishing to VS Code Marketplace? (y/n) "
- echo.
- if /i "!TRY_PUBLISH!"=="y" (
- call npm run publish:vscode
- ) else (
- echo !YELLOW!VS Code Marketplace publication skipped.!NC!
- )
- )
-)
-
-REM Publish to Open VSX
-echo !BLUE!Publishing to Open VSX...!NC!
-if defined OVSX_TOKEN (
- echo !GREEN!✓ Open VSX token found in environment variables!NC!
- call npm run publish:ovsx
-) else (
- echo !YELLOW!Open VSX token not found in environment variables!NC!
- set /p HAS_OVSX_TOKEN="Do you have an Open VSX token? (y/n) "
- echo.
- if /i "!HAS_OVSX_TOKEN!"=="y" (
- set /p OVSX_TOKEN_VALUE="Enter your Open VSX token: "
- echo.
- if defined OVSX_TOKEN_VALUE (
- set "OVSX_TOKEN=!OVSX_TOKEN_VALUE!"
- call npm run publish:ovsx
- ) else (
- echo !RED!Empty token, Open VSX publication cancelled.!NC!
- )
- ) else (
- echo !YELLOW!Open VSX publication skipped.!NC!
- )
-)
-
-REM Create GitHub version tag
-echo !BLUE!Creating GitHub version tag...!NC!
-set /p CREATE_TAG="Do you want to create a GitHub tag for this version? (y/n) "
-echo.
-if /i "!CREATE_TAG!"=="y" (
- call npm run release
- echo !GREEN!✓ Tag v%VERSION% created on GitHub!NC!
-) else (
- echo !YELLOW!GitHub tag creation skipped.!NC!
-)
-
-echo !GREEN!^=== Publication process completed ===!NC!
-endlocal
diff --git a/publish.sh b/publish.sh
index f3ebe03f..012d3695 100644
--- a/publish.sh
+++ b/publish.sh
@@ -7,103 +7,233 @@ YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
-# Get version from package.json
-VERSION=$(node -p "require('./package.json').version")
-RELEASE_NOTES="./releases/$VERSION.md"
-
-echo -e "${BLUE}=== Bearded Theme Release Process ===${NC}"
-echo -e "${BLUE}Version: ${GREEN}v$VERSION${NC}"
-
-# Check if VSIX version already exists
-if [ -f "./releases/$VERSION.vsix" ]; then
- echo -e "${YELLOW}VSIX file for v$VERSION already exists.${NC}"
- read -p "Do you want to rebuild the package? (y/n) " -n 1 -r
- echo
- if [[ $REPLY =~ ^[Yy]$ ]]; then
+# ==========================================
+# VS Code publication
+# ==========================================
+publish_vscode() {
+ # Check if VSIX version already exists
+ if [ -f "./releases/vscode/$VERSION.vsix" ]; then
+ echo -e "${YELLOW}VSIX file for v$VERSION already exists.${NC}"
+ read -p "Do you want to rebuild the package? (y/n) " -n 1 -r
+ echo
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ echo -e "${BLUE}Building VSIX package...${NC}"
+ npm run build:ext:vscode
+ fi
+ else
echo -e "${BLUE}Building VSIX package...${NC}"
- npm run build:ext
+ npm run build:ext:vscode
fi
-else
- echo -e "${BLUE}Building VSIX package...${NC}"
- npm run build:ext
-fi
-# Check if release notes file exists
-if [ ! -f "$RELEASE_NOTES" ]; then
- echo -e "${YELLOW}Release notes file not found.${NC}"
- read -p "Do you want to create a release notes template? (y/n) " -n 1 -r
- echo
- if [[ $REPLY =~ ^[Yy]$ ]]; then
- echo -e "${BLUE}Creating release notes file...${NC}"
- npm run create:release-notes
- echo -e "${GREEN}✓ Release notes file created: $RELEASE_NOTES${NC}"
- echo -e "${YELLOW}Please edit the release notes file before continuing.${NC}"
- read -p "Press Enter when you have finished editing..." -n 1 -r
+ # Check if release notes file exists
+ if [ ! -f "$RELEASE_NOTES" ]; then
+ echo -e "${YELLOW}Release notes file not found.${NC}"
+ read -p "Do you want to create a release notes template? (y/n) " -n 1 -r
echo
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ echo -e "${BLUE}Creating release notes file...${NC}"
+ npm run create:release-notes vscode
+ echo -e "${GREEN}✓ Release notes file created: $RELEASE_NOTES${NC}"
+ echo -e "${YELLOW}Please edit the release notes file before continuing.${NC}"
+ read -p "Press Enter when you have finished editing..." -n 1 -r
+ echo
+ fi
+ else
+ echo -e "${GREEN}✓ Release notes file found: $RELEASE_NOTES${NC}"
fi
-else
- echo -e "${GREEN}✓ Release notes file found: $RELEASE_NOTES${NC}"
-fi
-# Publish to VS Code Marketplace
-echo -e "${BLUE}Publishing to VS Code Marketplace...${NC}"
-if [ -n "$VSCE_PAT" ]; then
- echo -e "${GREEN}✓ VSCE token found in environment variables${NC}"
- npm run publish:vscode
-else
- echo -e "${YELLOW}VSCE token not found in environment variables${NC}"
- read -p "Do you have a VSCE token? (y/n) " -n 1 -r
- echo
- if [[ $REPLY =~ ^[Yy]$ ]]; then
- read -p "Enter your VS Code Marketplace token: " VSCE_TOKEN
+ # Publish to VS Code Marketplace
+ echo -e "${BLUE}Publishing to VS Code Marketplace...${NC}"
+ if [ -n "$VSCE_PAT" ]; then
+ echo -e "${GREEN}✓ VSCE token found in environment variables${NC}"
+ npm run publish:vscode
+ else
+ echo -e "${YELLOW}VSCE token not found in environment variables${NC}"
+ read -p "Do you have a VSCE token? (y/n) " -n 1 -r
echo
- if [ -n "$VSCE_TOKEN" ]; then
- VSCE_PAT=$VSCE_TOKEN npm run publish:vscode
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ read -p "Enter your VS Code Marketplace token: " VSCE_TOKEN
+ echo
+ if [ -n "$VSCE_TOKEN" ]; then
+ VSCE_PAT=$VSCE_TOKEN npm run publish:vscode
+ else
+ echo -e "${RED}Empty token, VS Code Marketplace publication cancelled.${NC}"
+ fi
else
- echo -e "${RED}Empty token, VS Code Marketplace publication cancelled.${NC}"
+ read -p "Do you still want to try publishing to VS Code Marketplace? (y/n) " -n 1 -r
+ echo
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ npm run publish:vscode
+ else
+ echo -e "${YELLOW}VS Code Marketplace publication skipped.${NC}"
+ fi
fi
+ fi
+
+ # Publish to Open VSX
+ echo -e "${BLUE}Publishing to Open VSX...${NC}"
+ if [ -n "$OVSX_TOKEN" ]; then
+ echo -e "${GREEN}✓ Open VSX token found in environment variables${NC}"
+ npm run publish:ovsx
else
- read -p "Do you still want to try publishing to VS Code Marketplace? (y/n) " -n 1 -r
+ echo -e "${YELLOW}Open VSX token not found in environment variables${NC}"
+ read -p "Do you have an Open VSX token? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
- npm run publish:vscode
+ read -p "Enter your Open VSX token: " OVSX_TOKEN_VALUE
+ echo
+ if [ -n "$OVSX_TOKEN_VALUE" ]; then
+ OVSX_TOKEN=$OVSX_TOKEN_VALUE npm run publish:ovsx
+ else
+ echo -e "${RED}Empty token, Open VSX publication cancelled.${NC}"
+ fi
else
- echo -e "${YELLOW}VS Code Marketplace publication skipped.${NC}"
+ echo -e "${YELLOW}Open VSX publication skipped.${NC}"
fi
fi
-fi
-# Publish to Open VSX
-echo -e "${BLUE}Publishing to Open VSX...${NC}"
-if [ -n "$OVSX_TOKEN" ]; then
- echo -e "${GREEN}✓ Open VSX token found in environment variables${NC}"
- npm run publish:ovsx
-else
- echo -e "${YELLOW}Open VSX token not found in environment variables${NC}"
- read -p "Do you have an Open VSX token? (y/n) " -n 1 -r
+ # Create GitHub version tag
+ echo -e "${BLUE}Creating GitHub version tag...${NC}"
+ read -p "Do you want to create a GitHub tag for this version? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
- read -p "Enter your Open VSX token: " OVSX_TOKEN_VALUE
+ npm run release:vscode
+ echo -e "${GREEN}✓ Tag vscode-v$VERSION created on GitHub${NC}"
+ else
+ echo -e "${YELLOW}GitHub tag creation skipped.${NC}"
+ fi
+}
+
+# ==========================================
+# Zed publication
+# ==========================================
+publish_zed() {
+ # Build Zed extension
+ echo -e "${BLUE}Building Zed extension...${NC}"
+ npm run build:ext:zed
+
+ # Check if release notes file exists
+ if [ ! -f "$RELEASE_NOTES" ]; then
+ echo -e "${YELLOW}Release notes file not found.${NC}"
+ read -p "Do you want to create a release notes template? (y/n) " -n 1 -r
echo
- if [ -n "$OVSX_TOKEN_VALUE" ]; then
- OVSX_TOKEN=$OVSX_TOKEN_VALUE npm run publish:ovsx
- else
- echo -e "${RED}Empty token, Open VSX publication cancelled.${NC}"
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ echo -e "${BLUE}Creating release notes file...${NC}"
+ npm run create:release-notes zed
+ echo -e "${GREEN}✓ Release notes file created: $RELEASE_NOTES${NC}"
+ echo -e "${YELLOW}Please edit the release notes file before continuing.${NC}"
+ read -p "Press Enter when you have finished editing..." -n 1 -r
+ echo
+ fi
+ else
+ echo -e "${GREEN}✓ Release notes file found: $RELEASE_NOTES${NC}"
+ fi
+
+ echo ""
+ echo -e "${BLUE}Zed publication steps:${NC}"
+ echo " 1. Extension built in: dist/zed/"
+ echo " 2. Commit and push your changes"
+ echo " 3. Open a PR to zed-industries/extensions repository"
+ echo ""
+
+ # Create GitHub version tag
+ read -p "Do you want to create a GitHub tag for this version? (y/n) " -n 1 -r
+ echo
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ npm run release:zed
+ echo -e "${GREEN}✓ Tag zed-v$VERSION created on GitHub${NC}"
+ else
+ echo -e "${YELLOW}GitHub tag creation skipped.${NC}"
+ fi
+}
+
+# ==========================================
+# JetBrains publication
+# ==========================================
+publish_jetbrains() {
+ # Build JetBrains plugin
+ echo -e "${BLUE}Building JetBrains plugin...${NC}"
+ npm run build:ext:jetbrains
+
+ # Check if release notes file exists
+ if [ ! -f "$RELEASE_NOTES" ]; then
+ echo -e "${YELLOW}Release notes file not found.${NC}"
+ read -p "Do you want to create a release notes template? (y/n) " -n 1 -r
+ echo
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ echo -e "${BLUE}Creating release notes file...${NC}"
+ npm run create:release-notes jetbrains
+ echo -e "${GREEN}✓ Release notes file created: $RELEASE_NOTES${NC}"
+ echo -e "${YELLOW}Please edit the release notes file before continuing.${NC}"
+ read -p "Press Enter when you have finished editing..." -n 1 -r
+ echo
fi
else
- echo -e "${YELLOW}Open VSX publication skipped.${NC}"
+ echo -e "${GREEN}✓ Release notes file found: $RELEASE_NOTES${NC}"
fi
+
+ echo ""
+ echo -e "${BLUE}JetBrains publication steps:${NC}"
+ echo " 1. Plugin built in: releases/jetbrains/"
+ echo " 2. Go to https://plugins.jetbrains.com/"
+ echo " 3. Upload the ZIP file manually"
+ echo ""
+
+ # Create GitHub version tag
+ read -p "Do you want to create a GitHub tag for this version? (y/n) " -n 1 -r
+ echo
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ npm run release:jetbrains
+ echo -e "${GREEN}✓ Tag jetbrains-v$VERSION created on GitHub${NC}"
+ else
+ echo -e "${YELLOW}GitHub tag creation skipped.${NC}"
+ fi
+}
+
+# ==========================================
+# Main script
+# ==========================================
+
+# Check for IDE argument
+if [ -z "$1" ]; then
+ echo -e "${RED}Usage: ./publish.sh ${NC}"
+ echo " ide: vscode | zed | jetbrains"
+ echo ""
+ echo "Examples:"
+ echo " ./publish.sh vscode"
+ echo " ./publish.sh zed"
+ echo " ./publish.sh jetbrains"
+ exit 1
fi
-# Create GitHub version tag
-echo -e "${BLUE}Creating GitHub version tag...${NC}"
-read -p "Do you want to create a GitHub tag for this version? (y/n) " -n 1 -r
-echo
-if [[ $REPLY =~ ^[Yy]$ ]]; then
- npm run release
- echo -e "${GREEN}✓ Tag v$VERSION created on GitHub${NC}"
-else
- echo -e "${YELLOW}GitHub tag creation skipped.${NC}"
+IDE=$1
+
+# Validate IDE argument
+if [[ ! "$IDE" =~ ^(vscode|zed|jetbrains)$ ]]; then
+ echo -e "${RED}Invalid IDE: $IDE${NC}"
+ echo " Must be: vscode | zed | jetbrains"
+ exit 1
fi
+# Get version from versions.json
+VERSION=$(node -p "require('./versions.json').$IDE")
+RELEASE_NOTES="./releases/$IDE/$VERSION.md"
+
+echo -e "${BLUE}=== Bearded Theme Release Process ===${NC}"
+echo -e "${BLUE}IDE: ${GREEN}$IDE${NC}"
+echo -e "${BLUE}Version: ${GREEN}v$VERSION${NC}"
+
+# IDE-specific publication
+case $IDE in
+ vscode)
+ publish_vscode
+ ;;
+ zed)
+ publish_zed
+ ;;
+ jetbrains)
+ publish_jetbrains
+ ;;
+esac
+
echo -e "${GREEN}=== Publication process completed ===${NC}"
diff --git a/releases/jetbrains/.gitkeep b/releases/jetbrains/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/releases/jetbrains/1.0.0.md b/releases/jetbrains/1.0.0.md
new file mode 100644
index 00000000..a9e75e69
--- /dev/null
+++ b/releases/jetbrains/1.0.0.md
@@ -0,0 +1,36 @@
+## 1.0.0 - 2026-01-21
+
+### Features and Improvements
+
+- Add .claude to .gitignore
+- Add JetBrains bookmark UI keys
+- Add JetBrains theme generator
+- Add zed dist
+- Add borders and version control colors to Zed UI
+- Add Zed theme generator
+- Add versioning support and bump script
+- Add editor.subheader and search.active styles for Zed
+- Add Zed publish/dev scripts and generator updates
+- Add AGENTS.md with AI agent guidelines
+- Add Zed support and update build scripts
+- Add new experimental variation : OLED [#207 (Thanks @Nova38)](https://github.com/BeardedBear/bearded-theme/issues/207)
+- Improve contrast for light theme
+- Improve publish process
+- Add inline suggest support
+- Add scmGraph foreground support
+
+### Bug Fixes
+
+- Fix Zed theme text and ignored color mappings
+- Fix python doc string contrast [#203 (Thanks @johnReeferVermont)](https://github.com/BeardedBear/bearded-theme/issues/203)
+- Fix inlay hint colors [#201 (Thanks @Oracynx)](https://github.com/BeardedBear/bearded-theme/issues/201)
+- Fix bash evaluation and pipe colors [#169 (Thanks @Wheels35)](https://github.com/BeardedBear/bearded-theme/issues/169)
+- Fix window control hover in linux [#204 (Thanks @PavelDobCZ23)](https://github.com/BeardedBear/bearded-theme/issues/204)
+- Fix status bar item contrast [#195 (Thanks @Loskir)](https://github.com/BeardedBear/bearded-theme/issues/195)
+- Fix list background hover contrast
+- Fix Icons in popup dialogs have unnatural colors [#165 (Thanks @Loskir)](https://github.com/BeardedBear/bearded-theme/issues/165)
+- Fix tab foreground color with no modifications [#205 (Thanks @lperson)](https://github.com/BeardedBear/bearded-theme/issues/205)
+- Fix toolbar icon background
+- Fix Don't distribute image assets within extension package [#196 (Thanks @stevenlele)](https://github.com/BeardedBear/bearded-theme/issues/196)
+- Fix links color
+
diff --git a/releases/10.0.0.md b/releases/vscode/10.0.0.md
similarity index 100%
rename from releases/10.0.0.md
rename to releases/vscode/10.0.0.md
diff --git a/releases/10.1.0.md b/releases/vscode/10.1.0.md
similarity index 100%
rename from releases/10.1.0.md
rename to releases/vscode/10.1.0.md
diff --git a/releases/vscode/11.0.0.md b/releases/vscode/11.0.0.md
new file mode 100644
index 00000000..dda95a84
--- /dev/null
+++ b/releases/vscode/11.0.0.md
@@ -0,0 +1,36 @@
+## 11.0.0 - 2026-01-21
+
+### Features and Improvements
+
+- Add .claude to .gitignore
+- Add JetBrains bookmark UI keys
+- Add JetBrains theme generator
+- Add zed dist
+- Add borders and version control colors to Zed UI
+- Add Zed theme generator
+- Add versioning support and bump script
+- Add editor.subheader and search.active styles for Zed
+- Add Zed publish/dev scripts and generator updates
+- Add AGENTS.md with AI agent guidelines
+- Add Zed support and update build scripts
+- Add new experimental variation : OLED [#207 (Thanks @Nova38)](https://github.com/BeardedBear/bearded-theme/issues/207)
+- Improve contrast for light theme
+- Improve publish process
+- Add inline suggest support
+- Add scmGraph foreground support
+
+### Bug Fixes
+
+- Fix Zed theme text and ignored color mappings
+- Fix python doc string contrast [#203 (Thanks @johnReeferVermont)](https://github.com/BeardedBear/bearded-theme/issues/203)
+- Fix inlay hint colors [#201 (Thanks @Oracynx)](https://github.com/BeardedBear/bearded-theme/issues/201)
+- Fix bash evaluation and pipe colors [#169 (Thanks @Wheels35)](https://github.com/BeardedBear/bearded-theme/issues/169)
+- Fix window control hover in linux [#204 (Thanks @PavelDobCZ23)](https://github.com/BeardedBear/bearded-theme/issues/204)
+- Fix status bar item contrast [#195 (Thanks @Loskir)](https://github.com/BeardedBear/bearded-theme/issues/195)
+- Fix list background hover contrast
+- Fix Icons in popup dialogs have unnatural colors [#165 (Thanks @Loskir)](https://github.com/BeardedBear/bearded-theme/issues/165)
+- Fix tab foreground color with no modifications [#205 (Thanks @lperson)](https://github.com/BeardedBear/bearded-theme/issues/205)
+- Fix toolbar icon background
+- Fix Don't distribute image assets within extension package [#196 (Thanks @stevenlele)](https://github.com/BeardedBear/bearded-theme/issues/196)
+- Fix links color
+
diff --git a/releases/8.3.2.md b/releases/vscode/8.3.2.md
similarity index 100%
rename from releases/8.3.2.md
rename to releases/vscode/8.3.2.md
diff --git a/releases/9.0.0.md b/releases/vscode/9.0.0.md
similarity index 100%
rename from releases/9.0.0.md
rename to releases/vscode/9.0.0.md
diff --git a/releases/9.0.1.md b/releases/vscode/9.0.1.md
similarity index 100%
rename from releases/9.0.1.md
rename to releases/vscode/9.0.1.md
diff --git a/releases/9.1.0.md b/releases/vscode/9.1.0.md
similarity index 100%
rename from releases/9.1.0.md
rename to releases/vscode/9.1.0.md
diff --git a/releases/9.1.1.md b/releases/vscode/9.1.1.md
similarity index 100%
rename from releases/9.1.1.md
rename to releases/vscode/9.1.1.md
diff --git a/releases/9.1.2.md b/releases/vscode/9.1.2.md
similarity index 100%
rename from releases/9.1.2.md
rename to releases/vscode/9.1.2.md
diff --git a/releases/9.1.3.md b/releases/vscode/9.1.3.md
similarity index 100%
rename from releases/9.1.3.md
rename to releases/vscode/9.1.3.md
diff --git a/releases/9.1.4.md b/releases/vscode/9.1.4.md
similarity index 100%
rename from releases/9.1.4.md
rename to releases/vscode/9.1.4.md
diff --git a/releases/9.1.5.md b/releases/vscode/9.1.5.md
similarity index 100%
rename from releases/9.1.5.md
rename to releases/vscode/9.1.5.md
diff --git a/releases/9.2.0.md b/releases/vscode/9.2.0.md
similarity index 100%
rename from releases/9.2.0.md
rename to releases/vscode/9.2.0.md
diff --git a/releases/9.3.0.md b/releases/vscode/9.3.0.md
similarity index 100%
rename from releases/9.3.0.md
rename to releases/vscode/9.3.0.md
diff --git a/CHANGELOG.md b/releases/vscode/CHANGELOG.md
similarity index 100%
rename from CHANGELOG.md
rename to releases/vscode/CHANGELOG.md
diff --git a/releases/zed/.gitkeep b/releases/zed/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/releases/zed/1.0.0.md b/releases/zed/1.0.0.md
new file mode 100644
index 00000000..a9e75e69
--- /dev/null
+++ b/releases/zed/1.0.0.md
@@ -0,0 +1,36 @@
+## 1.0.0 - 2026-01-21
+
+### Features and Improvements
+
+- Add .claude to .gitignore
+- Add JetBrains bookmark UI keys
+- Add JetBrains theme generator
+- Add zed dist
+- Add borders and version control colors to Zed UI
+- Add Zed theme generator
+- Add versioning support and bump script
+- Add editor.subheader and search.active styles for Zed
+- Add Zed publish/dev scripts and generator updates
+- Add AGENTS.md with AI agent guidelines
+- Add Zed support and update build scripts
+- Add new experimental variation : OLED [#207 (Thanks @Nova38)](https://github.com/BeardedBear/bearded-theme/issues/207)
+- Improve contrast for light theme
+- Improve publish process
+- Add inline suggest support
+- Add scmGraph foreground support
+
+### Bug Fixes
+
+- Fix Zed theme text and ignored color mappings
+- Fix python doc string contrast [#203 (Thanks @johnReeferVermont)](https://github.com/BeardedBear/bearded-theme/issues/203)
+- Fix inlay hint colors [#201 (Thanks @Oracynx)](https://github.com/BeardedBear/bearded-theme/issues/201)
+- Fix bash evaluation and pipe colors [#169 (Thanks @Wheels35)](https://github.com/BeardedBear/bearded-theme/issues/169)
+- Fix window control hover in linux [#204 (Thanks @PavelDobCZ23)](https://github.com/BeardedBear/bearded-theme/issues/204)
+- Fix status bar item contrast [#195 (Thanks @Loskir)](https://github.com/BeardedBear/bearded-theme/issues/195)
+- Fix list background hover contrast
+- Fix Icons in popup dialogs have unnatural colors [#165 (Thanks @Loskir)](https://github.com/BeardedBear/bearded-theme/issues/165)
+- Fix tab foreground color with no modifications [#205 (Thanks @lperson)](https://github.com/BeardedBear/bearded-theme/issues/205)
+- Fix toolbar icon background
+- Fix Don't distribute image assets within extension package [#196 (Thanks @stevenlele)](https://github.com/BeardedBear/bearded-theme/issues/196)
+- Fix links color
+
diff --git a/src/build.ts b/src/build.ts
index ea9e7e17..c7372b43 100644
--- a/src/build.ts
+++ b/src/build.ts
@@ -1,13 +1,102 @@
/**
* Bearded Theme Build Orchestrator
*
- * This script orchestrates the build process for both VSCode and Zed themes.
- * Run with: vite-node src/build.ts [vscode|zed|all]
+ * This script orchestrates the build process for VSCode, Zed, and JetBrains themes.
+ * Run with: vite-node src/build.ts [vscode|zed|jetbrains|all]
*/
import { execSync } from "child_process";
+import {
+ copyFileSync,
+ existsSync,
+ mkdirSync,
+ readdirSync,
+ readFileSync,
+} from "fs";
+import { join } from "path";
-type BuildTarget = "all" | "vscode" | "zed";
+type BuildTarget = "all" | "jetbrains" | "vscode" | "zed";
+
+function buildJetBrains(): void {
+ console.log("\n🟣 Building JetBrains themes...\n");
+ execSync("vite-node src/generators/jetbrains/index.ts", { stdio: "inherit" });
+}
+
+function buildJetBrainsPlugin(): void {
+ console.log("\n📦 Building JetBrains plugin package...\n");
+
+ const jetbrainsDir = join(process.cwd(), "dist", "jetbrains");
+
+ // Check if Java is available
+ if (!isCommandAvailable("java")) {
+ console.warn("\n⚠️ Java not found in PATH.");
+ console.warn(" Make sure Java 11+ is installed and JAVA_HOME is set.");
+ console.warn(" Theme files were still generated in dist/jetbrains/\n");
+ console.warn(" To build manually after installing Java:");
+ console.warn(" cd dist/jetbrains");
+ console.warn(" gradlew.bat buildPlugin (Windows)");
+ console.warn(" ./gradlew buildPlugin (macOS/Linux)\n");
+ return;
+ }
+
+ try {
+ execSync("java -version", { stdio: "pipe" });
+ } catch {
+ console.warn("\n⚠️ Could not verify Java installation.");
+ console.warn(" Theme files were still generated in dist/jetbrains/\n");
+ return;
+ }
+
+ // Determine the correct Gradle wrapper command for the platform
+ const isWindows = process.platform === "win32";
+ const gradleWrapper = isWindows ? "gradlew.bat" : "./gradlew";
+
+ // Initialize the wrapper if needed
+ if (!initGradleWrapper(jetbrainsDir)) {
+ console.warn("\n⚠️ Could not initialize Gradle wrapper.");
+ console.warn(" Please install Gradle and run: gradle wrapper --gradle-version 8.5");
+ console.warn(" Or download gradle-wrapper.jar manually to dist/jetbrains/gradle/wrapper/");
+ console.warn(" Theme files were still generated in dist/jetbrains/\n");
+ return;
+ }
+
+ // Build the plugin using the wrapper with cwd option
+ console.log("\n 🔨 Running Gradle build...\n");
+ try {
+ execSync(`${gradleWrapper} buildPlugin`, {
+ cwd: jetbrainsDir,
+ stdio: "inherit",
+ });
+
+ // Copy ZIP to releases/jetbrains/ with version number
+ const distDir = join(jetbrainsDir, "build", "distributions");
+ const releaseDir = join(process.cwd(), "releases", "jetbrains");
+
+ if (!existsSync(releaseDir)) {
+ mkdirSync(releaseDir, { recursive: true });
+ }
+
+ // Get version from versions.json
+ const versionsPath = join(process.cwd(), "versions.json");
+ const versions = JSON.parse(readFileSync(versionsPath, "utf8"));
+ const version = versions.jetbrains;
+
+ // Find and copy ZIP files
+ const zips = readdirSync(distDir).filter((f) => f.endsWith(".zip"));
+ zips.forEach((zip) => {
+ const destName = `bearded-theme-${version}.zip`;
+ copyFileSync(join(distDir, zip), join(releaseDir, destName));
+ console.log(`\n 📦 Copied to releases/jetbrains/${destName}`);
+ });
+
+ console.log("\n✅ JetBrains plugin built successfully!");
+ console.log(` Plugin ZIP: releases/jetbrains/bearded-theme-${version}.zip\n`);
+ } catch {
+ console.warn("\n⚠️ Gradle build failed.");
+ console.warn(" Check the error messages above for details.");
+ console.warn(" Theme files were still generated in dist/jetbrains/\n");
+ }
+}
function buildVscode(): void {
console.log("\n🔵 Building VSCode themes...\n");
@@ -21,12 +110,86 @@ function buildZed(): void {
function getBuildTarget(): BuildTarget {
const arg = process.argv[2]?.toLowerCase();
- if (arg === "vscode" || arg === "zed" || arg === "all") {
+ if (
+ arg === "vscode" ||
+ arg === "zed" ||
+ arg === "jetbrains" ||
+ arg === "all"
+ ) {
return arg;
}
return "all";
}
+/**
+ * Initialize or update the Gradle wrapper
+ */
+function initGradleWrapper(jetbrainsDir: string): boolean {
+ const isWindows = process.platform === "win32";
+ const wrapperJar = join(jetbrainsDir, "gradle", "wrapper", "gradle-wrapper.jar");
+
+ // If wrapper jar already exists, we're good
+ if (existsSync(wrapperJar)) {
+ return true;
+ }
+
+ console.log(" 📥 Gradle wrapper jar not found, initializing...");
+
+ // Try using gradle command to generate the wrapper
+ if (isCommandAvailable("gradle")) {
+ console.log(" Using 'gradle' to generate wrapper...");
+ try {
+ execSync("gradle wrapper --gradle-version 8.5", {
+ cwd: jetbrainsDir,
+ stdio: "inherit",
+ });
+ return true;
+ } catch (error) {
+ console.warn(" Failed to generate wrapper with gradle:", error);
+ }
+ }
+
+ // Try downloading the wrapper jar directly
+ console.log(" Attempting to download gradle-wrapper.jar...");
+ const wrapperJarUrl =
+ "https://github.com/gradle/gradle/raw/v8.13.0/gradle/wrapper/gradle-wrapper.jar";
+
+ try {
+ if (isWindows) {
+ // Use PowerShell to download on Windows
+ execSync(
+ `powershell -Command "New-Item -ItemType Directory -Force -Path 'gradle\\wrapper' | Out-Null; Invoke-WebRequest -Uri '${wrapperJarUrl}' -OutFile 'gradle\\wrapper\\gradle-wrapper.jar'"`,
+ { cwd: jetbrainsDir, stdio: "inherit" },
+ );
+ } else {
+ // Use curl on Unix
+ execSync(
+ `mkdir -p gradle/wrapper && curl -L -o gradle/wrapper/gradle-wrapper.jar "${wrapperJarUrl}"`,
+ { cwd: jetbrainsDir, stdio: "inherit" },
+ );
+ }
+ return true;
+ } catch (error) {
+ console.warn(" Failed to download wrapper jar:", error);
+ }
+
+ return false;
+}
+
+/**
+ * Check if a command is available in the system PATH
+ */
+function isCommandAvailable(command: string): boolean {
+ try {
+ const isWindows = process.platform === "win32";
+ const checkCmd = isWindows ? `where ${command}` : `which ${command}`;
+ execSync(checkCmd, { stdio: "pipe" });
+ return true;
+ } catch {
+ return false;
+ }
+}
+
async function main(): Promise {
const target = getBuildTarget();
@@ -42,6 +205,11 @@ async function main(): Promise {
case "all":
buildVscode();
buildZed();
+ buildJetBrains();
+ buildJetBrainsPlugin();
+ break;
+ case "jetbrains":
+ buildJetBrains();
break;
case "vscode":
buildVscode();
@@ -60,6 +228,10 @@ async function main(): Promise {
if (target === "zed" || target === "all") {
console.log(" - dist/zed/themes/");
}
+ if (target === "jetbrains" || target === "all") {
+ console.log(" - dist/jetbrains/themes/");
+ console.log(" - dist/jetbrains/resources/META-INF/");
+ }
} catch (error) {
console.error("\n❌ Build failed:", error);
process.exit(1);
diff --git a/src/bump-version.ts b/src/bump-version.ts
index 22070c02..670ef9b2 100644
--- a/src/bump-version.ts
+++ b/src/bump-version.ts
@@ -9,12 +9,13 @@ type BumpType = "major" | "minor" | "patch";
/**
* IDE types
*/
-type IDE = "all" | "vscode" | "zed";
+type IDE = "all" | "jetbrains" | "vscode" | "zed";
/**
* Version configuration interface
*/
interface VersionConfig {
+ jetbrains: string;
vscode: string;
zed: string;
}
@@ -45,17 +46,20 @@ function main(): void {
if (args.length !== 2) {
console.error("Usage: npm run bump:version ");
- console.error(" ide: vscode | zed | all");
+ console.error(" ide: vscode | zed | jetbrains | all");
console.error(" type: major | minor | patch");
console.error("");
console.error("Examples:");
console.error(
- " npm run bump:version zed patch # Bump Zed from 1.0.0 to 1.0.1",
+ " npm run bump:version zed patch # Bump Zed from 1.0.0 to 1.0.1",
);
console.error(
- " npm run bump:version vscode minor # Bump VS Code from 11.0.0 to 11.1.0",
+ " npm run bump:version vscode minor # Bump VS Code from 11.0.0 to 11.1.0",
);
- console.error(" npm run bump:version all patch # Bump both IDEs");
+ console.error(
+ " npm run bump:version jetbrains patch # Bump JetBrains from 1.0.0 to 1.0.1",
+ );
+ console.error(" npm run bump:version all patch # Bump all IDEs");
process.exit(1);
}
@@ -63,9 +67,9 @@ function main(): void {
const bumpType = args[1] as BumpType;
// Validate arguments
- if (!["all", "vscode", "zed"].includes(ide)) {
+ if (!["all", "jetbrains", "vscode", "zed"].includes(ide)) {
console.error(`❌ Invalid IDE: ${ide}`);
- console.error(" Must be: vscode | zed | all");
+ console.error(" Must be: vscode | zed | jetbrains | all");
process.exit(1);
}
@@ -79,8 +83,9 @@ function main(): void {
// Read current versions
const versions = readVersionConfig();
console.log("📦 Current versions:");
- console.log(` VS Code: ${versions.vscode}`);
- console.log(` Zed: ${versions.zed}`);
+ console.log(` VS Code: ${versions.vscode}`);
+ console.log(` Zed: ${versions.zed}`);
+ console.log(` JetBrains: ${versions.jetbrains}`);
console.log("");
// Bump versions
@@ -101,7 +106,14 @@ function main(): void {
const oldVersion = versions.zed;
const newVersion = bumpVersion(oldVersion, bumpType);
versions.zed = newVersion;
- console.log(`✅ Zed: ${oldVersion} → ${newVersion}`);
+ console.log(`✅ Zed: ${oldVersion} → ${newVersion}`);
+ }
+
+ if (ide === "jetbrains" || ide === "all") {
+ const oldVersion = versions.jetbrains;
+ const newVersion = bumpVersion(oldVersion, bumpType);
+ versions.jetbrains = newVersion;
+ console.log(`✅ JetBrains: ${oldVersion} → ${newVersion}`);
}
// Save updated versions
@@ -112,17 +124,33 @@ function main(): void {
console.log("📝 Next steps:");
if (ide === "vscode" || ide === "all") {
+ console.log("");
+ console.log(" VS Code:");
console.log(" 1. Run: npm run build:vscode");
- console.log(" 2. Run: npm run create:release-notes");
- console.log(` 3. Edit: releases/${versions.vscode}.md`);
+ console.log(" 2. Run: npm run create:release-notes vscode");
+ console.log(` 3. Edit: releases/vscode/${versions.vscode}.md`);
console.log(" 4. Run: npm run build:ext:vscode");
- console.log(" 5. Run: npm run publish:all");
+ console.log(" 5. Run: publish.bat vscode");
}
if (ide === "zed" || ide === "all") {
+ console.log("");
+ console.log(" Zed:");
console.log(" 1. Run: npm run build:zed");
- console.log(" 2. Commit and push changes");
- console.log(" 3. Open PR to zed-industries/extensions");
+ console.log(" 2. Run: npm run create:release-notes zed");
+ console.log(` 3. Edit: releases/zed/${versions.zed}.md`);
+ console.log(" 4. Commit and push changes");
+ console.log(" 5. Open PR to zed-industries/extensions");
+ }
+
+ if (ide === "jetbrains" || ide === "all") {
+ console.log("");
+ console.log(" JetBrains:");
+ console.log(" 1. Run: npm run build:jetbrains");
+ console.log(" 2. Run: npm run create:release-notes jetbrains");
+ console.log(` 3. Edit: releases/jetbrains/${versions.jetbrains}.md`);
+ console.log(" 4. Run: npm run build:ext:jetbrains");
+ console.log(" 5. Run: publish.bat jetbrains");
}
} catch (error) {
console.error("❌ Error:", error);
diff --git a/src/create-release-notes.ts b/src/create-release-notes.ts
index 44e95a33..5fadbdb0 100644
--- a/src/create-release-notes.ts
+++ b/src/create-release-notes.ts
@@ -3,20 +3,45 @@ import * as fs from "fs";
import * as path from "path";
/**
- * Creates release notes for the current version of the package
+ * IDE types
*/
-const createReleaseNotes = (): void => {
+type IDE = "jetbrains" | "vscode" | "zed";
+
+/**
+ * Version configuration interface
+ */
+interface VersionConfig {
+ jetbrains: string;
+ vscode: string;
+ zed: string;
+}
+
+/**
+ * Read versions.json
+ */
+function readVersionConfig(): VersionConfig {
+ const versionsPath = path.resolve(process.cwd(), "versions.json");
+ return JSON.parse(fs.readFileSync(versionsPath, "utf8"));
+}
+
+/**
+ * Creates release notes for a specific IDE
+ */
+const createReleaseNotes = (ide: IDE): void => {
try {
- // Get the current package version from package.json
- const packagePath = path.resolve(process.cwd(), "package.json");
- const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
- const version = packageJson.version;
+ // Get the version for the specified IDE from versions.json
+ const versions = readVersionConfig();
+ const version = versions[ide];
// Get the current branch
const branch = execSync("git branch --show-current").toString().trim();
- // Create the output path
- const outputPath = path.resolve(process.cwd(), "releases", `${version}.md`);
+ // Create the output directory and path
+ const outputDir = path.resolve(process.cwd(), "releases", ide);
+ if (!fs.existsSync(outputDir)) {
+ fs.mkdirSync(outputDir, { recursive: true });
+ }
+ const outputPath = path.resolve(outputDir, `${version}.md`);
// Create the header with version and date
const today = new Date();
@@ -26,16 +51,25 @@ const createReleaseNotes = (): void => {
// Fetch all tags
execSync("git fetch --tags");
- // Check if there are previous tags
+ // Check if there are previous tags for this IDE
let hasPreviousTag = false;
let lastTag = "";
try {
- // Use a more Windows-friendly approach to check for tags
- const tagsOutput = execSync("git tag -l").toString().trim();
- hasPreviousTag = tagsOutput.length > 0;
-
- if (hasPreviousTag) {
- lastTag = execSync("git describe --tags --abbrev=0").toString().trim();
+ // Look for IDE-specific tags first, then fall back to any tag
+ const tagsOutput = execSync(`git tag -l "${ide}-v*"`).toString().trim();
+ if (tagsOutput.length > 0) {
+ // Get the most recent IDE-specific tag
+ lastTag = execSync(`git describe --tags --abbrev=0 --match "${ide}-v*"`)
+ .toString()
+ .trim();
+ hasPreviousTag = true;
+ } else {
+ // Fall back to any tag
+ const anyTagsOutput = execSync("git tag -l").toString().trim();
+ hasPreviousTag = anyTagsOutput.length > 0;
+ if (hasPreviousTag) {
+ lastTag = execSync("git describe --tags --abbrev=0").toString().trim();
+ }
}
} catch (error) {
console.error("Error checking for tags:", error);
@@ -94,6 +128,26 @@ const createReleaseNotes = (): void => {
return commit;
};
+ // Function to check if a commit is relevant for the current IDE
+ const isRelevantForIDE = (commit: string): boolean => {
+ // Check for IDE-specific prefixes: [vscode], [zed], [jetbrains]
+ const idePrefixMatch = commit.match(/^\[(\w+)\]/);
+
+ if (idePrefixMatch) {
+ // If commit has an IDE prefix, only include if it matches current IDE
+ const commitIDE = idePrefixMatch[1].toLowerCase();
+ return commitIDE === ide;
+ }
+
+ // Commits without IDE prefix are global (included in all IDEs)
+ return true;
+ };
+
+ // Function to remove IDE prefix from commit message
+ const removeIDEPrefix = (commit: string): string => {
+ return commit.replace(/^\[\w+\]\s*/, "");
+ };
+
// Function to get all commits between two points
const getAllCommits = (): string[] => {
try {
@@ -108,7 +162,8 @@ const createReleaseNotes = (): void => {
return [];
}
- return allCommits.split("\n");
+ // Filter commits relevant for this IDE
+ return allCommits.split("\n").filter(isRelevantForIDE);
} catch (error) {
console.error("Error getting commits:", error);
return [];
@@ -133,10 +188,15 @@ const createReleaseNotes = (): void => {
return false;
}
+ // Remove IDE prefix for pattern matching
+ const commitWithoutIDEPrefix = removeIDEPrefix(commit);
+
// Check if commit matches any of the patterns
const matches = patternPrefixes.some((prefix) => {
const cleanPrefix = prefix.trim();
- return commit.toLowerCase().startsWith(cleanPrefix.toLowerCase());
+ return commitWithoutIDEPrefix
+ .toLowerCase()
+ .startsWith(cleanPrefix.toLowerCase());
});
// If it matches, mark it as processed
@@ -149,11 +209,13 @@ const createReleaseNotes = (): void => {
// Format the filtered commits
const processedLines = filteredCommits.map((line) => {
+ // Remove IDE prefix first
+ let cleanedLine = removeIDEPrefix(line);
+
// Process the line to extract issue numbers and format them correctly
- const processedLine = extractIssueNumbers(line);
+ cleanedLine = extractIssueNumbers(cleanedLine);
// Remove the commit type prefix (e.g., "fix: ", "feat: ")
- let cleanedLine = processedLine;
patternPrefixes.forEach((prefix) => {
const prefixRegex = new RegExp(`^${prefix}\\s*:\\s*`, "i");
cleanedLine = cleanedLine.replace(prefixRegex, "");
@@ -180,8 +242,11 @@ const createReleaseNotes = (): void => {
if (features.length > 0) {
content += `### Features and Improvements\n\n${features.join("\n")}\n\n`;
} else {
- content += "### Features and Improvements\n\nNo new features or improvements in this release.\n\n";
- } // Get bug fixes
+ content +=
+ "### Features and Improvements\n\nNo new features or improvements in this release.\n\n";
+ }
+
+ // Get bug fixes
const bugsPattern = "^fix\\|^bug";
const bugfixes = getCommits(bugsPattern);
if (bugfixes.length > 0) {
@@ -204,5 +269,38 @@ const createReleaseNotes = (): void => {
}
};
-// Run the function when the script is executed
-createReleaseNotes();
+// Main function
+function main(): void {
+ const args = process.argv.slice(2);
+
+ if (args.length !== 1) {
+ console.error("Usage: npm run create:release-notes ");
+ console.error(" ide: vscode | zed | jetbrains");
+ console.error("");
+ console.error("Examples:");
+ console.error(" npm run create:release-notes vscode");
+ console.error(" npm run create:release-notes zed");
+ console.error(" npm run create:release-notes jetbrains");
+ console.error("");
+ console.error("Commit prefix convention:");
+ console.error(" [vscode] feat: VS Code specific feature");
+ console.error(" [zed] fix: Zed specific fix");
+ console.error(" [jetbrains] add: JetBrains specific addition");
+ console.error(" feat: Global feature (included in all IDEs)");
+ process.exit(1);
+ }
+
+ const ide = args[0] as IDE;
+
+ // Validate arguments
+ if (!["jetbrains", "vscode", "zed"].includes(ide)) {
+ console.error(`Invalid IDE: ${ide}`);
+ console.error(" Must be: vscode | zed | jetbrains");
+ process.exit(1);
+ }
+
+ createReleaseNotes(ide);
+}
+
+// Run the script
+main();
diff --git a/src/generators/jetbrains/README.md b/src/generators/jetbrains/README.md
new file mode 100644
index 00000000..5f4c0835
--- /dev/null
+++ b/src/generators/jetbrains/README.md
@@ -0,0 +1,190 @@
+# JetBrains Theme Generator
+
+This directory contains the theme generator for JetBrains IDEs (WebStorm, IntelliJ IDEA, PyCharm, PhpStorm, Rider, GoLand, etc.).
+
+## Structure
+
+```
+jetbrains/
+├── index.ts # Main build script
+├── types.ts # TypeScript type definitions for JetBrains themes
+├── ui.ts # UI color mappings
+├── theme.ts # Theme JSON builder
+├── editor-scheme.ts # Editor color scheme XML generator
+├── plugin.ts # Plugin manifest (plugin.xml) generator
+├── utils.ts # Color utility functions
+└── README.md # This file
+```
+
+## Generated Output
+
+The build process generates a complete Gradle-based plugin structure:
+
+```
+dist/jetbrains/
+├── resources/
+│ └── META-INF/
+│ └── plugin.xml # Plugin manifest
+├── themes/
+│ ├── bearded-theme-*.theme.json # UI theme files
+│ └── bearded-theme-*.xml # Editor color schemes
+├── build.gradle.kts # Gradle build configuration
+├── settings.gradle.kts # Gradle settings
+├── gradle.properties # Gradle properties
+└── README.md # Installation instructions
+```
+
+## Building Themes
+
+### Generate Theme Files Only
+
+```bash
+npm run build:jetbrains
+```
+
+This generates all theme files in `dist/jetbrains/` but does not build the plugin package.
+
+### Build Plugin Package (ZIP)
+
+```bash
+npm run build:ext:jetbrains
+```
+
+This generates the theme files AND builds the plugin ZIP file. Requires:
+- Java 11 or higher installed
+- Internet connection (for Gradle to download dependencies)
+
+The plugin ZIP will be created in `dist/jetbrains/build/distributions/`.
+
+### Full Build (All Platforms)
+
+```bash
+npm run build
+```
+
+This builds VS Code, Zed, and JetBrains themes, plus the JetBrains plugin package.
+
+## Installation
+
+### Method 1: Install from Disk (Development)
+
+1. Build the plugin: `npm run build:ext:jetbrains`
+2. Open your JetBrains IDE
+3. Go to **Settings/Preferences** → **Plugins**
+4. Click the gear icon ⚙️ → **Install Plugin from Disk...**
+5. Select the ZIP file from `dist/jetbrains/build/distributions/`
+6. Restart the IDE
+
+### Method 2: Quick Install (Local Themes Only)
+
+```bash
+npm run install:jetbrains:local
+```
+
+This copies the theme files directly to your IDE's config directory for quick testing.
+
+### Method 3: Development Workflow
+
+```bash
+npm run dev:jetbrains:install
+```
+
+This builds and installs the themes in one command, useful during development.
+
+## Theme Structure
+
+### theme.json
+
+Each theme has a `.theme.json` file that defines:
+- Theme metadata (name, author, dark/light)
+- Parent theme (Islands Dark/Light for modern UI)
+- Named colors for reuse
+- UI component colors
+
+```json
+{
+ "name": "Bearded Theme Arc",
+ "dark": true,
+ "author": "BeardedBear",
+ "parentTheme": "Islands Dark",
+ "editorScheme": "/themes/bearded-theme-arc.xml",
+ "colors": {
+ "primary": "#8196b5",
+ "background": "#1c2433"
+ },
+ "ui": {
+ "*": {
+ "background": "#1c2433",
+ "foreground": "#c3cfd9"
+ },
+ "Button.default.startBackground": "#8196b5"
+ }
+}
+```
+
+### Editor Scheme (XML)
+
+Each theme also has an `.xml` file for syntax highlighting:
+- Color definitions for editor elements
+- Syntax highlighting attributes
+- Console colors
+- Diff/VCS colors
+
+## Adding New UI Keys
+
+JetBrains IDEs support hundreds of UI component keys. To add new ones:
+
+1. Find the key name using the **UI Inspector** in the IDE:
+ - Help → Diagnostic Tools → UI Inspector
+ - Click on any UI element to see its properties
+
+2. Add the key to `types.ts` in the `JetBrainsUiColors` interface
+
+3. Add the color mapping in `ui.ts`
+
+## Islands Theme Support
+
+The generator uses JetBrains' new Islands theme style by default:
+- Sets `parentTheme` to "Islands Dark" or "Islands Light"
+- Uses rounded corners and modern styling
+- Hides sidebar borders for cleaner appearance
+
+Reference: https://plugins.jetbrains.com/docs/intellij/supporting-islands-theme.html
+
+## Testing
+
+1. Build the themes: `npm run build:jetbrains`
+2. Install in IDE (see Installation above)
+3. Restart the IDE
+4. Go to **Settings** → **Appearance & Behavior** → **Appearance**
+5. Select a Bearded Theme from the Theme dropdown
+6. Verify:
+ - UI colors are correct
+ - Syntax highlighting works
+ - No console errors
+
+## Troubleshooting
+
+### "Could not resolve all files for configuration"
+
+Make sure you have Java 11+ installed and `JAVA_HOME` is set correctly.
+
+### Theme not appearing in IDE
+
+- Verify the plugin is installed (Settings → Plugins → Installed)
+- Check the IDE's log for errors (Help → Show Log in...)
+- Ensure the theme JSON is valid
+
+### Colors look wrong
+
+- Check that the hex colors don't have `#` prefix in wrong places
+- Verify alpha values are in correct format (RRGGBBAA)
+- Some keys may be overridden by other settings
+
+## Resources
+
+- [Developing Themes](https://plugins.jetbrains.com/docs/intellij/developing-themes.html)
+- [Customizing Themes](https://plugins.jetbrains.com/docs/intellij/themes-customize.html)
+- [Theme Extras (Editor Schemes)](https://plugins.jetbrains.com/docs/intellij/themes-extras.html)
+- [Islands Theme](https://plugins.jetbrains.com/docs/intellij/supporting-islands-theme.html)
+- [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template)
diff --git a/src/generators/jetbrains/editor-scheme.ts b/src/generators/jetbrains/editor-scheme.ts
new file mode 100644
index 00000000..66a9b0dc
--- /dev/null
+++ b/src/generators/jetbrains/editor-scheme.ts
@@ -0,0 +1,620 @@
+/**
+ * JetBrains Editor Color Scheme Generator
+ *
+ * Generates .xml editor color scheme files for JetBrains IDEs.
+ * These files define syntax highlighting colors for the editor.
+ *
+ * References:
+ * - https://plugins.jetbrains.com/docs/intellij/themes-extras.html
+ * - Editor color scheme XML format from IntelliJ Platform
+ */
+
+import { colord as c } from "colord";
+
+import { ThemeRegistryEntry } from "../../shared/theme-registry";
+import { Theme } from "../../shared/types";
+import { toHex } from "./utils";
+
+/**
+ * Build an editor color scheme XML string
+ *
+ * @param entry - Theme registry entry
+ * @returns XML string for the editor color scheme
+ */
+export function buildEditorScheme(entry: ThemeRegistryEntry): string {
+ const { name, options, theme } = entry;
+ const isDark = !options.light;
+ const schemeName = escapeXmlAttribute(`Bearded Theme ${name}`);
+ const parentScheme = isDark ? "Darcula" : "Default";
+
+ const xml = `
+
+
+ Bearded Theme Generator
+ JetBrains IDE
+ 2024.1
+ ${schemeName}
+
+
+${buildColorOptions(theme, options.light, options.hc)}
+
+
+${buildAttributeOptions(theme, options.light, options.hc)}
+
+`;
+
+ return xml;
+}
+
+/**
+ * Build attribute options for syntax highlighting
+ *
+ * @param theme - Theme object
+ * @param isLight - Whether this is a light theme
+ * @param isHc - Whether this is a high contrast theme
+ * @returns XML string of attribute options
+ */
+function buildAttributeOptions(
+ theme: Theme,
+ isLight?: boolean,
+ isHc?: boolean,
+): string {
+ const { colors, ui } = theme;
+
+ // Helper to mix color with background to simulate transparency
+ // JetBrains attributes don't support alpha, so we pre-mix
+ const mixWithBg = (color: string, alpha: number): string => {
+ return c(color).mix(ui.uibackground, 1 - alpha).toHex();
+ };
+
+ // Helper to create an attribute option
+ const attr = (
+ name: string,
+ opts: {
+ background?: string;
+ effectColor?: string;
+ effectType?: number;
+ fontType?: number;
+ foreground?: string;
+ },
+ ): string => {
+ const parts: string[] = [];
+
+ if (opts.foreground) {
+ parts.push(``);
+ }
+ if (opts.background) {
+ parts.push(``);
+ }
+ if (opts.fontType !== undefined) {
+ parts.push(``);
+ }
+ if (opts.effectColor) {
+ parts.push(``);
+ }
+ if (opts.effectType !== undefined) {
+ parts.push(``);
+ }
+
+ if (parts.length === 0) {
+ return ` `;
+ }
+
+ return ` `;
+ };
+
+ // Font types: 0=plain, 1=bold, 2=italic, 3=bold+italic
+ // Effect types: 0=bordered, 1=line underscore, 2=wave underscore,
+ // 3=strikeout, 4=bold line underscore, 5=dotted line
+
+ const attributes: string[] = [
+ // Default text - background is critical for editor background color
+ attr("TEXT", { background: ui.uibackground, foreground: ui.default }),
+
+ // Comments
+ attr("DEFAULT_BLOCK_COMMENT", { fontType: 2, foreground: ui.defaultalt }),
+ attr("DEFAULT_DOC_COMMENT", { fontType: 2, foreground: ui.defaultalt }),
+ attr("DEFAULT_DOC_COMMENT_TAG", {
+ fontType: 3,
+ foreground: ui.defaultalt,
+ }),
+ attr("DEFAULT_DOC_COMMENT_TAG_VALUE", {
+ fontType: 2,
+ foreground: colors.salmon,
+ }),
+ attr("DEFAULT_DOC_MARKUP", { foreground: ui.defaultalt }),
+ attr("DEFAULT_LINE_COMMENT", { fontType: 2, foreground: ui.defaultalt }),
+
+ // Keywords
+ attr("DEFAULT_KEYWORD", { foreground: colors.yellow }),
+
+ // Identifiers
+ attr("DEFAULT_IDENTIFIER", { foreground: ui.default }),
+
+ // Strings
+ attr("DEFAULT_STRING", { foreground: colors.green }),
+ attr("DEFAULT_VALID_STRING_ESCAPE", { foreground: colors.orange }),
+ attr("DEFAULT_INVALID_STRING_ESCAPE", {
+ effectColor: colors.red,
+ effectType: 2,
+ foreground: colors.red,
+ }),
+
+ // Numbers
+ attr("DEFAULT_NUMBER", { foreground: colors.red }),
+
+ // Operators and punctuation
+ attr("DEFAULT_OPERATION_SIGN", { foreground: colors.yellow }),
+ attr("DEFAULT_PARENTHS", {
+ foreground: isHc ? ui.default : c(ui.default).alpha(0.6).toHex(),
+ }),
+ attr("DEFAULT_BRACKETS", {
+ foreground: isHc ? ui.default : c(ui.default).alpha(0.6).toHex(),
+ }),
+ attr("DEFAULT_BRACES", {
+ foreground: isHc ? ui.default : c(ui.default).alpha(0.6).toHex(),
+ }),
+ attr("DEFAULT_COMMA", {
+ foreground: isHc ? ui.default : c(ui.default).alpha(0.6).toHex(),
+ }),
+ attr("DEFAULT_DOT", {
+ foreground: isHc ? ui.default : c(ui.default).alpha(0.6).toHex(),
+ }),
+ attr("DEFAULT_SEMICOLON", {
+ foreground: isHc ? ui.default : c(ui.default).alpha(0.6).toHex(),
+ }),
+
+ // Constants
+ attr("DEFAULT_CONSTANT", { foreground: colors.red }),
+
+ // Classes and Types
+ attr("DEFAULT_CLASS_NAME", { foreground: colors.greenAlt }),
+ attr("DEFAULT_CLASS_REFERENCE", { foreground: colors.greenAlt }),
+ attr("DEFAULT_INTERFACE_NAME", { foreground: colors.greenAlt }),
+
+ // Functions and Methods
+ attr("DEFAULT_FUNCTION_CALL", { foreground: colors.blue }),
+ attr("DEFAULT_FUNCTION_DECLARATION", { foreground: colors.blue }),
+ attr("DEFAULT_INSTANCE_METHOD", { foreground: colors.blue }),
+ attr("DEFAULT_STATIC_METHOD", { fontType: 2, foreground: colors.blue }),
+
+ // Fields and Properties
+ attr("DEFAULT_INSTANCE_FIELD", { foreground: ui.default }),
+ attr("DEFAULT_STATIC_FIELD", { fontType: 2, foreground: ui.default }),
+
+ // Parameters
+ attr("DEFAULT_PARAMETER", { foreground: colors.pink }),
+
+ // Local variables
+ attr("DEFAULT_LOCAL_VARIABLE", { foreground: colors.salmon }),
+ attr("DEFAULT_REASSIGNED_LOCAL_VARIABLE", {
+ effectColor: colors.salmon,
+ effectType: 1,
+ foreground: colors.salmon,
+ }),
+ attr("DEFAULT_REASSIGNED_PARAMETER", {
+ effectColor: colors.pink,
+ effectType: 1,
+ foreground: colors.pink,
+ }),
+
+ // Metadata / Annotations / Decorators
+ attr("DEFAULT_METADATA", { foreground: colors.pink }),
+
+ // Labels
+ attr("DEFAULT_LABEL", { foreground: colors.yellow }),
+
+ // Predefined symbols
+ attr("DEFAULT_PREDEFINED_SYMBOL", { foreground: colors.turquoize }),
+
+ // Template language
+ attr("DEFAULT_TEMPLATE_LANGUAGE_COLOR", {
+ background: c(ui.uibackground).lighten(0.02).toHex(),
+ }),
+
+ // Markup languages
+ attr("DEFAULT_TAG", { foreground: colors.blue }),
+ attr("DEFAULT_ATTRIBUTE", { foreground: colors.yellow }),
+ attr("DEFAULT_ENTITY", { foreground: colors.orange }),
+
+ // HTML specific
+ attr("HTML_TAG", {
+ foreground: isHc ? colors.blue : mixWithBg(colors.blue, 0.7),
+ }),
+ attr("HTML_TAG_NAME", { foreground: colors.blue }),
+ attr("HTML_ATTRIBUTE_NAME", { foreground: colors.yellow }),
+ attr("HTML_ATTRIBUTE_VALUE", { foreground: colors.green }),
+ attr("HTML_ENTITY_REFERENCE", { foreground: colors.orange }),
+ attr("HTML_CUSTOM_TAG_NAME", { foreground: colors.greenAlt }),
+
+ // XML specific
+ attr("XML_TAG", {
+ foreground: isHc ? colors.blue : mixWithBg(colors.blue, 0.7),
+ }),
+ attr("XML_TAG_NAME", { foreground: colors.blue }),
+ attr("XML_ATTRIBUTE_NAME", { foreground: colors.yellow }),
+ attr("XML_ATTRIBUTE_VALUE", { foreground: colors.green }),
+ attr("XML_ENTITY_REFERENCE", { foreground: colors.orange }),
+
+ // Vue.js specific
+ attr("VUE_TAG", {
+ foreground: isHc ? colors.blue : mixWithBg(colors.blue, 0.7),
+ }),
+ attr("VUE_TAG_NAME", { foreground: colors.blue }),
+ attr("VUE_CUSTOM_TAG_NAME", { foreground: colors.greenAlt }),
+ attr("VUE_ATTRIBUTE_NAME", { foreground: colors.yellow }),
+ attr("VUE_ATTRIBUTE_VALUE", { foreground: colors.green }),
+ attr("VUE_DIRECTIVE", { foreground: colors.purple }),
+ attr("VUE_DIRECTIVE_ARGUMENT", { foreground: colors.pink }),
+ attr("VUE_DIRECTIVE_SHORTHAND_ARGUMENT", { foreground: colors.pink }),
+ attr("VUE_INTERPOLATION_DELIMITERS", { foreground: colors.yellow }),
+ attr("VUE_EXPRESSION", { foreground: ui.default }),
+ attr("XML_TAG_DATA", { foreground: ui.default }),
+ attr("XML_PROLOGUE", { foreground: ui.defaultalt }),
+ attr("XML_NS_PREFIX", { foreground: colors.turquoize }),
+
+ // CSS specific
+ attr("CSS.COLOR", { foreground: colors.orange }),
+ attr("CSS.FUNCTION", { foreground: colors.blue }),
+ attr("CSS.IDENT", { foreground: ui.default }),
+ attr("CSS.IMPORTANT", { fontType: 1, foreground: colors.red }),
+ attr("CSS.KEYWORD", { foreground: colors.yellow }),
+ attr("CSS.NUMBER", { foreground: colors.red }),
+ attr("CSS.PROPERTY_NAME", { foreground: colors.turquoize }),
+ attr("CSS.PROPERTY_VALUE", { foreground: ui.default }),
+ attr("CSS.PSEUDO", { foreground: colors.pink }),
+ attr("CSS.STRING", { foreground: colors.green }),
+ attr("CSS.TAG_NAME", { foreground: colors.blue }),
+ attr("CSS.URL", { foreground: colors.green }),
+
+ // SCSS/SASS specific
+ attr("SCSS_VARIABLE", { foreground: colors.salmon }),
+ attr("SASS_MIXIN", { foreground: colors.purple }),
+
+ // JavaScript/TypeScript specific
+ attr("JS.GLOBAL_FUNCTION", { foreground: colors.blue }),
+ attr("JS.GLOBAL_VARIABLE", { foreground: colors.salmon }),
+ attr("JS.INSTANCE_MEMBER_FUNCTION", { foreground: colors.blue }),
+ attr("JS.LOCAL_VARIABLE", { foreground: colors.salmon }),
+ attr("JS.PARAMETER", { foreground: colors.pink }),
+ attr("JS.REGEXP", { foreground: colors.orange }),
+
+ attr("TS.MODULE_NAME", { foreground: colors.greenAlt }),
+ attr("TS.TYPE_PARAMETER", { foreground: colors.purple }),
+
+ // JSON specific
+ attr("JSON.KEYWORD", { foreground: colors.turquoize }),
+ attr("JSON.PROPERTY_KEY", { foreground: colors.salmon }),
+ attr("JSON.STRING", { foreground: colors.green }),
+
+ // YAML specific
+ attr("YAML_ANCHOR", { foreground: colors.purple }),
+ attr("YAML_SCALAR_KEY", { foreground: colors.turquoize }),
+ attr("YAML_SCALAR_VALUE", { foreground: ui.default }),
+ attr("YAML_SIGN", {
+ foreground: isHc ? ui.default : c(ui.default).alpha(0.6).toHex(),
+ }),
+
+ // Markdown specific
+ attr("MARKDOWN_BOLD", { fontType: 1, foreground: colors.salmon }),
+ attr("MARKDOWN_CODE_SPAN", { foreground: colors.purple }),
+ attr("MARKDOWN_HEADER", { fontType: 1, foreground: colors.yellow }),
+ attr("MARKDOWN_HEADER_LEVEL_1", { fontType: 1, foreground: colors.yellow }),
+ attr("MARKDOWN_HEADER_LEVEL_2", { fontType: 1, foreground: colors.yellow }),
+ attr("MARKDOWN_HEADER_LEVEL_3", { fontType: 1, foreground: colors.yellow }),
+ attr("MARKDOWN_HEADER_LEVEL_4", { fontType: 1, foreground: colors.yellow }),
+ attr("MARKDOWN_HEADER_LEVEL_5", { fontType: 1, foreground: colors.yellow }),
+ attr("MARKDOWN_HEADER_LEVEL_6", { fontType: 1, foreground: colors.yellow }),
+ attr("MARKDOWN_ITALIC", { fontType: 2, foreground: colors.orange }),
+ attr("MARKDOWN_LINK_DESTINATION", { foreground: colors.blue }),
+ attr("MARKDOWN_LINK_TEXT", { foreground: colors.green }),
+
+ // Python specific
+ attr("PY.BUILTIN_NAME", { foreground: colors.turquoize }),
+ attr("PY.DECORATOR", { foreground: colors.pink }),
+ attr("PY.FUNC_DEFINITION", { foreground: colors.blue }),
+ attr("PY.KEYWORD_ARGUMENT", { foreground: colors.pink }),
+ attr("PY.PREDEFINED_DEFINITION", { foreground: colors.turquoize }),
+ attr("PY.PREDEFINED_USAGE", { foreground: colors.turquoize }),
+ attr("PY.SELF_PARAMETER", { fontType: 2, foreground: colors.red }),
+ attr("PY.STRING.B", { foreground: colors.green }),
+ attr("PY.STRING.U", { foreground: colors.green }),
+
+ // Rust specific
+ attr("RUST_ATTRIBUTE", { foreground: colors.pink }),
+ attr("RUST_LIFETIME", { foreground: colors.purple }),
+ attr("RUST_MACRO", { foreground: colors.turquoize }),
+
+ // Go specific
+ attr("GO_BUILTIN_CONSTANT", { foreground: colors.red }),
+ attr("GO_BUILTIN_FUNCTION_CALL", { foreground: colors.turquoize }),
+ attr("GO_BUILTIN_TYPE_REFERENCE", { foreground: colors.purple }),
+ attr("GO_BUILTIN_VARIABLE", { foreground: colors.red }),
+ attr("GO_EXPORTED_FUNCTION", { foreground: colors.blue }),
+ attr("GO_PACKAGE", { foreground: colors.greenAlt }),
+ attr("GO_STRUCT_EXPORTED_MEMBER", { foreground: ui.default }),
+ attr("GO_TYPE_REFERENCE", { foreground: colors.greenAlt }),
+
+ // Kotlin specific
+ attr("KOTLIN_LABEL", { foreground: colors.yellow }),
+ attr("KOTLIN_MUTABLE_VARIABLE", {
+ effectColor: colors.salmon,
+ effectType: 1,
+ foreground: colors.salmon,
+ }),
+ attr("KOTLIN_NAMED_ARGUMENT", { foreground: colors.pink }),
+ attr("KOTLIN_PACKAGE_FUNCTION_CALL", { foreground: colors.blue }),
+
+ // Java specific
+ attr("ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES", { foreground: colors.pink }),
+ attr("ANNOTATION_NAME_ATTRIBUTES", { foreground: colors.pink }),
+ attr("ENUM_CONST", { foreground: colors.red }),
+ attr("IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES", {
+ foreground: colors.pink,
+ }),
+ attr("STATIC_FINAL_FIELD_ATTRIBUTES", { fontType: 2, foreground: colors.red }),
+ attr("TYPE_PARAMETER_NAME_ATTRIBUTES", { foreground: colors.purple }),
+
+ // SQL specific
+ attr("SQL_DATABASE_OBJECT", { foreground: colors.greenAlt }),
+ attr("SQL_KEYWORD", { foreground: colors.yellow }),
+ attr("SQL_PROCEDURE", { foreground: colors.blue }),
+ attr("SQL_STRING", { foreground: colors.green }),
+ attr("SQL_TABLE", { foreground: colors.greenAlt }),
+ attr("SQL_COLUMN", { foreground: colors.salmon }),
+
+ // Shell specific
+ attr("BASH.EXTERNAL_COMMAND", { foreground: colors.blue }),
+ attr("BASH.FUNCTION_DEF_NAME", { foreground: colors.blue }),
+ attr("BASH.SHEBANG", { fontType: 2, foreground: ui.defaultalt }),
+ attr("BASH.VAR_DEF", { foreground: colors.salmon }),
+ attr("BASH.VAR_USE", { foreground: colors.salmon }),
+
+ // Error and warning markers
+ attr("BAD_CHARACTER", { effectColor: colors.red, effectType: 2 }),
+ attr("DEPRECATED_ATTRIBUTES", { effectColor: ui.defaultalt, effectType: 3 }),
+ attr("ERRORS_ATTRIBUTES", {
+ effectColor: colors.red,
+ effectType: 2,
+ }),
+ attr("INFO_ATTRIBUTES", {
+ effectColor: colors.blue,
+ effectType: 1,
+ }),
+ attr("MARKED_FOR_REMOVAL_ATTRIBUTES", {
+ effectColor: colors.red,
+ effectType: 3,
+ }),
+ attr("NOT_USED_ELEMENT_ATTRIBUTES", { foreground: ui.defaultalt }),
+ attr("RUNTIME_ERROR", { effectColor: colors.red, effectType: 2 }),
+ attr("TYPO", { effectColor: colors.green, effectType: 2 }),
+ attr("WARNING_ATTRIBUTES", { effectColor: colors.orange, effectType: 2 }),
+ attr("WEAK_WARNING_ATTRIBUTES", {
+ effectColor: colors.yellow,
+ effectType: 1,
+ }),
+ attr("WRONG_REFERENCES_ATTRIBUTES", {
+ effectColor: colors.red,
+ effectType: 2,
+ foreground: colors.red,
+ }),
+
+ // Injected language
+ attr("INJECTED_LANGUAGE_FRAGMENT", {
+ background: c(ui.uibackground).lighten(0.03).toHex(),
+ }),
+
+ // Todo / Fixme
+ attr("TODO_DEFAULT_ATTRIBUTES", { fontType: 2, foreground: colors.yellow }),
+
+ // Diff and merge
+ attr("DIFF_CONFLICT", {
+ background: c(colors.orange).mix(ui.uibackground, 0.85).toHex(),
+ }),
+ attr("DIFF_DELETED", {
+ background: c(colors.red).mix(ui.uibackground, 0.85).toHex(),
+ }),
+ attr("DIFF_INSERTED", {
+ background: c(colors.green).mix(ui.uibackground, 0.85).toHex(),
+ }),
+ attr("DIFF_MODIFIED", {
+ background: c(colors.blue).mix(ui.uibackground, 0.85).toHex(),
+ }),
+
+ // Inline hints
+ attr("INLINE_PARAMETER_HINT", {
+ background: c(ui.uibackground).lighten(0.08).toHex(),
+ foreground: ui.defaultalt,
+ }),
+ attr("INLINE_PARAMETER_HINT_CURRENT", {
+ background: c(ui.primary).mix(ui.uibackground, 0.8).toHex(),
+ foreground: ui.default,
+ }),
+ attr("INLINE_PARAMETER_HINT_HIGHLIGHTED", {
+ background: c(ui.primary).mix(ui.uibackground, 0.7).toHex(),
+ foreground: ui.default,
+ }),
+
+ // Hyperlinks
+ attr("HYPERLINK_ATTRIBUTES", {
+ effectColor: colors.blue,
+ effectType: 1,
+ foreground: colors.blue,
+ }),
+ attr("FOLLOWED_HYPERLINK_ATTRIBUTES", {
+ effectColor: colors.purple,
+ effectType: 1,
+ foreground: colors.purple,
+ }),
+
+ // Breadcrumbs
+ attr("BREADCRUMBS_CURRENT", { foreground: ui.default }),
+ attr("BREADCRUMBS_DEFAULT", { foreground: ui.defaultalt }),
+ attr("BREADCRUMBS_HOVERED", { foreground: ui.primary }),
+ attr("BREADCRUMBS_INACTIVE", { foreground: ui.defaultalt }),
+
+ // Console colors
+ attr("CONSOLE_BLACK_OUTPUT", { foreground: isLight ? "#000000" : "#1E1E1E" }),
+ attr("CONSOLE_BLUE_BRIGHT_OUTPUT", {
+ foreground: c(colors.blue).lighten(0.1).toHex(),
+ }),
+ attr("CONSOLE_BLUE_OUTPUT", { foreground: colors.blue }),
+ attr("CONSOLE_CYAN_BRIGHT_OUTPUT", {
+ foreground: c(colors.turquoize).lighten(0.1).toHex(),
+ }),
+ attr("CONSOLE_CYAN_OUTPUT", { foreground: colors.turquoize }),
+ attr("CONSOLE_DARKGRAY_OUTPUT", { foreground: ui.defaultalt }),
+ attr("CONSOLE_ERROR_OUTPUT", { foreground: colors.red }),
+ attr("CONSOLE_GRAY_OUTPUT", { foreground: ui.defaultalt }),
+ attr("CONSOLE_GREEN_BRIGHT_OUTPUT", {
+ foreground: c(colors.green).lighten(0.1).toHex(),
+ }),
+ attr("CONSOLE_GREEN_OUTPUT", { foreground: colors.green }),
+ attr("CONSOLE_MAGENTA_BRIGHT_OUTPUT", {
+ foreground: c(colors.pink).lighten(0.1).toHex(),
+ }),
+ attr("CONSOLE_MAGENTA_OUTPUT", { foreground: colors.pink }),
+ attr("CONSOLE_NORMAL_OUTPUT", { foreground: ui.default }),
+ attr("CONSOLE_RED_BRIGHT_OUTPUT", {
+ foreground: c(colors.red).lighten(0.1).toHex(),
+ }),
+ attr("CONSOLE_RED_OUTPUT", { foreground: colors.red }),
+ attr("CONSOLE_SYSTEM_OUTPUT", { foreground: ui.defaultalt }),
+ attr("CONSOLE_USER_INPUT", { foreground: colors.green }),
+ attr("CONSOLE_WHITE_OUTPUT", { foreground: ui.default }),
+ attr("CONSOLE_YELLOW_BRIGHT_OUTPUT", {
+ foreground: c(colors.yellow).lighten(0.1).toHex(),
+ }),
+ attr("CONSOLE_YELLOW_OUTPUT", { foreground: colors.yellow }),
+
+ // Log console
+ attr("LOG_DEBUG_OUTPUT", { foreground: ui.defaultalt }),
+ attr("LOG_ERROR_OUTPUT", { foreground: colors.red }),
+ attr("LOG_EXPIRED_ENTRY", { foreground: ui.defaultalt }),
+ attr("LOG_INFO_OUTPUT", { foreground: colors.blue }),
+ attr("LOG_WARNING_OUTPUT", { foreground: colors.orange }),
+
+ // Debugger
+ attr("BREAKPOINT_ATTRIBUTES", {
+ background: c(colors.red).mix(ui.uibackground, 0.7).toHex(),
+ }),
+ attr("EXECUTIONPOINT_ATTRIBUTES", {
+ background: c(colors.yellow).mix(ui.uibackground, 0.7).toHex(),
+ }),
+ ];
+
+ return attributes.join("\n");
+}
+
+/**
+ * Build color options for the scheme
+ *
+ * @param theme - Theme object
+ * @param isLight - Whether this is a light theme
+ * @param isHc - Whether this is a high contrast theme
+ * @returns XML string of color options
+ */
+function buildColorOptions(
+ theme: Theme,
+ isLight?: boolean,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ isHc?: boolean,
+): string {
+ const { colors, levels, ui } = theme;
+
+ // Helper to mix color with background for transparent effect
+ const mixWithBg = (color: string, alpha: number): string => {
+ return toHex(c(color).mix(ui.uibackground, 1 - alpha).toHex());
+ };
+
+ const colorMap: Record = {
+ // VCS / Diff colors
+ ADDED_LINES_COLOR: toHex(colors.green),
+ // Bookmarks
+ Bookmark_mnemonic_assigned: toHex(ui.primary),
+ Bookmark_mnemonic_current: toHex(colors.yellow),
+ Bookmark_mnemonic_not_assigned: toHex(ui.defaultalt),
+ // Editor background and foreground
+ CARET_COLOR: toHex(ui.primary),
+ CARET_ROW_COLOR: mixWithBg(
+ isLight
+ ? c(ui.uibackground).darken(0.05).toHex()
+ : c(ui.uibackground).lighten(0.03).toHex(),
+ 1,
+ ),
+ CONSOLE_BACKGROUND_KEY: toHex(ui.uibackground),
+ DELETED_LINES_COLOR: toHex(levels.danger),
+ DIFF_SEPARATORS_BACKGROUND: toHex(ui.uibackgroundalt),
+ // Error / Warning / Info
+ ERRORS_ATTRIBUTES: toHex(levels.danger),
+ FILESTATUS_ADDED: toHex(colors.green),
+ FILESTATUS_COPIED: toHex(colors.green),
+ FILESTATUS_DELETED: toHex(levels.danger),
+ FILESTATUS_IDEA_FILESTATUS_DELETED_FROM_FILE_SYSTEM: toHex(
+ c(levels.danger).desaturate(0.3).toHex(),
+ ),
+ FILESTATUS_IDEA_FILESTATUS_IGNORED: toHex(ui.defaultalt),
+ FILESTATUS_MERGED: toHex(colors.purple),
+
+ FILESTATUS_MODIFIED: toHex(colors.blue),
+ FILESTATUS_NOT_CHANGED_IMMEDIATE: toHex(colors.blue),
+ FILESTATUS_NOT_CHANGED_RECURSIVE: toHex(colors.blue),
+ FILESTATUS_SWITCHED: toHex(colors.purple),
+ FILESTATUS_UNKNOWN: toHex(colors.orange),
+ GUTTER_BACKGROUND: toHex(ui.uibackground),
+ // Search
+ IDENTIFIER_UNDER_CARET_ATTRIBUTES: mixWithBg(ui.primary, 0.2),
+ INDENT_GUIDE: mixWithBg(ui.default, 0.1),
+ INFO_ATTRIBUTES: toHex(levels.info),
+ LINE_NUMBER_ON_CARET_ROW_COLOR: mixWithBg(ui.default, 0.6),
+ LINE_NUMBERS_COLOR: mixWithBg(ui.default, 0.3),
+ METHOD_SEPARATORS_COLOR: toHex(ui.border),
+ MODIFIED_LINES_COLOR: toHex(colors.blue),
+ RIGHT_MARGIN_COLOR: toHex(ui.border),
+ "ScrollBar.Mac.hoverThumbBorderColor": mixWithBg(ui.default, 0.25),
+
+ "ScrollBar.Mac.hoverThumbColor": mixWithBg(ui.default, 0.25),
+ "ScrollBar.Mac.thumbBorderColor": mixWithBg(ui.default, 0.15),
+ // ScrollBar (editor specific)
+ "ScrollBar.Mac.thumbColor": mixWithBg(ui.default, 0.15),
+
+ SEARCH_RESULT_ATTRIBUTES: mixWithBg(colors.yellow, 0.3),
+ SELECTED_INDENT_GUIDE: mixWithBg(ui.default, 0.2),
+ SELECTION_BACKGROUND: mixWithBg(ui.primary, 0.25),
+ SELECTION_FOREGROUND: "",
+ SOFT_WRAP_SIGN_COLOR: toHex(ui.defaultalt),
+
+ TEARLINE_COLOR: toHex(ui.border),
+ TEXT_SEARCH_RESULT_ATTRIBUTES: mixWithBg(colors.yellow, 0.3),
+ VISUAL_INDENT_GUIDE: mixWithBg(ui.default, 0.1),
+
+ WARNING_ATTRIBUTES: toHex(levels.warning),
+ WHITESPACES: mixWithBg(ui.default, 0.15),
+ WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES: mixWithBg(ui.primary, 0.3),
+ WRITE_SEARCH_RESULT_ATTRIBUTES: mixWithBg(colors.yellow, 0.4),
+ };
+
+ return Object.entries(colorMap)
+ .filter(([, value]) => value !== "")
+ .map(([name, value]) => ` `)
+ .join("\n");
+}
+
+/**
+ * Escape special XML characters for use in attributes
+ *
+ * @param str - String to escape
+ * @returns XML-safe string
+ */
+function escapeXmlAttribute(str: string): string {
+ return str
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+}
diff --git a/src/generators/jetbrains/index.ts b/src/generators/jetbrains/index.ts
new file mode 100644
index 00000000..ddfc3c25
--- /dev/null
+++ b/src/generators/jetbrains/index.ts
@@ -0,0 +1,598 @@
+/**
+ * JetBrains Theme Generator
+ *
+ * Main build script for generating JetBrains IDE themes.
+ * Generates a complete plugin structure that can be built with Gradle.
+ *
+ * Output structure:
+ * dist/jetbrains/
+ * ⌂ resources/
+ * ⌂ ⌂ META-INF/
+ * ⌂ ⌂ ⌂ plugin.xml
+ * ⌂ themes/
+ * ⌂ ⌂ bearded-theme-{slug}.theme.json
+ * ⌂ ⌂ bearded-theme-{slug}.xml (editor schemes)
+ * ⌂ build.gradle.kts
+ * ⌂ settings.gradle.kts
+ * ⌂ gradle.properties
+ * ⌂ README.md
+ */
+
+import { chmodSync, mkdirSync, writeFileSync } from "fs";
+import { join } from "path";
+
+import { Meta } from "../../shared/meta";
+import { themeRegistry, ThemeRegistryEntry } from "../../shared/theme-registry";
+import { getJetBrainsVersion } from "../../version-manager";
+import { buildEditorScheme } from "./editor-scheme";
+import { generatePluginXml } from "./plugin";
+import { buildJetBrainsTheme } from "./theme";
+
+// Output directories
+const OUTPUT_DIR = "dist/jetbrains";
+const THEMES_DIR = join(OUTPUT_DIR, "themes");
+const RESOURCES_DIR = join(OUTPUT_DIR, "resources");
+const META_INF_DIR = join(RESOURCES_DIR, "META-INF");
+
+/**
+ * Main build function for JetBrains themes
+ */
+async function buildJetBrainsThemes(): Promise {
+ console.log("🎨 Building JetBrains themes...");
+
+ // Get version from versions.json
+ const version = getJetBrainsVersion();
+ console.log(`Using JetBrains version: ${version}`);
+
+ // Ensure output directories exist
+ mkdirSync(THEMES_DIR, { recursive: true });
+ mkdirSync(META_INF_DIR, { recursive: true });
+
+ // Generate all theme files
+ for (const entry of themeRegistry) {
+ await generateThemeFiles(entry);
+ }
+
+ // Generate plugin.xml
+ const pluginXml = generatePluginXml(themeRegistry, version);
+ writeFileSync(join(META_INF_DIR, "plugin.xml"), pluginXml, {
+ encoding: "utf8",
+ });
+
+ // Generate Gradle build files and wrapper
+ generateGradleFiles(version);
+ generateGradleWrapper();
+
+ // Generate README
+ generateReadme();
+
+ console.log(
+ `Generated ${themeRegistry.length} JetBrains themes in ${OUTPUT_DIR}`,
+ );
+ console.log(`Generated plugin.xml (version ${version})`);
+ console.log("✅ Generated Gradle build files");
+ console.log("✅ Generated README.md");
+ console.log(`
+ JetBrains plugin ready in: ${OUTPUT_DIR}/
+`);
+ console.log("\n To build the plugin:");
+ console.log(" cd dist/jetbrains");
+ console.log(" ./gradlew buildPlugin");
+ console.log("\n The plugin ZIP will be in build/distributions/");
+}
+
+/**
+ * Generate Gradle build files for the plugin
+ *
+ * @param version - Plugin version
+ */
+function generateGradleFiles(version: string): void {
+ // build.gradle.kts
+ const buildGradle = `plugins {
+ id("org.jetbrains.intellij.platform") version "2.10.5"
+}
+
+group = "com.beardedtheme"
+version = "${version}"
+
+repositories {
+ mavenCentral()
+ intellijPlatform {
+ defaultRepositories()
+ }
+}
+
+// Configure source sets to use our directory structure
+sourceSets {
+ main {
+ resources {
+ srcDirs("resources", "themes")
+ }
+ }
+}
+
+dependencies {
+ intellijPlatform {
+ // Target IntelliJ IDEA Community as our base IDE (works with all JetBrains IDEs)
+ // Using a stable version that has available dependencies
+ create("IC", "2024.2.1")
+
+ // Use bundled plugin verifier
+ pluginVerifier()
+ }
+}
+
+intellijPlatform {
+ pluginConfiguration {
+ name = "${Meta.name}"
+ version = "${version}"
+ description = "${Meta.description} A collection of carefully crafted color themes."
+ changeNotes = "See GitHub releases for changelog."
+
+ ideaVersion {
+ sinceBuild = "242"
+ untilBuild = provider { null }
+ }
+
+ vendor {
+ name = "${Meta.author.name}"
+ email = "${Meta.author.email}"
+ url = "${Meta.urls.github}"
+ }
+ }
+
+ publishing {
+ // Configure for JetBrains Marketplace publishing
+ // token = System.getenv("PUBLISH_TOKEN")
+ }
+
+ // Disable instrumentation since this is a theme-only plugin with no code
+ instrumentCode = false
+}
+
+tasks {
+ buildSearchableOptions {
+ enabled = false
+ }
+
+ processResources {
+ duplicatesStrategy = DuplicatesStrategy.INCLUDE
+ }
+}
+`;
+
+ writeFileSync(join(OUTPUT_DIR, "build.gradle.kts"), buildGradle, {
+ encoding: "utf8",
+ });
+
+ // settings.gradle.kts
+ const settingsGradle = `rootProject.name = "${Meta.slug}"
+
+pluginManagement {
+ repositories {
+ maven("https://oss.sonatype.org/content/repositories/snapshots/")
+ gradlePluginPortal()
+ }
+}
+
+dependencyResolutionManagement {
+ repositories {
+ mavenCentral()
+ }
+}
+`;
+
+ writeFileSync(join(OUTPUT_DIR, "settings.gradle.kts"), settingsGradle, {
+ encoding: "utf8",
+ });
+
+ // gradle.properties
+ const gradleProperties = `# Gradle settings
+org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError
+org.gradle.caching=true
+org.gradle.parallel=true
+
+# Kotlin settings
+kotlin.stdlib.default.dependency=false
+
+# IntelliJ Platform settings
+# See https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
+platformType=IC
+platformVersion=2024.2.1
+`;
+
+ writeFileSync(join(OUTPUT_DIR, "gradle.properties"), gradleProperties, {
+ encoding: "utf8",
+ });
+}
+
+/**
+ * Generate Gradle wrapper files
+ *
+ * Creates the gradlew, gradlew.bat scripts and gradle/wrapper directory
+ * so users don't need Gradle installed to build the plugin.
+ */
+function generateGradleWrapper(): void {
+ const wrapperDir = join(OUTPUT_DIR, "gradle", "wrapper");
+ mkdirSync(wrapperDir, { recursive: true });
+
+ // gradle-wrapper.properties
+ const wrapperProperties = `distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\\://services.gradle.org/distributions/gradle-8.13-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+`;
+
+ writeFileSync(
+ join(wrapperDir, "gradle-wrapper.properties"),
+ wrapperProperties,
+ { encoding: "utf8" },
+ );
+
+ // gradlew (Unix shell script)
+ const gradlewUnix = `#!/bin/sh
+
+#
+# Gradle start up script for POSIX systems
+#
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=\${app_path%"\${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=\${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;; #(
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=\${0##*/}
+APP_HOME=$( cd "\${APP_HOME:-./}" && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; #(
+ /?*) t=\${arg#)}; t=/\${t%%/*} #(
+ [ -e "$t" ] ;; #(
+ *) false ;; #(
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # temporary files, so each has its own turn at the end.
+ shift
+ set -- "$@" "$arg"
+ done
+fi
+
+# Add default JVM options here.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# temporary shell commands that run inside "" and get evaluated
+# within "" by the exec below.
+# * DEFAULT_JVM_OPTS://
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xeli" has created that special file indicating that the initialization is complete
+# that file is a sign for us to skip the code below, which is used for initializing Gradle
+
+exec "$JAVACMD" "$@"
+`;
+
+ writeFileSync(join(OUTPUT_DIR, "gradlew"), gradlewUnix, { encoding: "utf8" });
+
+ // Make gradlew executable on Unix systems
+ try {
+ chmodSync(join(OUTPUT_DIR, "gradlew"), 0o755);
+ } catch {
+ // Ignore chmod errors on Windows
+ }
+
+ // gradlew.bat (Windows batch script)
+ const gradlewBat = `@rem
+@rem Gradle startup script for Windows
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here.
+set DEFAULT_JVM_OPTS "-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+ echo.
+ echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ echo.
+ echo Please set the JAVA_HOME variable in your environment to match the
+ echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+ echo.
+ echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+ echo.
+ echo Please set the JAVA_HOME variable in your environment to match the
+ echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem having the _cmd.exe return code instead.
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
+`;
+
+ writeFileSync(join(OUTPUT_DIR, "gradlew.bat"), gradlewBat, {
+ encoding: "utf8",
+ });
+
+ console.log("✅ Generated Gradle wrapper scripts");
+ console.log(
+ " ⚠️ Note: gradle-wrapper.jar must be downloaded on first build",
+ );
+}
+
+/**
+ * Generate README for the JetBrains plugin
+ */
+function generateReadme(): void {
+ const codeBlock = "```";
+
+ const readmeContent = `# ${Meta.name} for JetBrains IDEs
+
+${Meta.description} A collection of carefully crafted color themes for JetBrains IDEs.
+
+## Installation
+
+### From JetBrains Marketplace (Recommended)
+
+1. Open your JetBrains IDE (WebStorm, IntelliJ IDEA, PyCharm, etc.)
+2. Go to **Settings/Preferences** → **Plugins** → **Marketplace**
+3. Search for "${Meta.name}"
+4. Click **Install**
+5. Restart the IDE
+6. Go to **Settings/Preferences** → **Appearance & Behavior** → **Appearance**
+7. Select your preferred ${Meta.name} from the Theme dropdown
+
+### From ZIP File (Manual Installation)
+
+1. Download the plugin ZIP file from the releases
+2. Open your JetBrains IDE
+3. Go to **Settings/Preferences** → **Plugins**
+4. Click the gear icon ⚙️ and select **Install Plugin from Disk...**
+5. Select the downloaded ZIP file
+6. Restart the IDE
+7. Select your theme in **Settings/Preferences** → **Appearance & Behavior** → **Appearance**
+
+## Building from Source
+
+### Prerequisites
+
+- Java 17 or higher
+- Gradle (wrapper included)
+
+### Build Commands
+
+${codeBlock}bash
+# Build the plugin
+./gradlew buildPlugin
+
+# The plugin ZIP will be in build/distributions/
+
+# Run the plugin in a sandbox IDE for testing
+./gradlew runIde
+
+# Verify plugin compatibility
+./gradlew verifyPlugin
+${codeBlock}
+
+## Available Themes
+
+${themeRegistry.map((entry) => `- ${Meta.name} ${entry.name}`).join(
+ "\n",
+)}
+
+## Theme Categories
+
+${Meta.categories.map((c) => `- **${c.name}** - ${c.description}`).join(
+ "\n",
+)}
+
+## Links
+
+- [VS Code Extension](${Meta.urls.marketplace.vscode})
+- [Zed Extension](${Meta.urls.github})
+- [GitHub Repository](${Meta.urls.github})
+- [Report Issues](${Meta.urls.issues})
+
+## License
+
+${Meta.license}
+
+## Author
+
+Made with ❤️ by [${Meta.author.name}](https://github.com/${Meta.author.name})
+`;
+
+ writeFileSync(join(OUTPUT_DIR, "README.md"), readmeContent, {
+ encoding: "utf8",
+ });
+}
+
+/**
+ * Generate theme.json and editor scheme XML for a single theme
+ *
+ * @param entry - Theme registry entry
+ */
+async function generateThemeFiles(entry: ThemeRegistryEntry): Promise {
+ const { slug } = entry;
+
+ // Generate theme.json
+ const theme = buildJetBrainsTheme(entry);
+ const themeJson = JSON.stringify(theme, null, 2);
+ writeFileSync(join(THEMES_DIR, `bearded-theme-${slug}.theme.json`), themeJson, {
+ encoding: "utf8",
+ });
+
+ // Generate editor color scheme XML
+ const editorScheme = buildEditorScheme(entry);
+ writeFileSync(join(THEMES_DIR, `bearded-theme-${slug}.xml`), editorScheme, {
+ encoding: "utf8",
+ });
+}
+
+// Run the build
+buildJetBrainsThemes();
+
+export { buildJetBrainsThemes, generateThemeFiles };
diff --git a/src/generators/jetbrains/plugin.ts b/src/generators/jetbrains/plugin.ts
new file mode 100644
index 00000000..6481d30e
--- /dev/null
+++ b/src/generators/jetbrains/plugin.ts
@@ -0,0 +1,132 @@
+/**
+ * JetBrains Plugin Manifest Generator
+ *
+ * Generates the plugin.xml file required for JetBrains IDE plugins.
+ * This file is placed in resources/META-INF/plugin.xml
+ *
+ * References:
+ * - https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html
+ * - https://plugins.jetbrains.com/docs/intellij/developing-themes.html
+ */
+
+import { Meta } from "../../shared/meta";
+import { ThemeRegistryEntry } from "../../shared/theme-registry";
+
+/**
+ * Generate the plugin.xml manifest file content
+ *
+ * @param themes - Array of theme registry entries
+ * @param version - Plugin version
+ * @returns XML string for plugin.xml
+ */
+export function generatePluginXml(
+ themes: ThemeRegistryEntry[],
+ version: string,
+): string {
+ const themeProviders = themes
+ .map((entry) => {
+ const themeId = escapeXml(`${Meta.slug}-${entry.slug}`);
+ // Path is relative to JAR root - no /themes/ prefix needed
+ const themePath = escapeXml(`/${Meta.slug}-${entry.slug}.theme.json`);
+
+ return ` `;
+ })
+ .join("\n");
+
+ const categoriesHtml = Meta.categories
+ .map((c) => `${escapeXml(c.name)} - ${escapeXml(c.description)}`)
+ .join("\n ");
+
+ return `
+
+ com.beardedtheme.jetbrains
+ ${Meta.name}
+ ${version}
+ ${Meta.author.name}
+
+ ${Meta.name}
+ ${Meta.description} A collection of carefully crafted color themes for your IDE.
+
+ Features
+
+ - ${themes.length}+ theme variants including dark, light, and high contrast options
+ - Carefully designed color palettes for reduced eye strain
+ - Consistent syntax highlighting across all supported languages
+ - Support for the new Islands UI theme style
+
+
+ Theme Categories
+
+
+ Links
+
+ ]]>
+
+ See the GitHub Releases for full changelog.
+ ]]>
+
+
+
+ com.intellij.modules.platform
+
+
+${themeProviders}
+
+
+`;
+}
+
+/**
+ * Generate a list of theme entries for the plugin
+ *
+ * @param themes - Array of theme registry entries
+ * @returns Array of theme information objects
+ */
+export function getThemeList(
+ themes: ThemeRegistryEntry[],
+): Array<{
+ dark: boolean;
+ id: string;
+ name: string;
+ path: string;
+}> {
+ return themes.map((entry) => ({
+ dark: !entry.options.light,
+ id: `${Meta.slug}-${entry.slug}`,
+ name: `${Meta.name} ${entry.name}`,
+ path: `/${Meta.slug}-${entry.slug}.theme.json`,
+ }));
+}
+
+/**
+ * Escape special XML characters in a string
+ *
+ * @param str - String to escape
+ * @returns XML-safe string
+ */
+function escapeXml(str: string): string {
+ return str
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+}
diff --git a/src/generators/jetbrains/theme.ts b/src/generators/jetbrains/theme.ts
new file mode 100644
index 00000000..c59ef174
--- /dev/null
+++ b/src/generators/jetbrains/theme.ts
@@ -0,0 +1,107 @@
+/**
+ * JetBrains Theme Builder
+ *
+ * Generates .theme.json files for JetBrains IDEs
+ * Based on official documentation:
+ * - https://plugins.jetbrains.com/docs/intellij/themes-customize.html
+ * - https://plugins.jetbrains.com/docs/intellij/supporting-islands-theme.html
+ */
+
+import { ThemeOptions, ThemeRegistryEntry } from "../../shared/theme-registry";
+import { JetBrainsTheme } from "./types";
+import { buildJetBrainsUiColors } from "./ui";
+
+/**
+ * Build a complete JetBrains theme object
+ *
+ * @param entry - Theme registry entry
+ * @returns JetBrains theme object ready for JSON serialization
+ */
+export function buildJetBrainsTheme(entry: ThemeRegistryEntry): JetBrainsTheme {
+ const { name, options, slug, theme } = entry;
+ const isDark = !options.light;
+
+ // Build the theme object
+ const jetbrainsTheme: JetBrainsTheme = {
+ author: "BeardedBear",
+ // Named colors for reuse in the theme
+ colors: buildNamedColors(entry),
+ dark: isDark,
+
+ // Reference to editor color scheme - path is relative to JAR root
+ editorScheme: `/bearded-theme-${slug}.xml`,
+
+ name: `Bearded Theme ${name}`,
+
+ // Use Islands theme as parent for modern JetBrains UI
+ parentTheme: isDark ? "Islands Dark" : "Islands Light",
+
+ // UI component colors
+ ui: buildJetBrainsUiColors(theme, options),
+ };
+
+ return jetbrainsTheme;
+}
+
+/**
+ * Get the parent theme based on options
+ *
+ * @param options - Theme options
+ * @returns Parent theme name
+ */
+export function getParentTheme(options: ThemeOptions): string {
+ return options.light ? "Islands Light" : "Islands Dark";
+}
+
+/**
+ * Determine if a theme should be marked as dark
+ *
+ * @param options - Theme options
+ * @returns true if dark theme
+ */
+export function isDarkTheme(options: ThemeOptions): boolean {
+ return !options.light;
+}
+
+/**
+ * Build named colors that can be referenced in the UI section
+ * This makes the theme more maintainable
+ *
+ * @param entry - Theme registry entry
+ * @returns Record of named colors
+ */
+function buildNamedColors(entry: ThemeRegistryEntry): Record {
+ const { theme } = entry;
+ const { colors, levels, ui } = theme;
+
+ return {
+ // UI colors
+ background: ui.uibackground,
+ backgroundAlt: ui.uibackgroundalt,
+ backgroundMid: ui.uibackgroundmid,
+ // Syntax colors
+ blue: colors.blue,
+ border: ui.border,
+ // Level colors
+ danger: levels.danger,
+ foreground: ui.default,
+ foregroundAlt: ui.defaultalt,
+ foregroundMain: ui.defaultMain,
+ green: colors.green,
+
+ greenAlt: colors.greenAlt,
+ info: levels.info,
+ orange: colors.orange,
+ pink: colors.pink,
+ primary: ui.primary,
+ primaryAlt: ui.primaryalt,
+ purple: colors.purple,
+ red: colors.red,
+ salmon: colors.salmon,
+
+ success: levels.success,
+ turquoize: colors.turquoize,
+ warning: levels.warning,
+ yellow: colors.yellow,
+ };
+}
diff --git a/src/generators/jetbrains/types.ts b/src/generators/jetbrains/types.ts
new file mode 100644
index 00000000..a81e472f
--- /dev/null
+++ b/src/generators/jetbrains/types.ts
@@ -0,0 +1,875 @@
+/**
+ * JetBrains Theme Type Definitions
+ * These interfaces define the structure of JetBrains theme files
+ *
+ * References:
+ * - https://plugins.jetbrains.com/docs/intellij/themes-customize.html
+ * - https://plugins.jetbrains.com/docs/intellij/supporting-islands-theme.html
+ * - https://plugins.jetbrains.com/docs/intellij/themes-extras.html
+ */
+
+/**
+ * Background image configuration
+ */
+export interface JetBrainsBackgroundConfig {
+ anchor?: "bottom" | "center" | "top";
+ fill?: "plain" | "scale" | "tile";
+ image: string;
+ transparency?: number;
+}
+
+/**
+ * Icon color palette - maps original colors to new colors
+ * Can also use Actions.* and Objects.* keys
+ */
+export interface JetBrainsIconColorPalette {
+ // Standard color overrides (original color -> new color)
+ [key: string]: string;
+}
+
+/**
+ * Icon customization configuration
+ */
+export interface JetBrainsIconConfig {
+ /**
+ * Color palette overrides for icons
+ */
+ ColorPalette?: JetBrainsIconColorPalette;
+}
+
+export interface JetBrainsPluginExtension {
+ dark: boolean;
+ id: string;
+ path: string;
+}
+
+/**
+ * Plugin manifest structure for plugin.xml
+ */
+export interface JetBrainsPluginManifest {
+ changeNotes?: string;
+ depends: string[];
+ description: string;
+ extensions: JetBrainsPluginExtension[];
+ id: string;
+ name: string;
+ vendor: {
+ email: string;
+ name: string;
+ url: string;
+ };
+ version: string;
+}
+
+/**
+ * Main JetBrains theme structure
+ */
+export interface JetBrainsTheme {
+ /**
+ * Author of the theme
+ */
+ author: string;
+
+ /**
+ * Background image configuration (optional)
+ */
+ background?: JetBrainsBackgroundConfig;
+
+ /**
+ * Named colors that can be referenced in UI
+ */
+ colors?: Record;
+
+ /**
+ * Whether this is a dark theme
+ */
+ dark: boolean;
+
+ /**
+ * Path to the editor color scheme XML file (optional)
+ */
+ editorScheme?: string;
+
+ /**
+ * Empty frame background image configuration (optional)
+ */
+ emptyFrameBackground?: JetBrainsBackgroundConfig;
+
+ /**
+ * Icon customization
+ */
+ icons?: JetBrainsIconConfig;
+
+ /**
+ * Display name of the theme
+ */
+ name: string;
+
+ /**
+ * Parent theme to inherit from (for Islands theme support)
+ * Use "Islands Dark" or "Islands Light"
+ */
+ parentTheme?: string;
+
+ /**
+ * UI component colors
+ */
+ ui: JetBrainsUiColors;
+}
+
+/**
+ * UI component colors for JetBrains themes
+ * Keys follow the pattern: Component.property
+ *
+ * This is a partial list - JetBrains supports hundreds of UI keys.
+ * See: https://plugins.jetbrains.com/docs/intellij/themes-customize.html
+ */
+export interface JetBrainsUiColors {
+ // Wildcard defaults
+ "*"?: JetBrainsWildcardColors;
+
+ // Action Button
+ "ActionButton.hoverBackground"?: string;
+ "ActionButton.hoverBorderColor"?: string;
+ "ActionButton.pressedBackground"?: string;
+ "ActionButton.pressedBorderColor"?: string;
+
+ // Banner
+ "Banner.errorBackground"?: string;
+ "Banner.errorBorderColor"?: string;
+ "Banner.infoBackground"?: string;
+ "Banner.infoBorderColor"?: string;
+ "Banner.successBackground"?: string;
+ "Banner.successBorderColor"?: string;
+ "Banner.warningBackground"?: string;
+ "Banner.warningBorderColor"?: string;
+
+ // Bookmark
+ "Bookmark.iconBackground"?: string;
+ "Bookmark.Mnemonic.iconForeground"?: string;
+ "Bookmark.MnemonicAssigned.background"?: string;
+ "Bookmark.MnemonicAssigned.foreground"?: string;
+ "Bookmark.MnemonicAvailable.background"?: string;
+ "Bookmark.MnemonicAvailable.borderColor"?: string;
+ "Bookmark.MnemonicAvailable.foreground"?: string;
+ "Bookmark.MnemonicCurrent.background"?: string;
+ "Bookmark.MnemonicCurrent.foreground"?: string;
+
+ // Borders
+ "Borders.color"?: string;
+ "Borders.ContrastBorderColor"?: string;
+
+ // Button
+ "Button.arc"?: number;
+ "Button.background"?: string;
+ "Button.borderColor"?: string;
+ "Button.default.borderColor"?: string;
+ "Button.default.endBackground"?: string;
+ "Button.default.focusColor"?: string;
+ "Button.default.focusedBorderColor"?: string;
+ "Button.default.foreground"?: string;
+ "Button.default.shadowColor"?: string;
+ "Button.default.startBackground"?: string;
+ "Button.disabledBackground"?: string;
+ "Button.disabledBorderColor"?: string;
+ "Button.disabledText"?: string;
+ "Button.endBackground"?: string;
+ "Button.focusedBorderColor"?: string;
+ "Button.foreground"?: string;
+ "Button.shadowColor"?: string;
+ "Button.startBackground"?: string;
+
+ // CheckBox (JDK Swing component)
+ "CheckBox.background"?: string;
+ // Checkbox (IntelliJ Platform component)
+ "Checkbox.Background.Default"?: string;
+ "Checkbox.Background.Disabled"?: string;
+ "Checkbox.Background.Selected"?: string;
+
+ "Checkbox.Border.Default"?: string;
+ "Checkbox.Border.Disabled"?: string;
+ "Checkbox.Border.Selected"?: string;
+ "CheckBox.disabledText"?: string;
+ "Checkbox.Focus.Thin.Default"?: string;
+ "Checkbox.Focus.Thin.Selected"?: string;
+ "Checkbox.Focus.Wide"?: string;
+ "CheckBox.foreground"?: string;
+ "Checkbox.Foreground.Disabled"?: string;
+ "Checkbox.Foreground.Selected"?: string;
+ "CheckBox.select"?: string;
+
+ "Code.Block.backgroundColor"?: string;
+ "Code.Block.borderColor"?: string;
+ "Code.Block.borderRadius"?: number;
+ "Code.Block.borderWidth"?: number;
+ "Code.Block.EditorPane.backgroundColor"?: string;
+ "Code.Block.EditorPane.borderColor"?: string;
+ "Code.Block.foregroundColor"?: string;
+ // Code (inline and block code elements)
+ "Code.Inline.backgroundColor"?: string;
+ "Code.Inline.borderColor"?: string;
+ "Code.Inline.borderRadius"?: number;
+ "Code.Inline.borderWidth"?: number;
+ "Code.Inline.foregroundColor"?: string;
+
+ // ComboBox
+ "ComboBox.ArrowButton.background"?: string;
+ "ComboBox.ArrowButton.disabledIconColor"?: string;
+ "ComboBox.ArrowButton.iconColor"?: string;
+
+ "ComboBox.ArrowButton.nonEditableBackground"?: string;
+ "ComboBox.background"?: string;
+ "ComboBox.disabledBackground"?: string;
+ "ComboBox.disabledForeground"?: string;
+ "ComboBox.foreground"?: string;
+ "ComboBox.modifiedItemForeground"?: string;
+ "ComboBox.nonEditableBackground"?: string;
+ "ComboBox.selectionBackground"?: string;
+ "ComboBox.selectionForeground"?: string;
+ // CompletionPopup
+ "CompletionPopup.Advertiser.background"?: string;
+ "CompletionPopup.Advertiser.foreground"?: string;
+ // CompletionPopup
+ "CompletionPopup.background"?: string;
+
+ "CompletionPopup.foreground"?: string;
+ "CompletionPopup.matchForeground"?: string;
+ "CompletionPopup.selectionBackground"?: string;
+ "CompletionPopup.selectionForeground"?: string;
+ "CompletionPopup.selectionInactiveBackground"?: string;
+ "CompletionPopup.selectionInfoForeground"?: string;
+ // Component (Universal JDK component settings)
+ "Component.arc"?: number;
+ "Component.borderColor"?: string;
+ "Component.disabledBorderColor"?: string;
+ "Component.errorFocusColor"?: string;
+ "Component.focusColor"?: string;
+
+ "Component.focusedBorderColor"?: string;
+ "Component.focusWidth"?: number;
+ "Component.inactiveErrorFocusColor"?: string;
+ "Component.inactiveWarningFocusColor"?: string;
+ "Component.infoForeground"?: string;
+ "Component.warningFocusColor"?: string;
+ // Counter
+ "Counter.background"?: string;
+ "Counter.foreground"?: string;
+ "Debugger.EvaluateExpression.background"?: string;
+
+ "Debugger.Variables.changedValueForeground"?: string;
+ // Debugger
+ "Debugger.Variables.collectingDataForeground"?: string;
+
+ "Debugger.Variables.errorMessageForeground"?: string;
+ "Debugger.Variables.evaluatingExpressionForeground"?: string;
+ "Debugger.Variables.modifyingValueForeground"?: string;
+ "Debugger.Variables.typeForeground"?: string;
+ "Debugger.Variables.valueForeground"?: string;
+ // DefaultTabs (for all tabs except TabbedPane)
+ "DefaultTabs.background"?: string;
+ "DefaultTabs.borderColor"?: string;
+ "DefaultTabs.hoverBackground"?: string;
+
+ "DefaultTabs.inactiveColoredFileBackground"?: string;
+ "DefaultTabs.inactiveMaskColor"?: string;
+ "DefaultTabs.underlineColor"?: string;
+ "DefaultTabs.underlinedTabBackground"?: string;
+ "DefaultTabs.underlinedTabForeground"?: string;
+ "DefaultTabs.underlineHeight"?: number;
+ // DisclosureButton
+ "DisclosureButton.arc"?: number;
+ "DisclosureButton.defaultBackground"?: string;
+ "DisclosureButton.hoverOverlay"?: string;
+
+ "DisclosureButton.pressedOverlay"?: string;
+ // DragAndDrop
+ "DragAndDrop.areaBackground"?: string;
+ "DragAndDrop.areaBorderColor"?: string;
+ "DragAndDrop.areaForeground"?: string;
+
+ // Editor
+ "Editor.background"?: string;
+ "Editor.foreground"?: string;
+ "Editor.SearchField.background"?: string;
+
+ // EditorPane
+ "EditorPane.background"?: string;
+ "EditorPane.caretForeground"?: string;
+ "EditorPane.foreground"?: string;
+
+ "EditorPane.inactiveBackground"?: string;
+ "EditorPane.inactiveForeground"?: string;
+ "EditorPane.selectionBackground"?: string;
+ "EditorPane.selectionForeground"?: string;
+ // EditorTabs
+ "EditorTabs.background"?: string;
+ "EditorTabs.borderColor"?: string;
+ "EditorTabs.hoverBackground"?: string;
+
+ "EditorTabs.inactiveColoredFileBackground"?: string;
+ "EditorTabs.inactiveMaskColor"?: string;
+ "EditorTabs.inactiveUnderlineColor"?: string;
+ "EditorTabs.inactiveUnderlinedTabBackground"?: string;
+ "EditorTabs.underlineArc"?: number;
+ "EditorTabs.underlineColor"?: string;
+ "EditorTabs.underlinedTabBackground"?: string;
+ "EditorTabs.underlinedTabForeground"?: string;
+ "EditorTabs.underlineHeight"?: number;
+ // FileColor
+ "FileColor.Blue"?: string;
+ "FileColor.Green"?: string;
+ "FileColor.Orange"?: string;
+
+ "FileColor.Rose"?: string;
+ "FileColor.Violet"?: string;
+ "FileColor.Yellow"?: string;
+ // Focus
+ "Focus.borderColor"?: string;
+ "Focus.color"?: string;
+ // Git
+ "Git.Log.Ref.LocalBranch"?: string;
+
+ "Git.Log.Ref.Other"?: string;
+ "Git.Log.Ref.RemoteBranch"?: string;
+ "Git.Log.Ref.Tag"?: string;
+ // Group
+ "Group.disabledSeparatorColor"?: string;
+ "Group.separatorColor"?: string;
+ // GutterTooltip
+ "GutterTooltip.backgroundColor"?: string;
+ "GutterTooltip.borderColor"?: string;
+ "GutterTooltip.lineSeparatorColor"?: string;
+
+ // IconBadge
+ "IconBadge.errorBackground"?: string;
+ "IconBadge.errorForeground"?: string;
+
+ "IconBadge.infoBackground"?: string;
+ "IconBadge.infoForeground"?: string;
+ "IconBadge.successBackground"?: string;
+ "IconBadge.successForeground"?: string;
+
+ "IconBadge.warningBackground"?: string;
+ "IconBadge.warningForeground"?: string;
+
+ // InfoPanel
+ "InfoPanel.background"?: string;
+ "InfoPanel.foreground"?: string;
+ // InplaceRefactoringPopup
+ "InplaceRefactoringPopup.borderColor"?: string;
+
+ // Islands (for Islands theme support)
+ "Island.arc"?: number;
+ "Island.arc.compact"?: number;
+
+ "Island.borderColor"?: string;
+
+ "Island.borderWidth"?: number;
+ "Island.borderWidth.compact"?: number;
+ "Island.inactiveAlpha"?: number;
+ Islands?: number;
+ // Label
+ "Label.background"?: string;
+ "Label.disabledForeground"?: string;
+ "Label.errorForeground"?: string;
+
+ "Label.foreground"?: string;
+ "Label.infoForeground"?: string;
+ "Label.selectedDisabledForeground"?: string;
+ "Label.selectedForeground"?: string;
+ "Label.successForeground"?: string;
+ "Label.warningForeground"?: string;
+ // Link
+ "Link.activeForeground"?: string;
+ "Link.hoverForeground"?: string;
+ "Link.pressedForeground"?: string;
+
+ "Link.secondaryForeground"?: string;
+ "Link.visitedForeground"?: string;
+ // List
+ "List.background"?: string;
+ "List.foreground"?: string;
+ "List.hoverBackground"?: string;
+
+ "List.selectionBackground"?: string;
+ "List.selectionForeground"?: string;
+ "List.selectionInactiveBackground"?: string;
+ "List.selectionInactiveForeground"?: string;
+ // MainMenu
+ "MainMenu.background"?: string;
+ "MainMenu.borderColor"?: string;
+ "MainMenu.disabledForeground"?: string;
+
+ "MainMenu.foreground"?: string;
+ "MainMenu.selectionBackground"?: string;
+ "MainMenu.selectionForeground"?: string;
+ // MainToolbar
+ "MainToolbar.background"?: string;
+ "MainToolbar.borderColor"?: string;
+ "MainToolbar.Dropdown.background"?: string;
+
+ "MainToolbar.Dropdown.hoverBackground"?: string;
+ "MainToolbar.Icon.hoverBackground"?: string;
+ "MainToolbar.Icon.pressedBackground"?: string;
+ "MainToolbar.inactiveBackground"?: string;
+ "MainToolbar.separatorColor"?: string;
+ "MainWindow.background"?: string;
+ "MainWindow.Tab.background"?: string;
+ "MainWindow.Tab.foreground"?: string;
+ "MainWindow.Tab.hoverBackground"?: string;
+ "MainWindow.Tab.inactiveUnderlineColor"?: string;
+ "MainWindow.Tab.selectedBackground"?: string;
+ "MainWindow.Tab.underlineColor"?: string;
+ "MainWindow.Tab.underlineHeight"?: number;
+ // MemoryIndicator
+ "MemoryIndicator.allocatedBackground"?: string;
+ "MemoryIndicator.usedBackground"?: string;
+ // Menu
+ "Menu.acceleratorForeground"?: string;
+
+ "Menu.acceleratorSelectionForeground"?: string;
+ "Menu.background"?: string;
+
+ "Menu.borderColor"?: string;
+ "Menu.disabledForeground"?: string;
+ "Menu.foreground"?: string;
+ "Menu.selectionBackground"?: string;
+ "Menu.selectionForeground"?: string;
+ "Menu.separatorColor"?: string;
+ // MenuItem
+ "MenuItem.acceleratorForeground"?: string;
+ "MenuItem.acceleratorSelectionForeground"?: string;
+ "MenuItem.background"?: string;
+
+ "MenuItem.disabledForeground"?: string;
+ "MenuItem.foreground"?: string;
+ "MenuItem.selectionBackground"?: string;
+ "MenuItem.selectionForeground"?: string;
+ // NavBar
+ "NavBar.background"?: string;
+ "NavBar.borderColor"?: string;
+ // NewUI (for new UI components)
+ "NewUI.activeBackground"?: string;
+
+ // NotificationError
+ "Notification.background"?: string;
+ "Notification.borderColor"?: string;
+
+ "Notification.errorBackground"?: string;
+
+ "Notification.errorBorderColor"?: string;
+ "Notification.errorForeground"?: string;
+ "Notification.foreground"?: string;
+ "Notification.linkForeground"?: string;
+ "Notification.MoreButton.background"?: string;
+ "Notification.MoreButton.foreground"?: string;
+ "Notification.ToolWindow.errorBackground"?: string;
+ "Notification.ToolWindow.errorBorderColor"?: string;
+ "Notification.ToolWindow.informativeBackground"?: string;
+ "Notification.ToolWindow.informativeBorderColor"?: string;
+ "Notification.ToolWindow.warningBackground"?: string;
+ "Notification.ToolWindow.warningBorderColor"?: string;
+ // Panel
+ "Panel.background"?: string;
+ "Panel.foreground"?: string;
+ // ParameterInfo
+ "ParameterInfo.background"?: string;
+
+ "ParameterInfo.borderColor"?: string;
+ "ParameterInfo.currentOverloadBackground"?: string;
+
+ "ParameterInfo.currentParameterForeground"?: string;
+ "ParameterInfo.disabledForeground"?: string;
+ "ParameterInfo.foreground"?: string;
+ // Plugins
+ "Plugins.Button.installBackground"?: string;
+ "Plugins.Button.installBorderColor"?: string;
+ "Plugins.Button.installFillBackground"?: string;
+
+ "Plugins.Button.installFillForeground"?: string;
+ "Plugins.Button.installFocusedBackground"?: string;
+ "Plugins.Button.installForeground"?: string;
+ "Plugins.Button.updateBackground"?: string;
+ "Plugins.Button.updateBorderColor"?: string;
+ "Plugins.Button.updateForeground"?: string;
+ "Plugins.disabledForeground"?: string;
+ "Plugins.eapTagBackground"?: string;
+ "Plugins.eapTagForeground"?: string;
+ "Plugins.hoverBackground"?: string;
+ "Plugins.lightSelectionBackground"?: string;
+ "Plugins.paidTagBackground"?: string;
+ "Plugins.paidTagForeground"?: string;
+ "Plugins.SearchField.background"?: string;
+ "Plugins.SearchField.borderColor"?: string;
+ "Plugins.SectionHeader.background"?: string;
+ "Plugins.SectionHeader.foreground"?: string;
+ "Plugins.Tab.hoverBackground"?: string;
+ "Plugins.Tab.selectedBackground"?: string;
+ "Plugins.Tab.selectedForeground"?: string;
+ "Plugins.tagBackground"?: string;
+ "Plugins.tagForeground"?: string;
+ "Plugins.trialTagBackground"?: string;
+ "Plugins.trialTagForeground"?: string;
+ // Popup
+ "Popup.Advertiser.background"?: string;
+ "Popup.Advertiser.borderColor"?: string;
+ "Popup.Advertiser.borderInsets"?: string;
+
+ "Popup.Advertiser.foreground"?: string;
+ "Popup.background"?: string;
+ "Popup.borderColor"?: string;
+ "Popup.Header.activeBackground"?: string;
+ "Popup.Header.inactiveBackground"?: string;
+ "Popup.inactiveBorderColor"?: string;
+ "Popup.Separator.foreground"?: string;
+ "Popup.Toolbar.background"?: string;
+ "Popup.Toolbar.borderColor"?: string;
+ // PopupMenu
+ "PopupMenu.background"?: string;
+ "PopupMenu.foreground"?: string;
+ "PopupMenu.selectionBackground"?: string;
+
+ "PopupMenu.selectionForeground"?: string;
+ "PopupMenu.translucentBackground"?: string;
+ // ProgressBar
+ "ProgressBar.backgroundColor"?: string;
+ "ProgressBar.failedColor"?: string;
+ "ProgressBar.failedEndColor"?: string;
+
+ "ProgressBar.foreground"?: string;
+ "ProgressBar.indeterminateEndColor"?: string;
+ "ProgressBar.indeterminateStartColor"?: string;
+ "ProgressBar.passedColor"?: string;
+ "ProgressBar.passedEndColor"?: string;
+ "ProgressBar.progressColor"?: string;
+ "ProgressBar.selectionBackground"?: string;
+ "ProgressBar.selectionForeground"?: string;
+ "ProgressBar.trackColor"?: string;
+ // RadioButton (JDK Swing component)
+ "RadioButton.background"?: string;
+ "RadioButton.disabledText"?: string;
+ "RadioButton.foreground"?: string;
+
+ // RunWidget
+ "RunWidget.background"?: string;
+ "RunWidget.foreground"?: string;
+ "RunWidget.hoverBackground"?: string;
+ "RunWidget.iconColor"?: string;
+ "RunWidget.runningBackground"?: string;
+ "RunWidget.runningForeground"?: string;
+ "RunWidget.runningHoverBackground"?: string;
+ "RunWidget.runningIconColor"?: string;
+ "RunWidget.stopBackground"?: string;
+ "RunWidget.stopForeground"?: string;
+ "RunWidget.stopHoverBackground"?: string;
+
+ // ScrollBar
+ "ScrollBar.background"?: string;
+ "ScrollBar.hoverThumbColor"?: string;
+ "ScrollBar.hoverTrackColor"?: string;
+ "ScrollBar.Mac.hoverThumbBorderColor"?: string;
+ "ScrollBar.Mac.hoverThumbColor"?: string;
+ "ScrollBar.Mac.hoverTrackColor"?: string;
+ "ScrollBar.Mac.thumbBorderColor"?: string;
+ "ScrollBar.Mac.thumbColor"?: string;
+ "ScrollBar.Mac.trackColor"?: string;
+ "ScrollBar.Mac.Transparent.hoverThumbBorderColor"?: string;
+ "ScrollBar.Mac.Transparent.hoverThumbColor"?: string;
+ "ScrollBar.Mac.Transparent.hoverTrackColor"?: string;
+ "ScrollBar.Mac.Transparent.thumbBorderColor"?: string;
+ "ScrollBar.Mac.Transparent.thumbColor"?: string;
+ "ScrollBar.Mac.Transparent.trackColor"?: string;
+ "ScrollBar.thumbColor"?: string;
+ "ScrollBar.track"?: string;
+ "ScrollBar.trackColor"?: string;
+ "ScrollBar.Transparent.hoverThumbColor"?: string;
+ "ScrollBar.Transparent.hoverTrackColor"?: string;
+ "ScrollBar.Transparent.thumbColor"?: string;
+ "ScrollBar.Transparent.trackColor"?: string;
+
+ // SearchEverywhere
+ "SearchEverywhere.Advertiser.background"?: string;
+ "SearchEverywhere.Advertiser.foreground"?: string;
+ "SearchEverywhere.background"?: string;
+ "SearchEverywhere.Header.background"?: string;
+ "SearchEverywhere.List.separatorColor"?: string;
+ "SearchEverywhere.List.separatorForeground"?: string;
+ "SearchEverywhere.SearchField.background"?: string;
+ "SearchEverywhere.SearchField.borderColor"?: string;
+ "SearchEverywhere.Tab.selectedBackground"?: string;
+ "SearchEverywhere.Tab.selectedForeground"?: string;
+
+ // SearchField
+ "SearchField.background"?: string;
+ "SearchField.errorBackground"?: string;
+ "SearchField.errorForeground"?: string;
+
+ // SearchMatch
+ "SearchMatch.endBackground"?: string;
+ "SearchMatch.endForeground"?: string;
+ "SearchMatch.startBackground"?: string;
+ "SearchMatch.startForeground"?: string;
+
+ // SearchOption
+ "SearchOption.background"?: string;
+ "SearchOption.selectedBackground"?: string;
+
+ // SegmentedButton
+ "SegmentedButton.focusedSelectedButtonColor"?: string;
+ "SegmentedButton.selectedButtonColor"?: string;
+ "SegmentedButton.selectedEndBorderColor"?: string;
+ "SegmentedButton.selectedStartBorderColor"?: string;
+
+ // Separator
+ "Separator.foreground"?: string;
+ "Separator.separatorColor"?: string;
+
+ // Settings
+ "Settings.Spotlight.borderColor"?: string;
+
+ // SidePanel
+ "SidePanel.background"?: string;
+
+ // Slider
+ "Slider.background"?: string;
+ "Slider.buttonBorderColor"?: string;
+ "Slider.buttonColor"?: string;
+ "Slider.tickColor"?: string;
+ "Slider.trackColor"?: string;
+
+ // SpeedSearch
+ "SpeedSearch.background"?: string;
+ "SpeedSearch.borderColor"?: string;
+ "SpeedSearch.errorBackground"?: string;
+ "SpeedSearch.errorBorderColor"?: string;
+ "SpeedSearch.foreground"?: string;
+
+ // Spinner
+ "Spinner.background"?: string;
+
+ // StatusBar
+ "StatusBar.background"?: string;
+ "StatusBar.borderColor"?: string;
+ "StatusBar.hoverBackground"?: string;
+ "StatusBar.Widget.hoverBackground"?: string;
+
+ // TabbedPane
+ "TabbedPane.background"?: string;
+ "TabbedPane.borderColor"?: string;
+ "TabbedPane.contentAreaColor"?: string;
+ "TabbedPane.disabled"?: string;
+ "TabbedPane.focus"?: string;
+ "TabbedPane.focusColor"?: string;
+ "TabbedPane.foreground"?: string;
+ "TabbedPane.hoverColor"?: string;
+ "TabbedPane.tabSelectionHeight"?: number;
+ "TabbedPane.underlineColor"?: string;
+ // Table
+ "Table.alternateRowBackground"?: string;
+ "Table.background"?: string;
+ "Table.dropLineColor"?: string;
+ "Table.focusCellBackground"?: string;
+ "Table.foreground"?: string;
+ "Table.gridColor"?: string;
+
+ "Table.hoverBackground"?: string;
+ "Table.lightSelectionBackground"?: string;
+ "Table.lightSelectionForeground"?: string;
+ "Table.lightSelectionInactiveBackground"?: string;
+ "Table.lightSelectionInactiveForeground"?: string;
+ "Table.selectionBackground"?: string;
+ "Table.selectionForeground"?: string;
+ "Table.selectionInactiveBackground"?: string;
+ "Table.selectionInactiveForeground"?: string;
+ "Table.stripeColor"?: string;
+
+ // Tag
+ "Tag.background"?: string;
+ "Tag.foreground"?: string;
+
+ // TextArea
+ "TextArea.background"?: string;
+ "TextArea.caretForeground"?: string;
+ "TextArea.foreground"?: string;
+ "TextArea.inactiveBackground"?: string;
+ "TextArea.inactiveForeground"?: string;
+ "TextArea.selectionBackground"?: string;
+ "TextArea.selectionForeground"?: string;
+
+ // TextField
+ "TextField.background"?: string;
+ "TextField.borderColor"?: string;
+ "TextField.caretForeground"?: string;
+ "TextField.disabledBackground"?: string;
+ "TextField.focusedBorderColor"?: string;
+ "TextField.foreground"?: string;
+ "TextField.highlight"?: string;
+ "TextField.hoverBorderColor"?: string;
+ "TextField.inactiveBackground"?: string;
+ "TextField.inactiveForeground"?: string;
+ "TextField.placeholderForeground"?: string;
+ "TextField.selectionBackground"?: string;
+ "TextField.selectionForeground"?: string;
+
+ // TitlePane
+ "TitlePane.background"?: string;
+ "TitlePane.Button.hoverBackground"?: string;
+ "TitlePane.foreground"?: string;
+ "TitlePane.fullScreen.background"?: string;
+ "TitlePane.inactiveBackground"?: string;
+ "TitlePane.inactiveForeground"?: string;
+ "TitlePane.infoForeground"?: string;
+
+ // ToggleButton
+ "ToggleButton.background"?: string;
+ "ToggleButton.borderColor"?: string;
+ "ToggleButton.buttonColor"?: string;
+ "ToggleButton.disabledBorderColor"?: string;
+ "ToggleButton.offBackground"?: string;
+ "ToggleButton.offForeground"?: string;
+ "ToggleButton.onBackground"?: string;
+ "ToggleButton.onForeground"?: string;
+
+ // ToolBar
+ "ToolBar.background"?: string;
+ "ToolBar.borderHandleColor"?: string;
+ "ToolBar.floatingBackground"?: string;
+ "ToolBar.foreground"?: string;
+ "ToolBar.separatorColor"?: string;
+
+ // ToolTip
+ "ToolTip.Actions.background"?: string;
+ "ToolTip.Actions.foreground"?: string;
+ "ToolTip.Actions.Info.foreground"?: string;
+ "ToolTip.background"?: string;
+ "ToolTip.borderColor"?: string;
+ "ToolTip.foreground"?: string;
+ "ToolTip.infoForeground"?: string;
+ "ToolTip.separatorColor"?: string;
+ "ToolTip.shortcutForeground"?: string;
+
+ // ToolWindow
+ "ToolWindow.background"?: string;
+ "ToolWindow.Button.hoverBackground"?: string;
+ "ToolWindow.Button.selectedBackground"?: string;
+ "ToolWindow.Button.selectedForeground"?: string;
+ "ToolWindow.Header.background"?: string;
+ "ToolWindow.Header.borderColor"?: string;
+ "ToolWindow.Header.closeButton.background"?: string;
+ "ToolWindow.Header.inactiveBackground"?: string;
+ "ToolWindow.HeaderCloseButton.background"?: string;
+ "ToolWindow.HeaderTab.hoverBackground"?: string;
+ "ToolWindow.HeaderTab.hoverInactiveBackground"?: string;
+ "ToolWindow.HeaderTab.selectedBackground"?: string;
+ "ToolWindow.HeaderTab.selectedInactiveBackground"?: string;
+ "ToolWindow.HeaderTab.underlineColor"?: string;
+ "ToolWindow.HeaderTab.underlinedTabBackground"?: string;
+ "ToolWindow.HeaderTab.underlinedTabForeground"?: string;
+ "ToolWindow.HeaderTab.underlinedTabInactiveBackground"?: string;
+ "ToolWindow.HeaderTab.underlinedTabInactiveForeground"?: string;
+ "ToolWindow.HeaderTab.underlineHeight"?: number;
+ "ToolWindow.Stripe.background"?: string;
+ "ToolWindow.Stripe.borderColor"?: string;
+
+ // Tree
+ "Tree.background"?: string;
+ "Tree.errorForeground"?: string;
+ "Tree.foreground"?: string;
+ "Tree.hoverBackground"?: string;
+ "Tree.modifiedItemForeground"?: string;
+ "Tree.rowHeight"?: number;
+ "Tree.selectionBackground"?: string;
+ "Tree.selectionForeground"?: string;
+ "Tree.selectionInactiveBackground"?: string;
+
+ // ValidationTooltip
+ "ValidationTooltip.errorBackground"?: string;
+ "ValidationTooltip.errorBorderColor"?: string;
+ "ValidationTooltip.warningBackground"?: string;
+ "ValidationTooltip.warningBorderColor"?: string;
+
+ // VersionControl
+ "VersionControl.FileHistory.Commit.otherBranchBackground"?: string;
+ "VersionControl.FileHistory.Commit.selectedBranchBackground"?: string;
+ "VersionControl.GitCommits.graphColor"?: string;
+ "VersionControl.GitLog.headIconColor"?: string;
+ "VersionControl.GitLog.localBranchIconColor"?: string;
+ "VersionControl.GitLog.otherIconColor"?: string;
+ "VersionControl.GitLog.remoteBranchIconColor"?: string;
+ "VersionControl.GitLog.tagIconColor"?: string;
+ "VersionControl.HgLog.bookmarkIconColor"?: string;
+ "VersionControl.HgLog.branchIconColor"?: string;
+ "VersionControl.HgLog.closedBranchIconColor"?: string;
+ "VersionControl.HgLog.headIconColor"?: string;
+ "VersionControl.HgLog.localTagIconColor"?: string;
+ "VersionControl.HgLog.mqTagIconColor"?: string;
+ "VersionControl.HgLog.tagIconColor"?: string;
+ "VersionControl.HgLog.tipIconColor"?: string;
+ "VersionControl.Log.Commit.currentBranchBackground"?: string;
+ "VersionControl.Log.Commit.hoveredBackground"?: string;
+ "VersionControl.Log.Commit.unmatchedForeground"?: string;
+ "VersionControl.Ref.background"?: string;
+ "VersionControl.Ref.backgroundBase"?: string;
+ "VersionControl.RefLabel.background"?: string;
+ "VersionControl.RefLabel.backgroundBase"?: string;
+ "VersionControl.RefLabel.foreground"?: string;
+
+ // WelcomeScreen
+ "WelcomeScreen.background"?: string;
+ "WelcomeScreen.borderColor"?: string;
+ "WelcomeScreen.captionBackground"?: string;
+ "WelcomeScreen.captionForeground"?: string;
+ "WelcomeScreen.Details.background"?: string;
+ "WelcomeScreen.footerBackground"?: string;
+ "WelcomeScreen.footerForeground"?: string;
+ "WelcomeScreen.groupIconBorderColor"?: string;
+ "WelcomeScreen.headerBackground"?: string;
+ "WelcomeScreen.headerForeground"?: string;
+ "WelcomeScreen.Projects.actions.background"?: string;
+ "WelcomeScreen.Projects.actions.selectionBackground"?: string;
+ "WelcomeScreen.Projects.background"?: string;
+ "WelcomeScreen.Projects.selectionBackground"?: string;
+ "WelcomeScreen.Projects.selectionInactiveBackground"?: string;
+ "WelcomeScreen.separatorColor"?: string;
+ "WelcomeScreen.SidePanel.background"?: string;
+
+ // Window
+ "window.border"?: string;
+}
+
+/**
+ * Wildcard colors (applied to all components)
+ */
+export interface JetBrainsWildcardColors {
+ acceleratorForeground?: string;
+ acceleratorSelectionForeground?: string;
+ background?: string;
+ borderColor?: string;
+ caretForeground?: string;
+ disabledBackground?: string;
+ disabledBorderColor?: string;
+ disabledForeground?: string;
+ disabledText?: string;
+ errorBorderColor?: string;
+ errorForeground?: string;
+ focusColor?: string;
+ focusedBorderColor?: string;
+ foreground?: string;
+ hoverBackground?: string;
+ hoverBorderColor?: string;
+ inactiveBackground?: string;
+ inactiveForeground?: string;
+ infoForeground?: string;
+ lightSelectionBackground?: string;
+ lightSelectionForeground?: string;
+ modifiedItemForeground?: string;
+ pressedBackground?: string;
+ pressedBorderColor?: string;
+ selectionBackground?: string;
+ selectionForeground?: string;
+ selectionInactiveBackground?: string;
+ selectionInactiveForeground?: string;
+ separatorColor?: string;
+ warningBorderColor?: string;
+ warningForeground?: string;
+}
diff --git a/src/generators/jetbrains/ui.ts b/src/generators/jetbrains/ui.ts
new file mode 100644
index 00000000..d69640c5
--- /dev/null
+++ b/src/generators/jetbrains/ui.ts
@@ -0,0 +1,819 @@
+/**
+ * JetBrains UI Color Mappings
+ *
+ * Maps Bearded Theme colors to JetBrains UI component colors.
+ * Based on official JetBrains theme documentation:
+ * - https://plugins.jetbrains.com/docs/intellij/themes-customize.html
+ * - https://plugins.jetbrains.com/docs/intellij/supporting-islands-theme.html
+ */
+
+import { colord as c } from "colord";
+
+import { ThemeOptions } from "../../shared/theme-registry";
+import { Theme } from "../../shared/types";
+import { JetBrainsUiColors } from "./types";
+import { transparent } from "./utils";
+
+/**
+ * Build JetBrains UI colors from a Bearded Theme
+ *
+ * @param theme - The source theme
+ * @param options - Theme options (light, hc, etc.)
+ * @returns JetBrains UI color configuration
+ */
+export function buildJetBrainsUiColors(
+ theme: Theme,
+ options: ThemeOptions,
+): JetBrainsUiColors {
+ const { hc, light } = options;
+ const { colors, levels, ui } = theme;
+
+ // Helper functions
+ const alpha = (color: string, a: number): string =>
+ c(color).alpha(a).toHex();
+
+ const lightenOrDarken = (color: string, amount: number): string =>
+ light ? c(color).darken(amount).toHex() : c(color).lighten(amount).toHex();
+
+ const hoverBg = lightenOrDarken(ui.uibackground, 0.05);
+ const selectedBg = alpha(ui.primary, 0.2);
+ const activeBg = alpha(ui.primary, 0.3);
+ const borderColor = ui.border;
+ const inputBg = light
+ ? c(ui.uibackground).lighten(0.02).toHex()
+ : c(ui.uibackground).lighten(0.03).toHex();
+
+ return {
+ // Wildcard defaults (applied to all components)
+ "*": {
+ acceleratorForeground: ui.defaultalt,
+ acceleratorSelectionForeground: ui.default,
+ background: ui.uibackground,
+ borderColor: borderColor,
+ caretForeground: ui.primary,
+ disabledBackground: alpha(ui.uibackground, 0.6),
+ disabledBorderColor: alpha(borderColor, 0.5),
+ disabledForeground: alpha(ui.default, 0.4),
+ disabledText: alpha(ui.default, 0.4),
+ errorBorderColor: levels.danger,
+ errorForeground: levels.danger,
+ focusColor: alpha(ui.primary, 0.5),
+ focusedBorderColor: ui.primary,
+ foreground: ui.default,
+ hoverBackground: hoverBg,
+ hoverBorderColor: lightenOrDarken(borderColor, 0.1),
+ inactiveBackground: ui.uibackgroundalt,
+ inactiveForeground: ui.defaultalt,
+ infoForeground: levels.info,
+ lightSelectionBackground: alpha(ui.primary, 0.15),
+ lightSelectionForeground: ui.default,
+ modifiedItemForeground: levels.info,
+ pressedBackground: activeBg,
+ pressedBorderColor: ui.primary,
+ selectionBackground: selectedBg,
+ selectionForeground: ui.default,
+ selectionInactiveBackground: alpha(ui.primary, 0.1),
+ selectionInactiveForeground: ui.default,
+ separatorColor: borderColor,
+ warningBorderColor: levels.warning,
+ warningForeground: levels.warning,
+ },
+
+ // Action Button
+ "ActionButton.hoverBackground": hoverBg,
+ "ActionButton.hoverBorderColor": transparent(borderColor),
+ "ActionButton.pressedBackground": activeBg,
+ "ActionButton.pressedBorderColor": transparent(borderColor),
+
+ // Banner
+ "Banner.errorBackground": alpha(levels.danger, 0.15),
+ "Banner.errorBorderColor": alpha(levels.danger, 0.5),
+ "Banner.infoBackground": alpha(levels.info, 0.15),
+ "Banner.infoBorderColor": alpha(levels.info, 0.5),
+ "Banner.successBackground": alpha(levels.success, 0.15),
+ "Banner.successBorderColor": alpha(levels.success, 0.5),
+ "Banner.warningBackground": alpha(levels.warning, 0.15),
+ "Banner.warningBorderColor": alpha(levels.warning, 0.5),
+
+ // Bookmark
+ "Bookmark.iconBackground": ui.primary,
+ "Bookmark.Mnemonic.iconForeground": light
+ ? "#FFFFFF"
+ : c(ui.primary).isDark()
+ ? "#FFFFFF"
+ : "#000000",
+ "Bookmark.MnemonicAssigned.background": alpha(ui.primary, 0.15),
+ "Bookmark.MnemonicAssigned.foreground": ui.default,
+ "Bookmark.MnemonicAvailable.background": ui.uibackgroundalt,
+ "Bookmark.MnemonicAvailable.borderColor": borderColor,
+ "Bookmark.MnemonicAvailable.foreground": ui.defaultalt,
+ "Bookmark.MnemonicCurrent.background": ui.primary,
+ "Bookmark.MnemonicCurrent.foreground": light
+ ? "#FFFFFF"
+ : c(ui.primary).isDark()
+ ? "#FFFFFF"
+ : "#000000",
+
+ // Borders
+ "Borders.color": borderColor,
+ "Borders.ContrastBorderColor": hc
+ ? ui.default
+ : lightenOrDarken(borderColor, 0.1),
+
+ // Button
+ "Button.arc": 6,
+ "Button.background": ui.uibackgroundalt,
+ "Button.borderColor": borderColor,
+ "Button.default.borderColor": transparent(borderColor),
+ "Button.default.endBackground": alpha(ui.primary, 0.25),
+ "Button.default.focusColor": alpha(ui.primary, 0.5),
+ "Button.default.focusedBorderColor": alpha(ui.primary, 0.5),
+ "Button.default.foreground": ui.default,
+ "Button.default.shadowColor": transparent(ui.uibackground),
+ "Button.default.startBackground": alpha(ui.primary, 0.25),
+ "Button.disabledBackground": alpha(ui.uibackgroundalt, 0.5),
+ "Button.disabledBorderColor": alpha(borderColor, 0.5),
+ "Button.disabledText": alpha(ui.default, 0.4),
+ "Button.endBackground": ui.uibackgroundalt,
+ "Button.focusedBorderColor": ui.primary,
+ "Button.foreground": ui.default,
+ "Button.shadowColor": transparent(ui.uibackground),
+ "Button.startBackground": ui.uibackgroundalt,
+
+ // CheckBox (JDK Swing component)
+ "CheckBox.background": ui.uibackground,
+ // Checkbox (IntelliJ Platform component)
+ "Checkbox.Background.Default": inputBg,
+ "Checkbox.Background.Disabled": alpha(inputBg, 0.5),
+ "Checkbox.Background.Selected": ui.primary,
+
+ "Checkbox.Border.Default": borderColor,
+ "Checkbox.Border.Disabled": alpha(borderColor, 0.5),
+ "Checkbox.Border.Selected": ui.primary,
+ "CheckBox.disabledText": alpha(ui.default, 0.4),
+ "Checkbox.Focus.Thin.Default": alpha(ui.primary, 0.5),
+ "Checkbox.Focus.Thin.Selected": alpha(ui.primary, 0.5),
+ "Checkbox.Focus.Wide": alpha(ui.primary, 0.3),
+ "CheckBox.foreground": ui.default,
+ "Checkbox.Foreground.Disabled": alpha(ui.default, 0.4),
+ "Checkbox.Foreground.Selected": light
+ ? "#FFFFFF"
+ : c(ui.primary).isDark()
+ ? "#FFFFFF"
+ : "#000000",
+ "CheckBox.select": ui.primary,
+
+ // Code (inline and block code elements)
+ "Code.Block.backgroundColor": alpha(ui.uibackgroundalt, 0.5),
+ "Code.Block.borderColor": borderColor,
+ "Code.Block.borderRadius": 4,
+
+ "Code.Block.borderWidth": 1,
+ "Code.Block.EditorPane.backgroundColor": alpha(ui.uibackgroundalt, 0.3),
+ "Code.Block.EditorPane.borderColor": alpha(borderColor, 0.5),
+ "Code.Block.foregroundColor": ui.default,
+ "Code.Inline.backgroundColor": alpha(colors.orange, 0.15),
+ "Code.Inline.borderColor": alpha(colors.orange, 0.3),
+ "Code.Inline.borderRadius": 3,
+ "Code.Inline.borderWidth": 1,
+ "Code.Inline.foregroundColor": colors.orange,
+ // ComboBox
+ "ComboBox.ArrowButton.background": inputBg,
+ "ComboBox.ArrowButton.disabledIconColor": alpha(ui.default, 0.3),
+ "ComboBox.ArrowButton.iconColor": ui.defaultalt,
+
+ "ComboBox.ArrowButton.nonEditableBackground": inputBg,
+ "ComboBox.background": inputBg,
+ "ComboBox.disabledBackground": alpha(inputBg, 0.5),
+ "ComboBox.disabledForeground": alpha(ui.default, 0.4),
+ "ComboBox.foreground": ui.default,
+ "ComboBox.modifiedItemForeground": levels.info,
+
+ "ComboBox.nonEditableBackground": inputBg,
+ "ComboBox.selectionBackground": selectedBg,
+ "ComboBox.selectionForeground": ui.default,
+ // CompletionPopup
+ "CompletionPopup.Advertiser.background": ui.uibackgroundalt,
+ "CompletionPopup.Advertiser.foreground": ui.defaultalt,
+
+ // CompletionPopup
+ "CompletionPopup.background": ui.uibackgroundmid,
+
+ "CompletionPopup.foreground": ui.default,
+ "CompletionPopup.matchForeground": ui.primary,
+ "CompletionPopup.selectionBackground": selectedBg,
+ "CompletionPopup.selectionForeground": ui.default,
+ "CompletionPopup.selectionInactiveBackground": alpha(ui.primary, 0.1),
+ "CompletionPopup.selectionInfoForeground": ui.defaultalt,
+ // Component (Universal JDK component settings)
+ "Component.arc": 6,
+ // Component (Universal JDK component settings)
+ "Component.borderColor": borderColor,
+ "Component.disabledBorderColor": alpha(borderColor, 0.5),
+
+ "Component.errorFocusColor": alpha(levels.danger, 0.5),
+ "Component.focusColor": alpha(ui.primary, 0.5),
+ "Component.focusedBorderColor": ui.primary,
+ "Component.focusWidth": 2,
+ "Component.inactiveErrorFocusColor": alpha(levels.danger, 0.3),
+
+ "Component.inactiveWarningFocusColor": alpha(levels.warning, 0.3),
+ "Component.infoForeground": ui.defaultalt,
+ "Component.warningFocusColor": alpha(levels.warning, 0.5),
+ // Counter
+ "Counter.background": ui.primary,
+ "Counter.foreground": light
+ ? "#FFFFFF"
+ : c(ui.primary).isDark()
+ ? "#FFFFFF"
+ : "#000000",
+ "Debugger.EvaluateExpression.background": inputBg,
+
+ "Debugger.Variables.changedValueForeground": colors.yellow,
+ // Debugger
+ "Debugger.Variables.collectingDataForeground": ui.defaultalt,
+
+ "Debugger.Variables.errorMessageForeground": levels.danger,
+ "Debugger.Variables.evaluatingExpressionForeground": levels.info,
+ "Debugger.Variables.modifyingValueForeground": levels.warning,
+ "Debugger.Variables.typeForeground": colors.purple,
+ "Debugger.Variables.valueForeground": ui.default,
+ // DefaultTabs
+ "DefaultTabs.background": ui.uibackgroundalt,
+ "DefaultTabs.borderColor": borderColor,
+ "DefaultTabs.hoverBackground": hoverBg,
+
+ "DefaultTabs.inactiveColoredFileBackground": transparent(ui.uibackground),
+ "DefaultTabs.inactiveMaskColor": transparent(ui.uibackground),
+ "DefaultTabs.underlineColor": ui.primary,
+ "DefaultTabs.underlinedTabBackground": ui.uibackground,
+ "DefaultTabs.underlinedTabForeground": ui.default,
+ "DefaultTabs.underlineHeight": 3,
+ // DisclosureButton
+ "DisclosureButton.arc": 6,
+ "DisclosureButton.defaultBackground": ui.uibackgroundalt,
+ "DisclosureButton.hoverOverlay": alpha(ui.primary, 0.1),
+
+ "DisclosureButton.pressedOverlay": alpha(ui.primary, 0.2),
+ // DragAndDrop
+ "DragAndDrop.areaBackground": alpha(ui.primary, 0.1),
+ "DragAndDrop.areaBorderColor": ui.primary,
+ "DragAndDrop.areaForeground": ui.primary,
+
+ // Editor
+ "Editor.background": ui.uibackground,
+ "Editor.foreground": ui.default,
+ "Editor.SearchField.background": inputBg,
+
+ // EditorPane
+ "EditorPane.background": ui.uibackground,
+ "EditorPane.caretForeground": ui.primary,
+ "EditorPane.foreground": ui.default,
+
+ "EditorPane.inactiveBackground": alpha(ui.uibackground, 0.5),
+ "EditorPane.inactiveForeground": ui.defaultalt,
+ "EditorPane.selectionBackground": selectedBg,
+ "EditorPane.selectionForeground": ui.default,
+ // EditorTabs
+ "EditorTabs.background": ui.uibackgroundalt,
+ "EditorTabs.borderColor": borderColor,
+ "EditorTabs.hoverBackground": hoverBg,
+
+ "EditorTabs.inactiveColoredFileBackground": transparent(ui.uibackground),
+ "EditorTabs.inactiveMaskColor": transparent(ui.uibackground),
+ "EditorTabs.inactiveUnderlineColor": alpha(ui.primary, 0.5),
+ "EditorTabs.inactiveUnderlinedTabBackground": ui.uibackgroundmid,
+ "EditorTabs.underlineArc": 0,
+ "EditorTabs.underlineColor": ui.primary,
+ // Islands-specific tab colors
+ "EditorTabs.underlinedTabBackground": ui.uibackground,
+ "EditorTabs.underlinedTabForeground": ui.default,
+ "EditorTabs.underlineHeight": 3,
+ // FileColor
+ "FileColor.Blue": alpha(colors.blue, 0.15),
+
+ "FileColor.Green": alpha(colors.green, 0.15),
+ "FileColor.Orange": alpha(colors.orange, 0.15),
+ "FileColor.Rose": alpha(colors.pink, 0.15),
+ "FileColor.Violet": alpha(colors.purple, 0.15),
+ "FileColor.Yellow": alpha(colors.yellow, 0.15),
+ // Focus
+ "Focus.borderColor": ui.primary,
+ "Focus.color": alpha(ui.primary, 0.5),
+ // Git
+ "Git.Log.Ref.LocalBranch": colors.green,
+
+ "Git.Log.Ref.Other": colors.purple,
+ "Git.Log.Ref.RemoteBranch": colors.turquoize,
+ "Git.Log.Ref.Tag": colors.yellow,
+ // Group
+ "Group.disabledSeparatorColor": alpha(borderColor, 0.5),
+ "Group.separatorColor": borderColor,
+ // GutterTooltip
+ "GutterTooltip.backgroundColor": ui.uibackgroundmid,
+ "GutterTooltip.borderColor": borderColor,
+ "GutterTooltip.lineSeparatorColor": borderColor,
+
+ // IconBadge
+ "IconBadge.errorBackground": levels.danger,
+ "IconBadge.errorForeground": "#FFFFFF",
+ "IconBadge.infoBackground": levels.info,
+ "IconBadge.infoForeground": "#FFFFFF",
+
+ "IconBadge.successBackground": levels.success,
+ "IconBadge.successForeground": "#FFFFFF",
+
+ "IconBadge.warningBackground": levels.warning,
+ "IconBadge.warningForeground": "#FFFFFF",
+ // InfoPanel
+ "InfoPanel.background": ui.uibackgroundalt,
+
+ "InfoPanel.foreground": ui.default,
+ // InplaceRefactoringPopup
+ "InplaceRefactoringPopup.borderColor": ui.primary,
+
+ "Island.arc": 20,
+
+ "Island.arc.compact": 16,
+ "Island.borderColor": borderColor,
+ "Island.borderWidth": 5,
+ "Island.borderWidth.compact": 4,
+ "Island.inactiveAlpha": 0.44,
+ // Islands Theme Support
+ // See: https://plugins.jetbrains.com/docs/intellij/supporting-islands-theme.html
+ Islands: 1,
+ // Label
+ "Label.background": ui.uibackground,
+ "Label.disabledForeground": alpha(ui.default, 0.4),
+ "Label.errorForeground": levels.danger,
+
+ "Label.foreground": ui.default,
+ "Label.infoForeground": levels.info,
+ "Label.selectedDisabledForeground": alpha(ui.default, 0.4),
+ "Label.selectedForeground": ui.default,
+ "Label.successForeground": levels.success,
+
+ "Label.warningForeground": levels.warning,
+ // Link
+ "Link.activeForeground": c(ui.primary).lighten(0.1).toHex(),
+ "Link.hoverForeground": c(ui.primary).lighten(0.1).toHex(),
+ "Link.pressedForeground": c(ui.primary).darken(0.1).toHex(),
+ "Link.secondaryForeground": ui.defaultalt,
+ "Link.visitedForeground": colors.purple,
+ // List
+ "List.background": ui.uibackground,
+
+ "List.foreground": ui.default,
+ "List.hoverBackground": hoverBg,
+ "List.selectionBackground": selectedBg,
+ "List.selectionForeground": ui.default,
+ "List.selectionInactiveBackground": alpha(ui.primary, 0.1),
+ "List.selectionInactiveForeground": ui.default,
+
+ // MainMenu
+ "MainMenu.background": ui.uibackgroundalt,
+ "MainMenu.borderColor": borderColor,
+ "MainMenu.disabledForeground": alpha(ui.default, 0.4),
+ "MainMenu.foreground": ui.default,
+ "MainMenu.selectionBackground": selectedBg,
+ "MainMenu.selectionForeground": ui.default,
+ // MainToolbar
+ "MainToolbar.background": ui.uibackgroundalt,
+ "MainToolbar.borderColor": transparent(borderColor),
+ "MainToolbar.Dropdown.background": ui.uibackgroundalt,
+ "MainToolbar.Dropdown.hoverBackground": hoverBg,
+ "MainToolbar.Icon.hoverBackground": hoverBg,
+ "MainToolbar.Icon.pressedBackground": activeBg,
+ "MainToolbar.inactiveBackground": ui.uibackgroundalt,
+ "MainToolbar.separatorColor": borderColor,
+ "MainWindow.background": lightenOrDarken(ui.uibackgroundalt, 0.05),
+ "MainWindow.Tab.background": ui.uibackgroundalt,
+
+ "MainWindow.Tab.foreground": ui.defaultalt,
+ "MainWindow.Tab.hoverBackground": hoverBg,
+
+ "MainWindow.Tab.inactiveUnderlineColor": alpha(ui.primary, 0.5),
+ "MainWindow.Tab.selectedBackground": ui.uibackground,
+ "MainWindow.Tab.underlineColor": ui.primary,
+ "MainWindow.Tab.underlineHeight": 3,
+ // MemoryIndicator
+ "MemoryIndicator.allocatedBackground": alpha(ui.primary, 0.2),
+ "MemoryIndicator.usedBackground": ui.primary,
+ // Menu
+ "Menu.acceleratorForeground": ui.defaultalt,
+ "Menu.acceleratorSelectionForeground": ui.default,
+ "Menu.background": ui.uibackgroundmid,
+
+ "Menu.borderColor": borderColor,
+ "Menu.disabledForeground": alpha(ui.default, 0.4),
+ "Menu.foreground": ui.default,
+ "Menu.selectionBackground": selectedBg,
+ "Menu.selectionForeground": ui.default,
+ "Menu.separatorColor": borderColor,
+ // MenuItem
+ "MenuItem.acceleratorForeground": ui.defaultalt,
+
+ "MenuItem.acceleratorSelectionForeground": ui.default,
+ "MenuItem.background": ui.uibackgroundmid,
+
+ "MenuItem.disabledForeground": alpha(ui.default, 0.4),
+ "MenuItem.foreground": ui.default,
+ "MenuItem.selectionBackground": selectedBg,
+ "MenuItem.selectionForeground": ui.default,
+ // NavBar
+ "NavBar.background": ui.uibackgroundalt,
+ "NavBar.borderColor": borderColor,
+ // Notification
+ "Notification.background": ui.uibackgroundmid,
+ "Notification.borderColor": borderColor,
+ "Notification.errorBackground": alpha(levels.danger, 0.15),
+ "Notification.errorBorderColor": levels.danger,
+ "Notification.errorForeground": ui.default,
+ "Notification.foreground": ui.default,
+ "Notification.linkForeground": ui.primary,
+ "Notification.MoreButton.background": ui.uibackgroundalt,
+ "Notification.MoreButton.foreground": ui.default,
+
+ "Notification.ToolWindow.errorBackground": alpha(levels.danger, 0.15),
+ "Notification.ToolWindow.errorBorderColor": levels.danger,
+
+ "Notification.ToolWindow.informativeBackground": alpha(levels.info, 0.15),
+ "Notification.ToolWindow.informativeBorderColor": levels.info,
+ "Notification.ToolWindow.warningBackground": alpha(levels.warning, 0.15),
+ "Notification.ToolWindow.warningBorderColor": levels.warning,
+ // Panel
+ "Panel.background": ui.uibackground,
+ "Panel.foreground": ui.default,
+
+ // ParameterInfo
+ "ParameterInfo.background": ui.uibackgroundmid,
+ "ParameterInfo.borderColor": borderColor,
+ "ParameterInfo.currentOverloadBackground": alpha(ui.primary, 0.1),
+ "ParameterInfo.currentParameterForeground": ui.primary,
+ "ParameterInfo.disabledForeground": alpha(ui.default, 0.4),
+ "ParameterInfo.foreground": ui.default,
+ // Plugins
+ "Plugins.Button.installBackground": alpha(levels.success, 0.15),
+ "Plugins.Button.installBorderColor": levels.success,
+ "Plugins.Button.installFillBackground": levels.success,
+ "Plugins.Button.installFillForeground": "#FFFFFF",
+ "Plugins.Button.installFocusedBackground": alpha(levels.success, 0.25),
+ "Plugins.Button.installForeground": levels.success,
+ "Plugins.Button.updateBackground": alpha(ui.primary, 0.15),
+ "Plugins.Button.updateBorderColor": ui.primary,
+ "Plugins.Button.updateForeground": ui.primary,
+ "Plugins.disabledForeground": alpha(ui.default, 0.4),
+ "Plugins.eapTagBackground": alpha(colors.orange, 0.2),
+ "Plugins.eapTagForeground": colors.orange,
+ "Plugins.hoverBackground": hoverBg,
+ "Plugins.lightSelectionBackground": alpha(ui.primary, 0.1),
+ "Plugins.paidTagBackground": alpha(colors.green, 0.2),
+ "Plugins.paidTagForeground": colors.green,
+ "Plugins.SearchField.background": inputBg,
+ "Plugins.SearchField.borderColor": borderColor,
+ "Plugins.SectionHeader.background": ui.uibackgroundalt,
+ "Plugins.SectionHeader.foreground": ui.default,
+ "Plugins.Tab.hoverBackground": hoverBg,
+
+ "Plugins.Tab.selectedBackground": selectedBg,
+ "Plugins.Tab.selectedForeground": ui.default,
+ "Plugins.tagBackground": alpha(ui.primary, 0.15),
+ "Plugins.tagForeground": ui.primary,
+ "Plugins.trialTagBackground": alpha(colors.purple, 0.2),
+ "Plugins.trialTagForeground": colors.purple,
+ // Popup
+ "Popup.Advertiser.background": ui.uibackgroundalt,
+ "Popup.Advertiser.borderColor": borderColor,
+ "Popup.Advertiser.borderInsets": "1,1,1,1",
+ "Popup.Advertiser.foreground": ui.defaultalt,
+ "Popup.background": ui.uibackgroundmid,
+ "Popup.borderColor": borderColor,
+
+ "Popup.Header.activeBackground": ui.uibackgroundalt,
+ "Popup.Header.inactiveBackground": ui.uibackgroundalt,
+ "Popup.inactiveBorderColor": alpha(borderColor, 0.5),
+ "Popup.Separator.foreground": borderColor,
+ "Popup.Toolbar.background": ui.uibackgroundalt,
+
+ "Popup.Toolbar.borderColor": borderColor,
+ // PopupMenu
+ "PopupMenu.background": ui.uibackgroundmid,
+ "PopupMenu.foreground": ui.default,
+ "PopupMenu.selectionBackground": selectedBg,
+ "PopupMenu.selectionForeground": ui.default,
+ "PopupMenu.translucentBackground": alpha(ui.uibackgroundmid, 0.95),
+ // ProgressBar
+ "ProgressBar.backgroundColor": ui.uibackgroundalt,
+ "ProgressBar.failedColor": levels.danger,
+ "ProgressBar.failedEndColor": c(levels.danger).lighten(0.1).toHex(),
+ "ProgressBar.foreground": ui.primary,
+ "ProgressBar.indeterminateEndColor": c(ui.primary).lighten(0.15).toHex(),
+ "ProgressBar.indeterminateStartColor": ui.primary,
+
+ "ProgressBar.passedColor": levels.success,
+ "ProgressBar.passedEndColor": c(levels.success).lighten(0.1).toHex(),
+ "ProgressBar.progressColor": ui.primary,
+ "ProgressBar.selectionBackground": ui.uibackgroundalt,
+ "ProgressBar.selectionForeground": ui.default,
+ "ProgressBar.trackColor": ui.uibackgroundalt,
+ // RadioButton (JDK Swing component)
+ "RadioButton.background": ui.uibackground,
+ "RadioButton.disabledText": alpha(ui.default, 0.4),
+ "RadioButton.foreground": ui.default,
+ // RunWidget
+ "RunWidget.background": ui.uibackgroundalt,
+ "RunWidget.foreground": ui.default,
+
+ "RunWidget.hoverBackground": hoverBg,
+ "RunWidget.iconColor": levels.success,
+ "RunWidget.runningBackground": alpha(levels.success, 0.15),
+ "RunWidget.runningForeground": ui.default,
+ "RunWidget.runningHoverBackground": alpha(levels.success, 0.25),
+ "RunWidget.runningIconColor": levels.success,
+ "RunWidget.stopBackground": alpha(levels.danger, 0.15),
+ "RunWidget.stopForeground": ui.default,
+ "RunWidget.stopHoverBackground": alpha(levels.danger, 0.25),
+ // ScrollBar
+ "ScrollBar.background": transparent(ui.uibackground),
+ "ScrollBar.hoverThumbColor": alpha(ui.default, 0.3),
+ "ScrollBar.hoverTrackColor": transparent(ui.uibackground),
+ "ScrollBar.Mac.hoverThumbBorderColor": transparent(ui.uibackground),
+ "ScrollBar.Mac.hoverThumbColor": alpha(ui.default, 0.3),
+ "ScrollBar.Mac.hoverTrackColor": transparent(ui.uibackground),
+ "ScrollBar.Mac.thumbBorderColor": transparent(ui.uibackground),
+ "ScrollBar.Mac.thumbColor": alpha(ui.default, 0.15),
+ "ScrollBar.Mac.trackColor": transparent(ui.uibackground),
+ "ScrollBar.Mac.Transparent.hoverThumbBorderColor":
+ transparent(ui.uibackground),
+ "ScrollBar.Mac.Transparent.hoverThumbColor": alpha(ui.default, 0.3),
+ "ScrollBar.Mac.Transparent.hoverTrackColor": transparent(ui.uibackground),
+ "ScrollBar.Mac.Transparent.thumbBorderColor": transparent(ui.uibackground),
+
+ "ScrollBar.Mac.Transparent.thumbColor": alpha(ui.default, 0.15),
+ "ScrollBar.Mac.Transparent.trackColor": transparent(ui.uibackground),
+ "ScrollBar.thumbColor": alpha(ui.default, 0.15),
+ "ScrollBar.track": transparent(ui.uibackground),
+ "ScrollBar.trackColor": transparent(ui.uibackground),
+ "ScrollBar.Transparent.hoverThumbColor": alpha(ui.default, 0.3),
+ "ScrollBar.Transparent.hoverTrackColor": transparent(ui.uibackground),
+ "ScrollBar.Transparent.thumbColor": alpha(ui.default, 0.15),
+ "ScrollBar.Transparent.trackColor": transparent(ui.uibackground),
+ // SearchEverywhere
+ "SearchEverywhere.Advertiser.background": ui.uibackgroundalt,
+
+ "SearchEverywhere.Advertiser.foreground": ui.defaultalt,
+ "SearchEverywhere.background": ui.uibackgroundmid,
+ "SearchEverywhere.Header.background": ui.uibackgroundalt,
+
+ "SearchEverywhere.List.separatorColor": borderColor,
+ "SearchEverywhere.List.separatorForeground": ui.defaultalt,
+ "SearchEverywhere.SearchField.background": inputBg,
+ "SearchEverywhere.SearchField.borderColor": borderColor,
+
+ "SearchEverywhere.Tab.selectedBackground": selectedBg,
+ "SearchEverywhere.Tab.selectedForeground": ui.default,
+
+ // SearchField
+ "SearchField.background": inputBg,
+ "SearchField.errorBackground": alpha(levels.danger, 0.15),
+ "SearchField.errorForeground": levels.danger,
+ // SearchMatch
+ "SearchMatch.endBackground": alpha(colors.yellow, 0.3),
+
+ "SearchMatch.endForeground": ui.default,
+ "SearchMatch.startBackground": alpha(colors.yellow, 0.3),
+
+ "SearchMatch.startForeground": ui.default,
+
+ // SearchOption
+ "SearchOption.background": ui.uibackgroundalt,
+
+ "SearchOption.selectedBackground": selectedBg,
+ // SegmentedButton
+ "SegmentedButton.focusedSelectedButtonColor": ui.primary,
+ "SegmentedButton.selectedButtonColor": selectedBg,
+ "SegmentedButton.selectedEndBorderColor": ui.primary,
+ "SegmentedButton.selectedStartBorderColor": ui.primary,
+
+ // Separator
+ "Separator.foreground": borderColor,
+ "Separator.separatorColor": borderColor,
+ // Settings
+ "Settings.Spotlight.borderColor": ui.primary,
+ // SidePanel
+ "SidePanel.background": ui.uibackgroundalt,
+ // Slider
+ "Slider.background": ui.uibackground,
+
+ "Slider.buttonBorderColor": borderColor,
+
+ "Slider.buttonColor": ui.uibackgroundalt,
+ "Slider.tickColor": ui.defaultalt,
+ "Slider.trackColor": ui.uibackgroundalt,
+ // SpeedSearch
+ "SpeedSearch.background": ui.uibackgroundmid,
+
+ "SpeedSearch.borderColor": ui.primary,
+ "SpeedSearch.errorBackground": alpha(levels.danger, 0.15),
+ "SpeedSearch.errorBorderColor": levels.danger,
+ "SpeedSearch.foreground": ui.default,
+ // Spinner
+ "Spinner.background": inputBg,
+ // StatusBar
+ "StatusBar.background": ui.uibackgroundalt,
+ "StatusBar.borderColor": transparent(borderColor),
+ "StatusBar.hoverBackground": hoverBg,
+ "StatusBar.Widget.hoverBackground": hoverBg,
+ // TabbedPane
+ "TabbedPane.background": ui.uibackgroundalt,
+ "TabbedPane.borderColor": borderColor,
+ "TabbedPane.contentAreaColor": ui.uibackground,
+ "TabbedPane.disabled": alpha(ui.default, 0.4),
+ "TabbedPane.focus": ui.primary,
+ "TabbedPane.focusColor": alpha(ui.primary, 0.5),
+ "TabbedPane.foreground": ui.default,
+
+ "TabbedPane.hoverColor": hoverBg,
+ "TabbedPane.tabSelectionHeight": 3,
+ "TabbedPane.underlineColor": ui.primary,
+ // Table
+ "Table.alternateRowBackground": alpha(ui.uibackgroundalt, 0.5),
+ "Table.background": ui.uibackground,
+ "Table.dropLineColor": ui.primary,
+ "Table.focusCellBackground": selectedBg,
+ "Table.foreground": ui.default,
+ "Table.gridColor": borderColor,
+ "Table.hoverBackground": hoverBg,
+
+ "Table.lightSelectionBackground": alpha(ui.primary, 0.1),
+ "Table.lightSelectionForeground": ui.default,
+
+ "Table.lightSelectionInactiveBackground": alpha(ui.primary, 0.05),
+ "Table.lightSelectionInactiveForeground": ui.default,
+ "Table.selectionBackground": selectedBg,
+ "Table.selectionForeground": ui.default,
+ "Table.selectionInactiveBackground": alpha(ui.primary, 0.1),
+ "Table.selectionInactiveForeground": ui.default,
+ "Table.stripeColor": alpha(ui.uibackgroundalt, 0.5),
+
+ // Tag
+ "Tag.background": alpha(ui.primary, 0.15),
+ "Tag.foreground": ui.primary,
+ // TextArea
+ "TextArea.background": inputBg,
+ "TextArea.caretForeground": ui.primary,
+ "TextArea.foreground": ui.default,
+ "TextArea.inactiveBackground": alpha(inputBg, 0.5),
+ "TextArea.inactiveForeground": ui.defaultalt,
+ "TextArea.selectionBackground": selectedBg,
+ "TextArea.selectionForeground": ui.default,
+ // TextField
+ "TextField.background": inputBg,
+ "TextField.borderColor": borderColor,
+ "TextField.caretForeground": ui.primary,
+ "TextField.disabledBackground": alpha(inputBg, 0.5),
+
+ "TextField.focusedBorderColor": ui.primary,
+ "TextField.foreground": ui.default,
+ "TextField.highlight": selectedBg,
+ "TextField.hoverBorderColor": lightenOrDarken(borderColor, 0.1),
+ "TextField.inactiveBackground": alpha(inputBg, 0.5),
+ "TextField.inactiveForeground": ui.defaultalt,
+ "TextField.placeholderForeground": ui.defaultalt,
+
+ "TextField.selectionBackground": selectedBg,
+ "TextField.selectionForeground": ui.default,
+ // TitlePane
+ "TitlePane.background": ui.uibackgroundalt,
+ "TitlePane.Button.hoverBackground": hoverBg,
+ "TitlePane.foreground": ui.default,
+ "TitlePane.fullScreen.background": ui.uibackgroundalt,
+ "TitlePane.inactiveBackground": ui.uibackgroundalt,
+ "TitlePane.inactiveForeground": ui.defaultalt,
+
+ "TitlePane.infoForeground": ui.defaultalt,
+ // ToggleButton
+ "ToggleButton.background": ui.uibackgroundalt,
+ "ToggleButton.borderColor": borderColor,
+ "ToggleButton.buttonColor": ui.default,
+ "ToggleButton.disabledBorderColor": alpha(borderColor, 0.5),
+
+ "ToggleButton.offBackground": ui.uibackgroundalt,
+ "ToggleButton.offForeground": ui.defaultalt,
+ "ToggleButton.onBackground": ui.primary,
+ "ToggleButton.onForeground": light
+ ? "#FFFFFF"
+ : c(ui.primary).isDark()
+ ? "#FFFFFF"
+ : "#000000",
+ // ToolBar
+ "ToolBar.background": ui.uibackgroundalt,
+ "ToolBar.borderHandleColor": borderColor,
+ "ToolBar.floatingBackground": ui.uibackgroundmid,
+ "ToolBar.foreground": ui.default,
+ "ToolBar.separatorColor": borderColor,
+
+ // ToolTip
+ "ToolTip.Actions.background": ui.uibackgroundalt,
+ "ToolTip.Actions.foreground": ui.default,
+ "ToolTip.Actions.Info.foreground": ui.defaultalt,
+ "ToolTip.background": ui.uibackgroundmid,
+ "ToolTip.borderColor": borderColor,
+ "ToolTip.foreground": ui.default,
+ "ToolTip.infoForeground": ui.defaultalt,
+ "ToolTip.separatorColor": borderColor,
+ "ToolTip.shortcutForeground": ui.defaultalt,
+ // ToolWindow
+ "ToolWindow.background": ui.uibackground,
+ "ToolWindow.Button.hoverBackground": hoverBg,
+ "ToolWindow.Button.selectedBackground": selectedBg,
+ "ToolWindow.Button.selectedForeground": ui.default,
+ "ToolWindow.Header.background": ui.uibackgroundalt,
+ "ToolWindow.Header.borderColor": borderColor,
+ "ToolWindow.Header.closeButton.background": transparent(ui.uibackground),
+ "ToolWindow.Header.inactiveBackground": ui.uibackgroundalt,
+ "ToolWindow.HeaderCloseButton.background": transparent(ui.uibackground),
+ "ToolWindow.HeaderTab.hoverBackground": hoverBg,
+ "ToolWindow.HeaderTab.hoverInactiveBackground": hoverBg,
+ "ToolWindow.HeaderTab.selectedBackground": ui.uibackground,
+
+ "ToolWindow.HeaderTab.selectedInactiveBackground": ui.uibackgroundmid,
+ "ToolWindow.HeaderTab.underlineColor": ui.primary,
+ "ToolWindow.HeaderTab.underlinedTabBackground": ui.uibackground,
+ "ToolWindow.HeaderTab.underlinedTabForeground": ui.default,
+ "ToolWindow.HeaderTab.underlinedTabInactiveBackground": ui.uibackgroundmid,
+ "ToolWindow.HeaderTab.underlinedTabInactiveForeground": ui.defaultalt,
+ "ToolWindow.HeaderTab.underlineHeight": 3,
+
+ "ToolWindow.Stripe.background": ui.uibackgroundalt,
+ "ToolWindow.Stripe.borderColor": transparent(borderColor),
+
+ // Tree
+ "Tree.background": ui.uibackground,
+ "Tree.errorForeground": levels.danger,
+ "Tree.foreground": ui.default,
+ "Tree.hoverBackground": hoverBg,
+ "Tree.modifiedItemForeground": levels.info,
+ "Tree.rowHeight": 24,
+ "Tree.selectionBackground": selectedBg,
+ "Tree.selectionForeground": ui.default,
+ "Tree.selectionInactiveBackground": alpha(ui.primary, 0.1),
+
+ // ValidationTooltip
+ "ValidationTooltip.errorBackground": alpha(levels.danger, 0.15),
+ "ValidationTooltip.errorBorderColor": levels.danger,
+ "ValidationTooltip.warningBackground": alpha(levels.warning, 0.15),
+ "ValidationTooltip.warningBorderColor": levels.warning,
+
+ // VersionControl
+ "VersionControl.FileHistory.Commit.otherBranchBackground":
+ alpha(colors.purple, 0.1),
+ "VersionControl.FileHistory.Commit.selectedBranchBackground":
+ alpha(ui.primary, 0.1),
+ "VersionControl.GitCommits.graphColor": ui.primary,
+ "VersionControl.GitLog.headIconColor": colors.yellow,
+ "VersionControl.GitLog.localBranchIconColor": colors.green,
+ "VersionControl.GitLog.otherIconColor": colors.purple,
+ "VersionControl.GitLog.remoteBranchIconColor": colors.turquoize,
+ "VersionControl.GitLog.tagIconColor": colors.yellow,
+ "VersionControl.HgLog.bookmarkIconColor": colors.green,
+ "VersionControl.HgLog.branchIconColor": colors.turquoize,
+ "VersionControl.HgLog.closedBranchIconColor": alpha(colors.turquoize, 0.5),
+ "VersionControl.HgLog.headIconColor": colors.yellow,
+ "VersionControl.HgLog.localTagIconColor": colors.orange,
+ "VersionControl.HgLog.mqTagIconColor": colors.purple,
+ "VersionControl.HgLog.tagIconColor": colors.yellow,
+ "VersionControl.HgLog.tipIconColor": colors.pink,
+ "VersionControl.Log.Commit.currentBranchBackground": alpha(ui.primary, 0.1),
+ "VersionControl.Log.Commit.hoveredBackground": hoverBg,
+ "VersionControl.Log.Commit.unmatchedForeground": ui.defaultalt,
+ "VersionControl.Ref.background": alpha(ui.primary, 0.15),
+ "VersionControl.Ref.backgroundBase": ui.uibackgroundalt,
+ "VersionControl.RefLabel.background": alpha(ui.primary, 0.15),
+ "VersionControl.RefLabel.backgroundBase": ui.uibackgroundalt,
+ "VersionControl.RefLabel.foreground": ui.default,
+
+ // WelcomeScreen
+ "WelcomeScreen.background": ui.uibackground,
+ "WelcomeScreen.borderColor": borderColor,
+ "WelcomeScreen.captionBackground": ui.uibackgroundalt,
+ "WelcomeScreen.captionForeground": ui.default,
+ "WelcomeScreen.Details.background": ui.uibackgroundalt,
+ "WelcomeScreen.footerBackground": ui.uibackgroundalt,
+ "WelcomeScreen.footerForeground": ui.defaultalt,
+ "WelcomeScreen.groupIconBorderColor": borderColor,
+ "WelcomeScreen.headerBackground": ui.uibackgroundalt,
+ "WelcomeScreen.headerForeground": ui.default,
+ "WelcomeScreen.Projects.actions.background": ui.uibackgroundalt,
+ "WelcomeScreen.Projects.actions.selectionBackground": selectedBg,
+ "WelcomeScreen.Projects.background": ui.uibackground,
+ "WelcomeScreen.Projects.selectionBackground": selectedBg,
+ "WelcomeScreen.Projects.selectionInactiveBackground":
+ alpha(ui.primary, 0.1),
+ "WelcomeScreen.separatorColor": borderColor,
+ "WelcomeScreen.SidePanel.background": ui.uibackgroundalt,
+
+ // Window
+ "window.border": hc ? ui.default : borderColor,
+ };
+}
diff --git a/src/generators/jetbrains/utils.ts b/src/generators/jetbrains/utils.ts
new file mode 100644
index 00000000..a6411b97
--- /dev/null
+++ b/src/generators/jetbrains/utils.ts
@@ -0,0 +1,173 @@
+/**
+ * JetBrains Theme Utility Functions
+ *
+ * Helper functions for color manipulation and formatting
+ * specific to JetBrains theme requirements.
+ */
+
+import { colord as c } from "colord";
+
+/**
+ * Darken a color and return JetBrains-compatible hex
+ *
+ * @param hex - Input color
+ * @param amount - Amount to darken (0-1)
+ * @returns 6-digit hex string without #
+ */
+export function darken(hex: string, amount: number): string {
+ return toHex(c(hex).darken(amount).toHex());
+}
+
+/**
+ * Get a contrasting foreground color (black or white)
+ *
+ * @param background - Background color
+ * @returns "000000" or "FFFFFF"
+ */
+export function getContrastForeground(background: string): string {
+ return isLight(background) ? "000000" : "FFFFFF";
+}
+
+/**
+ * Generate plugin-compatible theme ID
+ *
+ * @param slug - Theme slug
+ * @returns Theme ID for plugin.xml
+ */
+export function getThemeId(slug: string): string {
+ return `bearded-theme-${slug}`;
+}
+
+/**
+ * Generate theme file path for plugin references
+ *
+ * @param slug - Theme slug
+ * @returns Path relative to resources folder
+ */
+export function getThemePath(slug: string): string {
+ return `/themes/bearded-theme-${slug}.theme.json`;
+}
+
+/**
+ * Determine if a color is considered "light"
+ * Useful for deciding contrast colors
+ *
+ * @param hex - Color to check
+ * @returns true if the color is light
+ */
+export function isLight(hex: string): boolean {
+ return c(hex).isLight();
+}
+
+/**
+ * Lighten a color and return JetBrains-compatible hex
+ *
+ * @param hex - Input color
+ * @param amount - Amount to lighten (0-1)
+ * @returns 6-digit hex string without #
+ */
+export function lighten(hex: string, amount: number): string {
+ return toHex(c(hex).lighten(amount).toHex());
+}
+
+/**
+ * Mix two colors and return JetBrains-compatible hex
+ *
+ * @param color1 - First color
+ * @param color2 - Second color
+ * @param ratio - Mix ratio (0 = color1, 1 = color2)
+ * @returns 6-digit hex string without #
+ */
+export function mixColors(
+ color1: string,
+ color2: string,
+ ratio: number = 0.5,
+): string {
+ return toHex(c(color1).mix(color2, ratio).toHex());
+}
+
+/**
+ * Adjust color saturation and return JetBrains-compatible hex
+ *
+ * @param hex - Input color
+ * @param amount - Positive to saturate, negative to desaturate
+ * @returns 6-digit hex string without #
+ */
+export function saturate(hex: string, amount: number): string {
+ if (amount >= 0) {
+ return toHex(c(hex).saturate(amount).toHex());
+ }
+ return toHex(c(hex).desaturate(Math.abs(amount)).toHex());
+}
+
+/**
+ * Escape a theme name to create a valid file slug
+ *
+ * @param name - Theme display name
+ * @returns Sanitized slug for filename
+ */
+export function slugify(name: string): string {
+ return name
+ .toLowerCase()
+ .replace(/\s+/g, "-")
+ .replace(/&/g, "and")
+ .replace(/[^a-z0-9-]/g, "");
+}
+
+/**
+ * Convert a hex color to JetBrains format (6-digit RGB without #)
+ * JetBrains uses RRGGBB format for colors in theme.json
+ *
+ * @param hex - Hex color string (e.g., "#FF5370" or "#FF537080")
+ * @returns 6-digit hex string without # (e.g., "FF5370")
+ */
+export function toHex(hex: string): string {
+ const color = c(hex);
+ // Get RGB hex without alpha
+ return color.toHex().replace("#", "").substring(0, 6).toUpperCase();
+}
+
+/**
+ * Convert a hex color with alpha to JetBrains 8-digit RRGGBBAA format
+ *
+ * @param hex - Hex color string
+ * @param alpha - Alpha value (0-1)
+ * @returns 8-digit hex string without # (e.g., "FF537080")
+ */
+export function toHexAlpha(hex: string, alpha: number): string {
+ const color = c(hex).alpha(alpha);
+ const rgbHex = color.toHex().replace("#", "").toUpperCase();
+
+ // Ensure we have 8 characters (RRGGBBAA)
+ if (rgbHex.length === 6) {
+ const alphaHex = Math.round(alpha * 255)
+ .toString(16)
+ .padStart(2, "0")
+ .toUpperCase();
+ return rgbHex + alphaHex;
+ }
+
+ return rgbHex;
+}
+
+/**
+ * Generate a fully transparent color (for hiding elements)
+ *
+ * @param hex - Base color (only RGB will be used)
+ * @returns 8-digit hex with # prefix and 00 alpha (e.g., "#1C243300")
+ */
+export function transparent(hex: string): string {
+ return "#" + toHex(hex) + "00";
+}
+
+/**
+ * Create a transparent version of a color for JetBrains
+ * Returns full 8-digit RRGGBBAA format
+ *
+ * @param hex - Input color
+ * @param alpha - Alpha value (0-1)
+ * @returns 8-digit hex string without # (e.g., "FF537080")
+ */
+export function withAlpha(hex: string, alpha: number): string {
+ return toHexAlpha(hex, alpha);
+}
diff --git a/src/generators/vscode/index.ts b/src/generators/vscode/index.ts
index b2c71a9f..658d7fe0 100644
--- a/src/generators/vscode/index.ts
+++ b/src/generators/vscode/index.ts
@@ -1,6 +1,7 @@
import { mkdirSync, writeFile, writeFileSync } from "fs";
import { dirname } from "path";
+import { Meta } from "../../shared/meta";
import {
getVscodeUiTheme,
themeRegistry,
@@ -45,8 +46,8 @@ function generateThemeContributes(): Array<{
uiTheme: string;
}> {
return themeRegistry.map((entry) => ({
- label: `Bearded Theme ${entry.name}`,
- path: `./dist/vscode/themes/bearded-theme-${entry.slug}.json`,
+ label: `${Meta.name} ${entry.name}`,
+ path: `./dist/vscode/themes/${Meta.slug}-${entry.slug}.json`,
uiTheme: getVscodeUiTheme(entry.options),
}));
}
@@ -61,13 +62,13 @@ async function makeVscodeTheme(entry: ThemeRegistryEntry): Promise {
const themeTemplate = {
$schema: "vscode://schemas/color-theme",
colors: ui(theme, hc, light, untindedSelection, desaturateInputs),
- name: `BeardedTheme ${name}`,
+ name: `${Meta.name} ${name}`,
semanticHighlighting: true,
semanticTokenColors: semanticTokens(theme),
tokenColors: syntax(theme, hc, light),
};
- const outputPath = `${OUTPUT_DIR}/bearded-theme-${slug}.json`;
+ const outputPath = `${OUTPUT_DIR}/${Meta.slug}-${slug}.json`;
// Ensure directory exists
mkdirSync(dirname(outputPath), { recursive: true });
diff --git a/src/generators/zed/index.ts b/src/generators/zed/index.ts
index b9379ad4..f4326bc0 100644
--- a/src/generators/zed/index.ts
+++ b/src/generators/zed/index.ts
@@ -1,6 +1,7 @@
import { copyFileSync, mkdirSync, writeFileSync } from "fs";
import { join } from "path";
+import { Meta } from "../../shared/meta";
import {
getZedAppearance,
themeRegistry,
@@ -30,8 +31,8 @@ async function buildZedThemes(): Promise {
// Create the theme family with all themes
const themeFamily: ZedThemeFamily = {
$schema: "https://zed.dev/schema/themes/v0.2.0.json",
- author: "BeardedBear",
- name: "Bearded Theme",
+ author: Meta.author.name,
+ name: Meta.name,
themes: themeRegistry.map(createZedTheme),
};
@@ -43,13 +44,13 @@ async function buildZedThemes(): Promise {
);
// Generate extension.toml with synced version
- const extensionToml = `id = "bearded-theme"
-name = "Bearded Theme"
-description = "The theme with a long beard."
+ const extensionToml = `id = "${Meta.slug}"
+name = "${Meta.name}"
+description = "${Meta.description}"
version = "${version}"
schema_version = 1
-authors = ["BeardedBear "]
-repository = "https://github.com/BeardedBear/bearded-theme"
+authors = ["${Meta.author.name} <${Meta.author.email}>"]
+repository = "${Meta.urls.github}"
`;
writeFileSync(`${ZED_DIR}/extension.toml`, extensionToml, {
@@ -69,34 +70,34 @@ repository = "https://github.com/BeardedBear/bearded-theme"
}
// Generate README for Zed extension
- const readmeContent = `# Bearded Theme for Zed
+ const readmeContent = `# ${Meta.name} for Zed
-The theme with a long beard.
+${Meta.description}
## Installation
1. Open Zed
2. Open the Extensions panel (\`cmd+shift+x\` or \`ctrl+shift+x\`)
-3. Search for "Bearded Theme"
+3. Search for "${Meta.name}"
4. Click Install
## Available Themes
-${themeRegistry.map((entry) => `- Bearded Theme ${entry.name}`).join("\n")}
+${themeRegistry.map((entry) => `- ${Meta.name} ${entry.name}`).join("\n")}
## Links
-- [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=BeardedBear.beardedtheme)
-- [GitHub Repository](https://github.com/BeardedBear/bearded-theme)
-- [Report Issues](https://github.com/BeardedBear/bearded-theme/issues)
+- [VS Code Extension](${Meta.urls.marketplace.vscode})
+- [GitHub Repository](${Meta.urls.github})
+- [Report Issues](${Meta.urls.issues})
## License
-GNU General Public License v3.0
+${Meta.license}
## Author
-Made with ❤️ by [BeardedBear](https://github.com/BeardedBear)
+Made with ❤️ by [${Meta.author.name}](https://github.com/${Meta.author.name})
`;
writeFileSync(`${ZED_DIR}/README.md`, readmeContent, { encoding: "utf8" });
@@ -115,7 +116,7 @@ Made with ❤️ by [BeardedBear](https://github.com/BeardedBear)
function createZedTheme(entry: ThemeRegistryEntry): ZedTheme {
return {
appearance: getZedAppearance(entry.options),
- name: `Bearded Theme ${entry.name}`,
+ name: `${Meta.name} ${entry.name}`,
style: buildZedThemeStyle(entry.theme, entry.options),
};
}
diff --git a/src/shared/meta.ts b/src/shared/meta.ts
new file mode 100644
index 00000000..4cd62cab
--- /dev/null
+++ b/src/shared/meta.ts
@@ -0,0 +1,67 @@
+export const Meta = {
+ author: {
+ email: "beardedbearbear@gmail.com",
+ name: "BeardedBear",
+ url: "https://github.com/BeardedBear/bearded-theme",
+ },
+ categories: [
+ {
+ description: "Clean, modern dark themes",
+ name: "Arc",
+ },
+ {
+ description: "Classic solarized color schemes",
+ name: "Solarized",
+ },
+ {
+ description: "Ocean-inspired color palettes",
+ name: "Oceanic",
+ },
+ {
+ description: "Monokai-inspired variants",
+ name: "Monokai",
+ },
+ {
+ description: "Pure black backgrounds with gem accent colors",
+ name: "Black & Gems",
+ },
+ {
+ description: "Accessibility-focused themes",
+ name: "High Contrast (HC)",
+ },
+ {
+ description: "Soft, pastel light themes",
+ name: "Milkshake",
+ },
+ {
+ description: "Warm, earthy tones",
+ name: "Coffee",
+ },
+ {
+ description: "Vibrant, saturated colors",
+ name: "Vivid",
+ },
+ {
+ description: "Watercolor-inspired themes",
+ name: "Aquarelle",
+ },
+ {
+ description: "Unique, unexpected color combinations",
+ name: "Surprising",
+ },
+ ],
+ description: "The theme with a long beard.",
+ license: "GNU General Public License v3.0",
+ name: "Bearded Theme",
+ slug: "bearded-theme",
+ urls: {
+ github: "https://github.com/BeardedBear/bearded-theme",
+ issues: "https://github.com/BeardedBear/bearded-theme/issues",
+ marketplace: {
+ jetbrains: "https://plugins.jetbrains.com/plugin/19438-bearded-theme",
+ openVsx: "https://open-vsx.org/extension/BeardedBear/beardedtheme",
+ vscode:
+ "https://marketplace.visualstudio.com/items?itemName=BeardedBear.beardedtheme",
+ },
+ },
+};
diff --git a/src/version-manager.ts b/src/version-manager.ts
index a9fda3c9..31b0ea98 100644
--- a/src/version-manager.ts
+++ b/src/version-manager.ts
@@ -5,6 +5,7 @@ import { join } from "path";
* Configuration interface for IDE versions
*/
export interface VersionConfig {
+ jetbrains: string;
vscode: string;
zed: string;
}
@@ -16,6 +17,14 @@ export function getAllVersions(): VersionConfig {
return getVersionConfig();
}
+/**
+ * Get JetBrains version from versions.json
+ */
+export function getJetBrainsVersion(): string {
+ const config = getVersionConfig();
+ return config.jetbrains;
+}
+
/**
* Get version from package.json (for backwards compatibility)
*/
@@ -62,6 +71,7 @@ function getVersionConfig(): VersionConfig {
error,
);
return {
+ jetbrains: "1.0.0",
vscode: "1.0.0",
zed: "1.0.0",
};
diff --git a/versions.json b/versions.json
index b7a55a98..9922f36b 100644
--- a/versions.json
+++ b/versions.json
@@ -1,4 +1,5 @@
{
"vscode": "11.0.0",
- "zed": "1.0.0"
+ "zed": "1.0.0",
+ "jetbrains": "1.0.0"
}