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(``; + }; + + // 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]) => `