From ccf3962332aca88533123b366451cb2d88c69797 Mon Sep 17 00:00:00 2001 From: Kyle Reddoch Date: Wed, 23 Sep 2026 16:48:19 -0500 Subject: [PATCH] feat: add native Xcode 27 workspace themes --- .github/workflows/native-check.yml | 24 + .gitignore | 1 + README.md | 10 + docs/xcode-27-import-results.json | 365 ++++++++++ docs/xcode-27.md | 64 ++ native/LICENSE | 21 + native/coverage.json | 423 ++++++++++++ native/mapping.json | 40 ++ native/supplemental-colors.json | 26 + scripts/generate_native.py | 109 +++ tests/test_native.py | 91 +++ ...uccin Frapp\303\251.xcworkspacecolortheme" | 625 ++++++++++++++++++ .../Catppuccin Latte.xcworkspacecolortheme | 625 ++++++++++++++++++ ...Catppuccin Macchiato.xcworkspacecolortheme | 625 ++++++++++++++++++ .../Catppuccin Mocha.xcworkspacecolortheme | 625 ++++++++++++++++++ 15 files changed, 3674 insertions(+) create mode 100644 .github/workflows/native-check.yml create mode 100644 .gitignore create mode 100644 docs/xcode-27-import-results.json create mode 100644 docs/xcode-27.md create mode 100644 native/LICENSE create mode 100644 native/coverage.json create mode 100644 native/mapping.json create mode 100644 native/supplemental-colors.json create mode 100644 scripts/generate_native.py create mode 100644 tests/test_native.py create mode 100644 "themes/xcode-27/Catppuccin Frapp\303\251.xcworkspacecolortheme" create mode 100644 themes/xcode-27/Catppuccin Latte.xcworkspacecolortheme create mode 100644 themes/xcode-27/Catppuccin Macchiato.xcworkspacecolortheme create mode 100644 themes/xcode-27/Catppuccin Mocha.xcworkspacecolortheme diff --git a/.github/workflows/native-check.yml b/.github/workflows/native-check.yml new file mode 100644 index 0000000..c256925 --- /dev/null +++ b/.github/workflows/native-check.yml @@ -0,0 +1,24 @@ +name: native themes + +on: + workflow_dispatch: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: '3.11' + - name: Check native generation + run: python3 scripts/generate_native.py --check + - name: Check palette fidelity and legacy coverage + run: python3 -m unittest discover -s tests -v diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c18dd8d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/README.md b/README.md index 4b16697..2109182 100644 --- a/README.md +++ b/README.md @@ -36,12 +36,22 @@ ## Usage +### Xcode 27 + +1. Copy your preferred `.xcworkspacecolortheme` files from [`themes/xcode-27/`](./themes/xcode-27/) to `~/Library/Developer/Xcode/UserData/FontAndColorThemes/`. Create the folder if needed and back up any existing files with the same names. +2. Open **Xcode → Settings → Appearance → Theme → Choose…** and select your theme. Use Light appearance for Latte and Dark for the other flavors. Restart Xcode if the new themes are not listed. + +These native themes preserve exact palette values and leave fonts and cursor shape unchanged. Copy the files directly rather than using the classic-theme importer. See [Xcode 27 compatibility, coverage and development notes](docs/xcode-27.md) for tested builds and remaining limitations. The previews above show the existing legacy themes. + +### Earlier Xcode versions + 1. Copy your preferred flavor(s) from [`themes/`](./themes/) to `~/Library/Developer/Xcode/UserData/FontAndColorThemes`. 2. Go to **Xcode** > **Preferences** (Command + ,), choose the **Themes** tab, and select your desired Catppuccin theme. ## 💝 Thanks to - [Quentin](https://github.com/quentinguidee) +- [Kyle Reddoch](https://github.com/kylereddoch) — native Xcode 27 themes   diff --git a/docs/xcode-27-import-results.json b/docs/xcode-27-import-results.json new file mode 100644 index 0000000..3b60be6 --- /dev/null +++ b/docs/xcode-27-import-results.json @@ -0,0 +1,365 @@ +{ + "date": "2026-09-23", + "xcode": "27.1", + "xcode_build": "27A9269", + "macos": "27.2", + "macos_build": "26B5091g", + "method": "Settings > Appearance > Theme > Choose > Import; colors enabled, fonts and cursor shape disabled. Native files copied into FontAndColorThemes and selected in Choose.", + "upstream_revision": "e3816a60caaf9889b81866924fd6ef0a4e2ad571", + "flavors": { + "latte": { + "legacy_import_succeeded": true, + "legacy_converted_colors": { + "background": "#f2f4f7", + "comment": "#8f92a4", + "currentLineHighlight": "#d5d9e1", + "insertionPointColor": "#7f8397", + "invisibles": "#babeca", + "keyword": "#9b59f2", + "keyword.attribute": "#0ea2aa", + "link": "#247ff7", + "markdown": "#8f92a4", + "memberDeclaration": "#5e637c", + "number": "#1007a05", + "number.character": "#4dac38", + "otherMember": "#247ff7", + "otherMember.constant": "#1007a05", + "otherMember.function": "#247ff7", + "otherMember.variable": "#5e637c", + "otherType": "#e79f25", + "otherType.class": "#e79f25", + "otherType.type": "#e79f25", + "plainText": "#5e637c", + "preprocessor": "#0ea2aa", + "preprocessor.macro": "#247ff7", + "preprocessor.macroSystem": "#247ff7", + "projectMember": "#247ff7", + "projectMember.constant": "#1007a05", + "projectMember.function": "#247ff7", + "projectMember.variable": "#5e637c", + "projectType": "#e79f25", + "projectType.class": "#e79f25", + "projectType.type": "#e79f25", + "selectedTextBackgroundColor": "#c8ccd6", + "string": "#4dac38", + "string.regex": "#f08fd5", + "typeDeclaration": "#e79f25" + }, + "native_file_colors": { + "background": "#eff1f5", + "plainText": "#4c4f69", + "comment": "#7c7f93", + "commentEmphasized": "#7c7f93", + "markdown": "#7c7f93", + "markdownEmphasized": "#7c7f93", + "keyword": "#8839ef", + "keyword.attribute": "#179299", + "string": "#40a02b", + "string.regex": "#ea76cb", + "number": "#fe640b", + "number.character": "#40a02b", + "link": "#1e66f5", + "preprocessor": "#179299", + "preprocessor.macro": "#1e66f5", + "preprocessor.macroSystem": "#1e66f5", + "typeDeclaration": "#df8e1d", + "memberDeclaration": "#4c4f69", + "projectType": "#df8e1d", + "projectType.class": "#df8e1d", + "projectType.type": "#df8e1d", + "projectMember": "#1e66f5", + "projectMember.function": "#1e66f5", + "projectMember.constant": "#fe640b", + "projectMember.variable": "#4c4f69", + "otherType": "#df8e1d", + "otherType.class": "#df8e1d", + "otherType.type": "#df8e1d", + "otherMember": "#1e66f5", + "otherMember.function": "#1e66f5", + "otherMember.constant": "#fe640b", + "otherMember.variable": "#4c4f69", + "selectedTextBackgroundColor": "#bcc0cc", + "insertionPointColor": "#6c6f85", + "currentLineHighlight": "#ccd0da", + "invisibles": "#acb0be", + "diffAddition": "#40a02b", + "diffDeletion": "#d20f39", + "debugger": "#40a02b" + }, + "native_ui_spot_checks": { + "plainText": "#4c4f69", + "debugger": "#40a02b", + "keyword": "#8839ef", + "keyword.attribute": "#179299", + "string": "#40a02b", + "string.regex": "#ea76cb", + "number": "#fe640b", + "number.character": "#40a02b", + "link": "#1e66f5", + "preprocessor": "#179299", + "preprocessor.macro": "#1e66f5", + "preprocessor.macroSystem": "#1e66f5", + "typeDeclaration": "#df8e1d" + } + }, + "frappe": { + "legacy_import_succeeded": true, + "legacy_converted_colors": { + "background": "#3f4458", + "comment": "#a5adc7", + "currentLineHighlight": "#52586c", + "insertionPointColor": "#b4bcd7", + "invisibles": "#757c92", + "keyword": "#d5b1eb", + "keyword.attribute": "#91d1ca", + "link": "#9dbaf2", + "markdown": "#a5adc7", + "memberDeclaration": "#d0daf7", + "number": "#f4af89", + "number.character": "#b4d79b", + "otherMember": "#9dbaf2", + "otherMember.constant": "#f4af89", + "otherMember.function": "#9dbaf2", + "otherMember.variable": "#d0daf7", + "otherType": "#ebd1a1", + "otherType.class": "#ebd1a1", + "otherType.type": "#ebd1a1", + "plainText": "#d0daf7", + "preprocessor": "#91d1ca", + "preprocessor.macro": "#9dbaf2", + "preprocessor.macroSystem": "#9dbaf2", + "projectMember": "#9dbaf2", + "projectMember.constant": "#f4af89", + "projectMember.function": "#9dbaf2", + "projectMember.variable": "#d0daf7", + "projectType": "#ebd1a1", + "projectType.class": "#ebd1a1", + "projectType.type": "#ebd1a1", + "selectedTextBackgroundColor": "#646b80", + "string": "#b4d79b", + "string.regex": "#f7c7e9", + "typeDeclaration": "#ebd1a1" + }, + "native_file_colors": { + "background": "#303446", + "plainText": "#c6d0f5", + "comment": "#949cbb", + "commentEmphasized": "#949cbb", + "markdown": "#949cbb", + "markdownEmphasized": "#949cbb", + "keyword": "#ca9ee6", + "keyword.attribute": "#81c8be", + "string": "#a6d189", + "string.regex": "#f4b8e4", + "number": "#ef9f76", + "number.character": "#a6d189", + "link": "#8caaee", + "preprocessor": "#81c8be", + "preprocessor.macro": "#8caaee", + "preprocessor.macroSystem": "#8caaee", + "typeDeclaration": "#e5c890", + "memberDeclaration": "#c6d0f5", + "projectType": "#e5c890", + "projectType.class": "#e5c890", + "projectType.type": "#e5c890", + "projectMember": "#8caaee", + "projectMember.function": "#8caaee", + "projectMember.constant": "#ef9f76", + "projectMember.variable": "#c6d0f5", + "otherType": "#e5c890", + "otherType.class": "#e5c890", + "otherType.type": "#e5c890", + "otherMember": "#8caaee", + "otherMember.function": "#8caaee", + "otherMember.constant": "#ef9f76", + "otherMember.variable": "#c6d0f5", + "selectedTextBackgroundColor": "#51576d", + "insertionPointColor": "#a5adce", + "currentLineHighlight": "#414559", + "invisibles": "#626880", + "diffAddition": "#a6d189", + "diffDeletion": "#e78284", + "debugger": "#a6d189" + }, + "native_ui_spot_checks": { + "plainText": "#c6d0f5", + "debugger": "#a6d189" + } + }, + "macchiato": { + "legacy_import_succeeded": true, + "legacy_converted_colors": { + "background": "#30354b", + "comment": "#a4abc4", + "currentLineHighlight": "#464b62", + "insertionPointColor": "#b4bcd5", + "invisibles": "#6e748b", + "keyword": "#d1b3f8", + "keyword.attribute": "#9bdcd4", + "link": "#9bbdf6", + "markdown": "#a4abc4", + "memberDeclaration": "#d4dcf7", + "number": "#f8b891", + "number.character": "#b4dfa6", + "otherMember": "#9bbdf6", + "otherMember.constant": "#f8b891", + "otherMember.function": "#9bbdf6", + "otherMember.variable": "#d4dcf7", + "otherType": "#f2dbaf", + "otherType.class": "#f2dbaf", + "otherType.type": "#f2dbaf", + "plainText": "#d4dcf7", + "preprocessor": "#9bdcd4", + "preprocessor.macro": "#9bbdf6", + "preprocessor.macroSystem": "#9bbdf6", + "projectMember": "#9bbdf6", + "projectMember.constant": "#f8b891", + "projectMember.function": "#9bbdf6", + "projectMember.variable": "#d4dcf7", + "projectType": "#f2dbaf", + "projectType.class": "#f2dbaf", + "projectType.type": "#f2dbaf", + "selectedTextBackgroundColor": "#5b6077", + "string": "#b4dfa6", + "string.regex": "#f8cbeb", + "typeDeclaration": "#f2dbaf" + }, + "native_file_colors": { + "background": "#24273a", + "plainText": "#cad3f5", + "comment": "#939ab7", + "commentEmphasized": "#939ab7", + "markdown": "#939ab7", + "markdownEmphasized": "#939ab7", + "keyword": "#c6a0f6", + "keyword.attribute": "#8bd5ca", + "string": "#a6da95", + "string.regex": "#f5bde6", + "number": "#f5a97f", + "number.character": "#a6da95", + "link": "#8aadf4", + "preprocessor": "#8bd5ca", + "preprocessor.macro": "#8aadf4", + "preprocessor.macroSystem": "#8aadf4", + "typeDeclaration": "#eed49f", + "memberDeclaration": "#cad3f5", + "projectType": "#eed49f", + "projectType.class": "#eed49f", + "projectType.type": "#eed49f", + "projectMember": "#8aadf4", + "projectMember.function": "#8aadf4", + "projectMember.constant": "#f5a97f", + "projectMember.variable": "#cad3f5", + "otherType": "#eed49f", + "otherType.class": "#eed49f", + "otherType.type": "#eed49f", + "otherMember": "#8aadf4", + "otherMember.function": "#8aadf4", + "otherMember.constant": "#f5a97f", + "otherMember.variable": "#cad3f5", + "selectedTextBackgroundColor": "#494d64", + "insertionPointColor": "#a5adcb", + "currentLineHighlight": "#363a4f", + "invisibles": "#5b6078", + "diffAddition": "#a6da95", + "diffDeletion": "#ed8796", + "debugger": "#a6da95" + }, + "native_ui_spot_checks": { + "plainText": "#cad3f5", + "debugger": "#a6da95" + } + }, + "mocha": { + "legacy_import_succeeded": true, + "legacy_converted_colors": { + "background": "#28293c", + "comment": "#a4aabf", + "currentLineHighlight": "#404256", + "insertionPointColor": "#b5bcd2", + "invisibles": "#6b6f83", + "keyword": "#d6b8f9", + "keyword.attribute": "#a3e6dd", + "link": "#9ac3fb", + "markdown": "#a4aabf", + "memberDeclaration": "#d6dff6", + "number": "#fcc199", + "number.character": "#b3e6b0", + "otherMember": "#9ac3fb", + "otherMember.constant": "#fcc199", + "otherMember.function": "#9ac3fb", + "otherMember.variable": "#d6dff6", + "otherType": "#fbe7bd", + "otherType.class": "#fbe7bd", + "otherType.type": "#fbe7bd", + "plainText": "#d6dff6", + "preprocessor": "#a3e6dd", + "preprocessor.macro": "#9ac3fb", + "preprocessor.macroSystem": "#9ac3fb", + "projectMember": "#9ac3fb", + "projectMember.constant": "#fcc199", + "projectMember.function": "#9ac3fb", + "projectMember.variable": "#d6dff6", + "projectType": "#fbe7bd", + "projectType.class": "#fbe7bd", + "projectType.type": "#fbe7bd", + "selectedTextBackgroundColor": "#575a6d", + "string": "#b3e6b0", + "string.regex": "#f8cfec", + "typeDeclaration": "#fbe7bd" + }, + "native_file_colors": { + "background": "#1e1e2e", + "plainText": "#cdd6f4", + "comment": "#9399b2", + "commentEmphasized": "#9399b2", + "markdown": "#9399b2", + "markdownEmphasized": "#9399b2", + "keyword": "#cba6f7", + "keyword.attribute": "#94e2d5", + "string": "#a6e3a1", + "string.regex": "#f5c2e7", + "number": "#fab387", + "number.character": "#a6e3a1", + "link": "#89b4fa", + "preprocessor": "#94e2d5", + "preprocessor.macro": "#89b4fa", + "preprocessor.macroSystem": "#89b4fa", + "typeDeclaration": "#f9e2af", + "memberDeclaration": "#cdd6f4", + "projectType": "#f9e2af", + "projectType.class": "#f9e2af", + "projectType.type": "#f9e2af", + "projectMember": "#89b4fa", + "projectMember.function": "#89b4fa", + "projectMember.constant": "#fab387", + "projectMember.variable": "#cdd6f4", + "otherType": "#f9e2af", + "otherType.class": "#f9e2af", + "otherType.type": "#f9e2af", + "otherMember": "#89b4fa", + "otherMember.function": "#89b4fa", + "otherMember.constant": "#fab387", + "otherMember.variable": "#cdd6f4", + "selectedTextBackgroundColor": "#45475a", + "insertionPointColor": "#a6adc8", + "currentLineHighlight": "#313244", + "invisibles": "#585b70", + "diffAddition": "#a6e3a1", + "diffDeletion": "#f38ba8", + "debugger": "#a6e3a1" + }, + "native_ui_spot_checks": { + "plainText": "#cdd6f4", + "debugger": "#a6e3a1" + } + } + }, + "notes": [ + "Converted legacy values are decoded from Xcode-saved OKLCH; imported Plain Text values were also read from the UI.", + "Native file values are automated measurements; native_ui_spot_checks contains only values observed in Appearance controls.", + "Import colors was enabled; fonts/line spacing and cursor shape were disabled. All flavor names used distinct test filenames.", + "Frapp\u00e9 required explicitly selecting its imported entry after the importer initially displayed Standard.", + "These checks do not certify console, diagnostics, rendered markup, or language-specific token classification." + ] +} diff --git a/docs/xcode-27.md b/docs/xcode-27.md new file mode 100644 index 0000000..d32dd0c --- /dev/null +++ b/docs/xcode-27.md @@ -0,0 +1,64 @@ +# Xcode 27 native workspace themes + +Xcode 27 introduced Appearance themes that extend across the workspace. The native `.xcworkspacecolortheme` files under [themes/xcode-27](../themes/xcode-27/) encode exact Catppuccin sRGB colors in Xcode's OKLCH representation, with 38 explicit overrides and solid backgrounds. Fonts, sizes, line spacing and cursor shape remain separate settings. + +## Installation + +1. Copy your preferred native flavor files into `~/Library/Developer/Xcode/UserData/FontAndColorThemes/`, creating the folder if needed. Back up existing files with the same names before replacing them. +2. Open **Xcode → Settings → Appearance → Theme → Choose…**. Select **Light** for Latte or **Dark** for Frappé, Macchiato or Mocha. Separate themes can be assigned for each appearance. +3. If the new files are not listed, restart Xcode when convenient. In the tested 27.1 build they appeared without a restart. + +Use direct file copying for these native files. Xcode 27.0's **Import…** workflow was observed interpreting a native file as a classic theme and substituting default colors. That workflow is appropriate for the existing legacy `.xccolortheme` files instead. Legacy files remain available for older Xcode versions. + +## Compatibility measurements + +On **2026-09-23**, all four legacy themes from revision `e3816a60caaf9889b81866924fd6ef0a4e2ad571` were imported in **Xcode 27.1 (27A9269)** on **macOS 27.2 (26B5091g)**. Colors were enabled; fonts/line spacing and cursor shape were disabled. Xcode converted them to native recipes with 33 explicit overrides, and the resulting colors differed from the source palette. + +| Flavor | Source background | Converted background | Source text | Imported text | Native text | +| --- | --- | --- | --- | --- | --- | +| Latte | `#EFF1F5` | `#F2F4F7` | `#4C4F69` | `#5E637C` | `#4C4F69` | +| Frappé | `#303446` | `#3F4458` | `#C6D0F5` | `#D0DAF7` | `#C6D0F5` | +| Macchiato | `#24273A` | `#30354B` | `#CAD3F5` | `#D4DCF7` | `#CAD3F5` | +| Mocha | `#1E1E2E` | `#28293C` | `#CDD6F4` | `#D6DFF6` | `#CDD6F4` | + +Converted backgrounds were decoded from Xcode's saved OKLCH recipes. Imported and native text colors were also read from Appearance's hex controls. The cause of the import conversion has not been isolated, and these results should not be generalized to every build. The [recorded values](xcode-27-import-results.json) distinguish decoded files from UI spot checks. + +All four native files loaded, with exact Plain Text and Debugger colors. Latte was checked in Light appearance; its keyword, attribute, string, regex, number, character, link, preprocessor, macro and type-declaration controls also matched. Frappé's classic import initially displayed Standard; explicitly choosing its imported entry loaded the correct converted theme. Testing used distinct filenames to avoid replacing existing themes. + +These are loading and Appearance preview checks, not complete workspace visual certification. Console output, rendered documentation, diagnostics, search, navigation, inactive windows, automatic appearance switching and language-specific token classification still need broader review. The legacy font import option was not tested. + +## Mapping and limitations + +The native mapping preserves directly corresponding legacy assignments: Text for plain text/declarations/variables, Overlay 2 for comments, Mauve for keywords, Teal for attributes/preprocessors, Green for strings/characters, Pink for regex, Peach for numbers/constants, Blue for functions/macros/links, and Yellow for types. The editor cursor uses Subtext 0. Background, current line, selection and invisibles use Base, Surface 0, Surface 1 and Surface 2 respectively. + +Native additions include Green/Red diff colors, explicit comment emphasis and type/member fallbacks. The single Debugger role uses the legacy prompt's Green as an approximation. Lavender and Base seed additional Xcode-generated foreground/background treatments. These derived workspace surfaces are not independent exact palette overrides. + +The [coverage manifest](../native/coverage.json) classifies all 104 leaf settings in each legacy theme: + +| Disposition | Count | Scope | +| --- | ---: | --- | +| Direct colors | 31 | 26 syntax assignments and 5 editor surfaces; checked against original RGB values. | +| Merged categories | 4 | Regex subcategories have one exposed native Regex role. | +| Approximation | 1 | Console prompt Green is used for the native Debugger role. | +| Separate typography | 40 | Editor, console and markup fonts are not part of the native color recipe. | +| No direct control verified | 27 | Seven console colors, ten rendered-markup colors, seven scrollbar colors, block dimming, MARK and inline documentation code. | +| Metadata | 1 | Legacy format version. | + +A classified setting is not necessarily reproduced. Rendered markup is different from source documentation comments, and diff colors do not guarantee scrollbar-marker parity. No unsupported legacy keys are inserted into the native recipe. The tests verify values and coverage; they cannot prove every language's runtime token classification. + +## Generation and tests + +Python 3.9+ is sufficient; the native generator has no third-party dependencies. Shared colors are read directly from the existing Whiskers-generated legacy files, so their assignments remain the source of truth. + +```sh +whiskers xcode.tera +python3 scripts/generate_native.py +python3 scripts/generate_native.py --check +python3 -m unittest discover -s tests -v +``` + +`native/mapping.json` maps native roles to legacy fields. Only Lavender (foreground seed) and Red (diff deletion), which are not available as corresponding legacy fields, come from [supplemental-colors.json](../native/supplemental-colors.json). Those values are pinned to the [Catppuccin palette at 07d02aa](https://github.com/catppuccin/palette/tree/07d02aa110ef9eb7e7427afca5c73ba9cf7f8ebd). The existing Whiskers check remains in place; a separate native check validates generation, coverage and exact RGB output. + +The generator recovers 8-bit RGB values from the legacy six-decimal channels, converts sRGB to OKLCH and rounds to twelve decimals for reproducible macOS/Linux output. Tests compare all direct assignments with the legacy files, check metadata and wrapper types, and require every legacy setting to have an explicit disposition. They never touch the active Xcode theme folder or preferences. + +This implementation is adapted from [kylereddoch/catppuccin-xcode](https://github.com/kylereddoch/catppuccin-xcode/tree/a4974c441a3ff048584b8299d6e914b129a7adce), with the original generator/test MIT notice preserved in [native/LICENSE](../native/LICENSE). The generated themes are byte-identical to that tested revision. The [original comparison report](https://github.com/kylereddoch/catppuccin-xcode/blob/a4974c441a3ff048584b8299d6e914b129a7adce/docs/UPSTREAM-COMPATIBILITY.md) contains further context for [issue #22](https://github.com/catppuccin/xcode/issues/22). diff --git a/native/LICENSE b/native/LICENSE new file mode 100644 index 0000000..c93857d --- /dev/null +++ b/native/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Kyle Reddoch + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/native/coverage.json b/native/coverage.json new file mode 100644 index 0000000..138cc04 --- /dev/null +++ b/native/coverage.json @@ -0,0 +1,423 @@ +{ + "DVTConsoleDebuggerInputTextColor": { + "status": "unexposed", + "note": "No independent console override in the tested native recipe or Appearance color controls." + }, + "DVTConsoleDebuggerInputTextFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTConsoleDebuggerOutputTextColor": { + "status": "unexposed", + "note": "No independent console override in the tested native recipe or Appearance color controls." + }, + "DVTConsoleDebuggerOutputTextFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTConsoleDebuggerPromptTextColor": { + "status": "approximation", + "target": "debugger", + "note": "Use upstream green for the single native debugger role; this is not a separate console prompt override." + }, + "DVTConsoleDebuggerPromptTextFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTConsoleExectuableInputTextColor": { + "status": "unexposed", + "note": "No independent console override in the tested native recipe or Appearance color controls." + }, + "DVTConsoleExectuableInputTextFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTConsoleExectuableOutputTextColor": { + "status": "unexposed", + "note": "No independent console override in the tested native recipe or Appearance color controls." + }, + "DVTConsoleExectuableOutputTextFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTConsoleTextBackgroundColor": { + "status": "unexposed", + "note": "No independent console override in the tested native recipe or Appearance color controls." + }, + "DVTConsoleTextInsertionPointColor": { + "status": "unexposed", + "note": "No independent console override in the tested native recipe or Appearance color controls." + }, + "DVTConsoleTextSelectionColor": { + "status": "unexposed", + "note": "No independent console override in the tested native recipe or Appearance color controls." + }, + "DVTFontAndColorVersion": { + "status": "metadata", + "note": "Legacy plist version; native files use fileVersion 1." + }, + "DVTMarkupTextBackgroundColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextBorderColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextCodeFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTMarkupTextEmphasisColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextEmphasisFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTMarkupTextInlineCodeColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextLinkColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextLinkFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTMarkupTextNormalColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextNormalFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTMarkupTextOtherHeadingColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextOtherHeadingFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTMarkupTextPrimaryHeadingColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextPrimaryHeadingFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTMarkupTextSecondaryHeadingColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextSecondaryHeadingFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTMarkupTextStrongColor": { + "status": "unexposed", + "note": "Rendered markup settings are distinct from source documentation comments; no direct native override verified." + }, + "DVTMarkupTextStrongFont": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTScrollbarMarkerAnalyzerColor": { + "status": "unexposed", + "note": "No independent scrollbar marker override verified; diffAddition/diffDeletion do not promise scrollbar parity." + }, + "DVTScrollbarMarkerBreakpointColor": { + "status": "unexposed", + "note": "No independent scrollbar marker override verified; diffAddition/diffDeletion do not promise scrollbar parity." + }, + "DVTScrollbarMarkerDiffColor": { + "status": "unexposed", + "note": "No independent scrollbar marker override verified; diffAddition/diffDeletion do not promise scrollbar parity." + }, + "DVTScrollbarMarkerDiffConflictColor": { + "status": "unexposed", + "note": "No independent scrollbar marker override verified; diffAddition/diffDeletion do not promise scrollbar parity." + }, + "DVTScrollbarMarkerErrorColor": { + "status": "unexposed", + "note": "No independent scrollbar marker override verified; diffAddition/diffDeletion do not promise scrollbar parity." + }, + "DVTScrollbarMarkerRuntimeIssueColor": { + "status": "unexposed", + "note": "No independent scrollbar marker override verified; diffAddition/diffDeletion do not promise scrollbar parity." + }, + "DVTScrollbarMarkerWarningColor": { + "status": "unexposed", + "note": "No independent scrollbar marker override verified; diffAddition/diffDeletion do not promise scrollbar parity." + }, + "DVTSourceTextBackground": { + "status": "direct", + "target": "background" + }, + "DVTSourceTextBlockDimBackgroundColor": { + "status": "unexposed", + "note": "No independent block dim background override verified." + }, + "DVTSourceTextCurrentLineHighlightColor": { + "status": "direct", + "target": "currentLineHighlight" + }, + "DVTSourceTextInsertionPointColor": { + "status": "direct", + "target": "insertionPointColor" + }, + "DVTSourceTextInvisiblesColor": { + "status": "direct", + "target": "invisibles" + }, + "DVTSourceTextSelectionColor": { + "status": "direct", + "target": "selectedTextBackgroundColor" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.attribute": { + "status": "direct", + "target": "keyword.attribute" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.character": { + "status": "direct", + "target": "number.character" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.comment": { + "status": "direct", + "target": "comment" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.comment.doc": { + "status": "direct", + "target": "markdown" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.comment.doc.keyword": { + "status": "direct", + "target": "markdownEmphasized" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.declaration.other": { + "status": "direct", + "target": "memberDeclaration" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.declaration.type": { + "status": "direct", + "target": "typeDeclaration" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.class": { + "status": "direct", + "target": "projectType.class" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.class.system": { + "status": "direct", + "target": "otherType.class" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.constant": { + "status": "direct", + "target": "projectMember.constant" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.constant.system": { + "status": "direct", + "target": "otherMember.constant" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.function": { + "status": "direct", + "target": "projectMember.function" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.function.system": { + "status": "direct", + "target": "otherMember.function" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.macro": { + "status": "direct", + "target": "preprocessor.macro" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.macro.system": { + "status": "direct", + "target": "preprocessor.macroSystem" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.type": { + "status": "direct", + "target": "projectType.type" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.type.system": { + "status": "direct", + "target": "otherType.type" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.variable": { + "status": "direct", + "target": "projectMember.variable" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.identifier.variable.system": { + "status": "direct", + "target": "otherMember.variable" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.keyword": { + "status": "direct", + "target": "keyword" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.mark": { + "status": "unexposed", + "note": "No dedicated MARK role verified; emphasized comment colors do not guarantee independent MARK styling." + }, + "DVTSourceTextSyntaxColors/xcode.syntax.markup.code": { + "status": "unexposed", + "note": "No dedicated inline documentation code role verified." + }, + "DVTSourceTextSyntaxColors/xcode.syntax.number": { + "status": "direct", + "target": "number" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.plain": { + "status": "direct", + "target": "plainText" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.preprocessor": { + "status": "direct", + "target": "preprocessor" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.regex": { + "status": "direct", + "target": "string.regex" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.regex.capturename": { + "status": "merged", + "target": "string.regex", + "note": "Native Appearance exposes one Regex color, not independently editable regex subcategories." + }, + "DVTSourceTextSyntaxColors/xcode.syntax.regex.charname": { + "status": "merged", + "target": "string.regex", + "note": "Native Appearance exposes one Regex color, not independently editable regex subcategories." + }, + "DVTSourceTextSyntaxColors/xcode.syntax.regex.number": { + "status": "merged", + "target": "string.regex", + "note": "Native Appearance exposes one Regex color, not independently editable regex subcategories." + }, + "DVTSourceTextSyntaxColors/xcode.syntax.regex.other": { + "status": "merged", + "target": "string.regex", + "note": "Native Appearance exposes one Regex color, not independently editable regex subcategories." + }, + "DVTSourceTextSyntaxColors/xcode.syntax.string": { + "status": "direct", + "target": "string" + }, + "DVTSourceTextSyntaxColors/xcode.syntax.url": { + "status": "direct", + "target": "link" + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.attribute": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.character": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.comment": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.comment.doc": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.comment.doc.keyword": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.declaration.other": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.declaration.type": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.class": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.class.system": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.constant": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.constant.system": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.function": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.function.system": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.macro": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.macro.system": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.type": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.type.system": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.variable": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.identifier.variable.system": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.keyword": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.mark": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.markup.code": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.number": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.plain": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.preprocessor": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.string": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + }, + "DVTSourceTextSyntaxFonts/xcode.syntax.url": { + "status": "separate-setting", + "note": "Fonts are separate in Xcode 27; native color recipes do not set typography." + } +} diff --git a/native/mapping.json b/native/mapping.json new file mode 100644 index 0000000..c2716d8 --- /dev/null +++ b/native/mapping.json @@ -0,0 +1,40 @@ +{ + "plainText": "DVTSourceTextSyntaxColors/xcode.syntax.plain", + "comment": "DVTSourceTextSyntaxColors/xcode.syntax.comment", + "commentEmphasized": "DVTSourceTextSyntaxColors/xcode.syntax.comment", + "markdown": "DVTSourceTextSyntaxColors/xcode.syntax.comment.doc", + "markdownEmphasized": "DVTSourceTextSyntaxColors/xcode.syntax.comment.doc.keyword", + "keyword": "DVTSourceTextSyntaxColors/xcode.syntax.keyword", + "keyword.attribute": "DVTSourceTextSyntaxColors/xcode.syntax.attribute", + "string": "DVTSourceTextSyntaxColors/xcode.syntax.string", + "string.regex": "DVTSourceTextSyntaxColors/xcode.syntax.regex", + "number": "DVTSourceTextSyntaxColors/xcode.syntax.number", + "number.character": "DVTSourceTextSyntaxColors/xcode.syntax.character", + "link": "DVTSourceTextSyntaxColors/xcode.syntax.url", + "preprocessor": "DVTSourceTextSyntaxColors/xcode.syntax.preprocessor", + "preprocessor.macro": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.macro", + "preprocessor.macroSystem": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.macro.system", + "typeDeclaration": "DVTSourceTextSyntaxColors/xcode.syntax.declaration.type", + "memberDeclaration": "DVTSourceTextSyntaxColors/xcode.syntax.declaration.other", + "projectType": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.type", + "projectType.class": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.class", + "projectType.type": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.type", + "projectMember": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.function", + "projectMember.function": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.function", + "projectMember.constant": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.constant", + "projectMember.variable": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.variable", + "otherType": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.type.system", + "otherType.class": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.class.system", + "otherType.type": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.type.system", + "otherMember": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.function.system", + "otherMember.function": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.function.system", + "otherMember.constant": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.constant.system", + "otherMember.variable": "DVTSourceTextSyntaxColors/xcode.syntax.identifier.variable.system", + "selectedTextBackgroundColor": "DVTSourceTextSelectionColor", + "insertionPointColor": "DVTSourceTextInsertionPointColor", + "currentLineHighlight": "DVTSourceTextCurrentLineHighlightColor", + "invisibles": "DVTSourceTextInvisiblesColor", + "diffAddition": "DVTSourceTextSyntaxColors/xcode.syntax.string", + "diffDeletion": "supplemental/red", + "debugger": "DVTConsoleDebuggerPromptTextColor" +} diff --git a/native/supplemental-colors.json b/native/supplemental-colors.json new file mode 100644 index 0000000..efe8536 --- /dev/null +++ b/native/supplemental-colors.json @@ -0,0 +1,26 @@ +{ + "latte": { + "name": "Latte", + "dark": false, + "lavender": "#7287fd", + "red": "#d20f39" + }, + "frappe": { + "name": "Frapp\u00e9", + "dark": true, + "lavender": "#babbf1", + "red": "#e78284" + }, + "macchiato": { + "name": "Macchiato", + "dark": true, + "lavender": "#b7bdf8", + "red": "#ed8796" + }, + "mocha": { + "name": "Mocha", + "dark": true, + "lavender": "#b4befe", + "red": "#f38ba8" + } +} diff --git a/scripts/generate_native.py b/scripts/generate_native.py new file mode 100644 index 0000000..d3eff14 --- /dev/null +++ b/scripts/generate_native.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +"""Generate Xcode 27 workspace themes from the existing Whiskers-generated themes. + +Shared colors come from the legacy files. Supplemental colors are pinned in +native/supplemental-colors.json; see docs/xcode-27.md for provenance. +""" +# Adapted from kylereddoch/catppuccin-xcode; MIT notice: native/LICENSE. +import argparse +import json +import math +from pathlib import Path +import plistlib + +ROOT = Path(__file__).resolve().parents[1] +FLAVORS = ("latte", "frappe", "macchiato", "mocha") + + +def legacy_hex(value): + channels = [float(channel) for channel in value.split()] + if len(channels) != 4 or channels[3] != 1: + raise ValueError(f"Expected opaque legacy RGBA, got {value!r}") + if any(not 0 <= channel <= 1 for channel in channels): + raise ValueError(f"Legacy RGBA out of range: {value!r}") + # The legacy generator rounds to six decimals; recover exact 8-bit sRGB. + return "#" + "".join(f"{round(channel * 255):02x}" for channel in channels[:3]) + + +def to_oklch(hex_color): + """Convert an sRGB hex color to Xcode's exact OKLCH representation.""" + value = hex_color.removeprefix("#") + rgb = [int(value[i:i + 2], 16) / 255 for i in (0, 2, 4)] + r, g, b = [v / 12.92 if v <= .04045 else ((v + .055) / 1.055) ** 2.4 for v in rgb] + l = (.4122214708 * r + .5363325363 * g + .0514459929 * b) ** (1 / 3) + m = (.2119034982 * r + .6806995451 * g + .1073969566 * b) ** (1 / 3) + s = (.0883024619 * r + .2817188376 * g + .6299787005 * b) ** (1 / 3) + lightness = .2104542553 * l + .793617785 * m - .0040720468 * s + a = 1.9779984951 * l - 2.428592205 * m + .4505937099 * s + b = .0259040371 * l + .7827717662 * m - .808675766 * s + return { + # Normalize libm's trailing-bit differences across macOS and Linux. + # Twelve decimals preserve every 8-bit sRGB palette value exactly. + "chroma": {"exact": round(math.hypot(a, b), 12)}, + "gamut": "sRGB", + "hue": {"radians": round(math.atan2(b, a) % (2 * math.pi), 12)}, + "lightness": {"exact": round(lightness, 12)}, + "opacity": 1, + } + + +def build_theme(flavor): + extra = json.loads((ROOT / "native/supplemental-colors.json").read_text())[flavor] + source = plistlib.loads((ROOT / "themes" / f"Catppuccin {extra['name']}.xccolortheme").read_bytes()) + mapping = json.loads((ROOT / "native/mapping.json").read_text()) + + def color(path): + if path.startswith("supplemental/"): + return to_oklch(extra[path.split("/", 1)[1]]) + value = source + for key in path.split("/"): + value = value[key] + return to_oklch(legacy_hex(value)) + + translucent_roles = {"selectedTextBackgroundColor", "currentLineHighlight"} + overrides = { + role: {"colorWithOpacity" if role in translucent_roles else "color": color(path)} + for role, path in mapping.items() + } + return { + "fileVersion": 1, + "recipe": { + "background": {"customColor": color("DVTSourceTextBackground")}, + "colorScheme": "dark" if extra["dark"] else "light", + "palette": { + "colorOverrides": overrides, + "primary": {"custom": color("supplemental/lavender")}, + "secondary": {"custom": color("DVTSourceTextBackground")}, + }, + }, + } + + +def theme_path(flavor): + extra = json.loads((ROOT / "native/supplemental-colors.json").read_text())[flavor] + return ROOT / "themes" / "xcode-27" / f"Catppuccin {extra['name']}.xcworkspacecolortheme" + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--check", action="store_true", help="Verify generated files without writing.") + args = parser.parse_args() + stale = [] + for flavor in FLAVORS: + path = theme_path(flavor) + expected = json.dumps(build_theme(flavor), indent=2) + "\n" + if args.check: + if not path.exists() or path.read_text() != expected: + stale.append(path.name) + else: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(expected) + print(f"Generated {path.name}") + if stale: + parser.exit(1, "Native themes need regeneration: " + ", ".join(stale) + "\n") + if args.check: + print("Native themes are current.") + + +if __name__ == "__main__": + main() diff --git a/tests/test_native.py b/tests/test_native.py new file mode 100644 index 0000000..553ac83 --- /dev/null +++ b/tests/test_native.py @@ -0,0 +1,91 @@ +"""Native color fidelity, legacy coverage, and generation regression checks.""" +# Adapted from kylereddoch/catppuccin-xcode; MIT notice: native/LICENSE. +import importlib.util +import json +import math +from pathlib import Path +import plistlib +import unittest + +ROOT = Path(__file__).resolve().parents[1] +spec = importlib.util.spec_from_file_location("generate_native", ROOT / "scripts/generate_native.py") +generate = importlib.util.module_from_spec(spec) +spec.loader.exec_module(generate) + + +def decode_hex(color): + lightness = color["lightness"]["exact"] + chroma = color["chroma"]["exact"] + hue = color["hue"]["radians"] + a, b = chroma * math.cos(hue), chroma * math.sin(hue) + l = (lightness + .3963377774 * a + .2158037573 * b) ** 3 + m = (lightness - .1055613458 * a - .0638541728 * b) ** 3 + s = (lightness - .0894841775 * a - 1.291485548 * b) ** 3 + linear = [ + 4.0767416621 * l - 3.3077115913 * m + .2309699292 * s, + -1.2684380046 * l + 2.6097574011 * m - .3413193965 * s, + -.0041960863 * l - .7034186147 * m + 1.707614701 * s, + ] + rgb = [12.92 * v if v <= .0031308 else 1.055 * v ** (1 / 2.4) - .055 for v in linear] + return "#" + "".join(f"{round(v * 255):02x}" for v in rgb) + + +def flatten(data): + return {f"{key}/{sub}" if sub else key: value + for key, item in data.items() + for sub, value in (item.items() if isinstance(item, dict) else [(None, item)])} + + +class NativeThemeTests(unittest.TestCase): + def test_generation_and_appearance(self): + for flavor in generate.FLAVORS: + with self.subTest(flavor=flavor): + actual = json.loads(generate.theme_path(flavor).read_text()) + self.assertEqual(actual, generate.build_theme(flavor)) + self.assertEqual(actual["fileVersion"], 1) + self.assertEqual(actual["recipe"]["colorScheme"], "light" if flavor == "latte" else "dark") + self.assertEqual(len(actual["recipe"]["palette"]["colorOverrides"]), 38) + + def test_complete_legacy_coverage_and_matching_colors(self): + coverage = json.loads((ROOT / "native/coverage.json").read_text()) + extras = json.loads((ROOT / "native/supplemental-colors.json").read_text()) + statuses = {"direct", "approximation", "merged", "unexposed", "separate-setting", "metadata"} + for flavor, extra in extras.items(): + source = flatten(plistlib.loads((ROOT / "themes" / f"Catppuccin {extra['name']}.xccolortheme").read_bytes())) + self.assertEqual(set(source), set(coverage)) + recipe = json.loads(generate.theme_path(flavor).read_text())["recipe"] + for setting, disposition in coverage.items(): + with self.subTest(flavor=flavor, setting=setting): + self.assertIn(disposition["status"], statuses) + if disposition["status"] != "direct": + self.assertTrue(disposition.get("note")) + if disposition["status"] not in {"direct", "approximation"}: + continue + target = disposition["target"] + native = recipe["background"]["customColor"] if target == "background" else next(iter(recipe["palette"]["colorOverrides"][target].values())) + self.assertEqual(decode_hex(native), generate.legacy_hex(source[setting])) + + def test_native_seeds_and_supplemental_colors(self): + extras = json.loads((ROOT / "native/supplemental-colors.json").read_text()) + for flavor, extra in extras.items(): + recipe = json.loads(generate.theme_path(flavor).read_text())["recipe"] + self.assertEqual(decode_hex(recipe["palette"]["primary"]["custom"]), extra["lavender"]) + self.assertEqual(decode_hex(recipe["palette"]["colorOverrides"]["diffDeletion"]["color"]), extra["red"]) + self.assertEqual(recipe["palette"]["secondary"]["custom"], recipe["background"]["customColor"]) + roles = recipe["palette"]["colorOverrides"] + for parent, child in {"projectType": "projectType.type", "otherType": "otherType.type", "projectMember": "projectMember.function", "otherMember": "otherMember.function", "commentEmphasized": "comment", "diffAddition": "string"}.items(): + self.assertEqual(roles[parent], roles[child]) + for role, entry in roles.items(): + key = "colorWithOpacity" if role in {"selectedTextBackgroundColor", "currentLineHighlight"} else "color" + self.assertEqual(set(entry), {key}) + self.assertEqual(entry[key]["gamut"], "sRGB") + self.assertEqual(entry[key]["opacity"], 1) + + def test_legacy_rgba_rejects_unsupported_values(self): + for value in ["0 0 0", "0 0 0 .5", "2 0 0 1", "nan 0 0 1"]: + with self.subTest(value=value), self.assertRaises(ValueError): + generate.legacy_hex(value) + + +if __name__ == "__main__": + unittest.main() diff --git "a/themes/xcode-27/Catppuccin Frapp\303\251.xcworkspacecolortheme" "b/themes/xcode-27/Catppuccin Frapp\303\251.xcworkspacecolortheme" new file mode 100644 index 0000000..f865ef2 --- /dev/null +++ "b/themes/xcode-27/Catppuccin Frapp\303\251.xcworkspacecolortheme" @@ -0,0 +1,625 @@ +{ + "fileVersion": 1, + "recipe": { + "background": { + "customColor": { + "chroma": { + "exact": 0.032391298747 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.795432575167 + }, + "lightness": { + "exact": 0.329073999893 + }, + "opacity": 1 + } + }, + "colorScheme": "dark", + "palette": { + "colorOverrides": { + "plainText": { + "color": { + "chroma": { + "exact": 0.052553260167 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.770811479409 + }, + "lightness": { + "exact": 0.861915898237 + }, + "opacity": 1 + } + }, + "comment": { + "color": { + "chroma": { + "exact": 0.046369806353 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.778308554278 + }, + "lightness": { + "exact": 0.696974150107 + }, + "opacity": 1 + } + }, + "commentEmphasized": { + "color": { + "chroma": { + "exact": 0.046369806353 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.778308554278 + }, + "lightness": { + "exact": 0.696974150107 + }, + "opacity": 1 + } + }, + "markdown": { + "color": { + "chroma": { + "exact": 0.046369806353 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.778308554278 + }, + "lightness": { + "exact": 0.696974150107 + }, + "opacity": 1 + } + }, + "markdownEmphasized": { + "color": { + "chroma": { + "exact": 0.046369806353 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.778308554278 + }, + "lightness": { + "exact": 0.696974150107 + }, + "opacity": 1 + } + }, + "keyword": { + "color": { + "chroma": { + "exact": 0.11077095182 + }, + "gamut": "sRGB", + "hue": { + "radians": 5.440952472895 + }, + "lightness": { + "exact": 0.764753045089 + }, + "opacity": 1 + } + }, + "keyword.attribute": { + "color": { + "chroma": { + "exact": 0.072960645267 + }, + "gamut": "sRGB", + "hue": { + "radians": 3.222662320405 + }, + "lightness": { + "exact": 0.782980299376 + }, + "opacity": 1 + } + }, + "string": { + "color": { + "chroma": { + "exact": 0.107060939631 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.328127999367 + }, + "lightness": { + "exact": 0.812373900724 + }, + "opacity": 1 + } + }, + "string.regex": { + "color": { + "chroma": { + "exact": 0.089242041466 + }, + "gamut": "sRGB", + "hue": { + "radians": 5.868902141902 + }, + "lightness": { + "exact": 0.850368704187 + }, + "opacity": 1 + } + }, + "number": { + "color": { + "chroma": { + "exact": 0.110571562951 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.832982691663 + }, + "lightness": { + "exact": 0.772722337532 + }, + "opacity": 1 + } + }, + "number.character": { + "color": { + "chroma": { + "exact": 0.107060939631 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.328127999367 + }, + "lightness": { + "exact": 0.812373900724 + }, + "opacity": 1 + } + }, + "link": { + "color": { + "chroma": { + "exact": 0.104443523925 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.636697385458 + }, + "lightness": { + "exact": 0.742010112695 + }, + "opacity": 1 + } + }, + "preprocessor": { + "color": { + "chroma": { + "exact": 0.072960645267 + }, + "gamut": "sRGB", + "hue": { + "radians": 3.222662320405 + }, + "lightness": { + "exact": 0.782980299376 + }, + "opacity": 1 + } + }, + "preprocessor.macro": { + "color": { + "chroma": { + "exact": 0.104443523925 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.636697385458 + }, + "lightness": { + "exact": 0.742010112695 + }, + "opacity": 1 + } + }, + "preprocessor.macroSystem": { + "color": { + "chroma": { + "exact": 0.104443523925 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.636697385458 + }, + "lightness": { + "exact": 0.742010112695 + }, + "opacity": 1 + } + }, + "typeDeclaration": { + "color": { + "chroma": { + "exact": 0.079543471606 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.456855169322 + }, + "lightness": { + "exact": 0.844316469979 + }, + "opacity": 1 + } + }, + "memberDeclaration": { + "color": { + "chroma": { + "exact": 0.052553260167 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.770811479409 + }, + "lightness": { + "exact": 0.861915898237 + }, + "opacity": 1 + } + }, + "projectType": { + "color": { + "chroma": { + "exact": 0.079543471606 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.456855169322 + }, + "lightness": { + "exact": 0.844316469979 + }, + "opacity": 1 + } + }, + "projectType.class": { + "color": { + "chroma": { + "exact": 0.079543471606 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.456855169322 + }, + "lightness": { + "exact": 0.844316469979 + }, + "opacity": 1 + } + }, + "projectType.type": { + "color": { + "chroma": { + "exact": 0.079543471606 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.456855169322 + }, + "lightness": { + "exact": 0.844316469979 + }, + "opacity": 1 + } + }, + "projectMember": { + "color": { + "chroma": { + "exact": 0.104443523925 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.636697385458 + }, + "lightness": { + "exact": 0.742010112695 + }, + "opacity": 1 + } + }, + "projectMember.function": { + "color": { + "chroma": { + "exact": 0.104443523925 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.636697385458 + }, + "lightness": { + "exact": 0.742010112695 + }, + "opacity": 1 + } + }, + "projectMember.constant": { + "color": { + "chroma": { + "exact": 0.110571562951 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.832982691663 + }, + "lightness": { + "exact": 0.772722337532 + }, + "opacity": 1 + } + }, + "projectMember.variable": { + "color": { + "chroma": { + "exact": 0.052553260167 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.770811479409 + }, + "lightness": { + "exact": 0.861915898237 + }, + "opacity": 1 + } + }, + "otherType": { + "color": { + "chroma": { + "exact": 0.079543471606 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.456855169322 + }, + "lightness": { + "exact": 0.844316469979 + }, + "opacity": 1 + } + }, + "otherType.class": { + "color": { + "chroma": { + "exact": 0.079543471606 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.456855169322 + }, + "lightness": { + "exact": 0.844316469979 + }, + "opacity": 1 + } + }, + "otherType.type": { + "color": { + "chroma": { + "exact": 0.079543471606 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.456855169322 + }, + "lightness": { + "exact": 0.844316469979 + }, + "opacity": 1 + } + }, + "otherMember": { + "color": { + "chroma": { + "exact": 0.104443523925 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.636697385458 + }, + "lightness": { + "exact": 0.742010112695 + }, + "opacity": 1 + } + }, + "otherMember.function": { + "color": { + "chroma": { + "exact": 0.104443523925 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.636697385458 + }, + "lightness": { + "exact": 0.742010112695 + }, + "opacity": 1 + } + }, + "otherMember.constant": { + "color": { + "chroma": { + "exact": 0.110571562951 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.832982691663 + }, + "lightness": { + "exact": 0.772722337532 + }, + "opacity": 1 + } + }, + "otherMember.variable": { + "color": { + "chroma": { + "exact": 0.052553260167 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.770811479409 + }, + "lightness": { + "exact": 0.861915898237 + }, + "opacity": 1 + } + }, + "selectedTextBackgroundColor": { + "colorWithOpacity": { + "chroma": { + "exact": 0.036661432859 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.764151948114 + }, + "lightness": { + "exact": 0.460056601318 + }, + "opacity": 1 + } + }, + "insertionPointColor": { + "color": { + "chroma": { + "exact": 0.048282862787 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.790450489042 + }, + "lightness": { + "exact": 0.752383812929 + }, + "opacity": 1 + } + }, + "currentLineHighlight": { + "colorWithOpacity": { + "chroma": { + "exact": 0.034239261524 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.81536217315 + }, + "lightness": { + "exact": 0.394918842239 + }, + "opacity": 1 + } + }, + "invisibles": { + "color": { + "chroma": { + "exact": 0.038589559596 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.78218824235 + }, + "lightness": { + "exact": 0.521117163069 + }, + "opacity": 1 + } + }, + "diffAddition": { + "color": { + "chroma": { + "exact": 0.107060939631 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.328127999367 + }, + "lightness": { + "exact": 0.812373900724 + }, + "opacity": 1 + } + }, + "diffDeletion": { + "color": { + "chroma": { + "exact": 0.124368139908 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.338348082029 + }, + "lightness": { + "exact": 0.717098717709 + }, + "opacity": 1 + } + }, + "debugger": { + "color": { + "chroma": { + "exact": 0.107060939631 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.328127999367 + }, + "lightness": { + "exact": 0.812373900724 + }, + "opacity": 1 + } + } + }, + "primary": { + "custom": { + "chroma": { + "exact": 0.07588274484 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.952205913459 + }, + "lightness": { + "exact": 0.809899266239 + }, + "opacity": 1 + } + }, + "secondary": { + "custom": { + "chroma": { + "exact": 0.032391298747 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.795432575167 + }, + "lightness": { + "exact": 0.329073999893 + }, + "opacity": 1 + } + } + } + } +} diff --git a/themes/xcode-27/Catppuccin Latte.xcworkspacecolortheme b/themes/xcode-27/Catppuccin Latte.xcworkspacecolortheme new file mode 100644 index 0000000..74b74c2 --- /dev/null +++ b/themes/xcode-27/Catppuccin Latte.xcworkspacecolortheme @@ -0,0 +1,625 @@ +{ + "fileVersion": 1, + "recipe": { + "background": { + "customColor": { + "chroma": { + "exact": 0.005766766878 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.616956443496 + }, + "lightness": { + "exact": 0.957760880836 + }, + "opacity": 1 + } + }, + "colorScheme": "light", + "palette": { + "colorOverrides": { + "plainText": { + "color": { + "chroma": { + "exact": 0.04300794191 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.875141346558 + }, + "lightness": { + "exact": 0.435469625385 + }, + "opacity": 1 + } + }, + "comment": { + "color": { + "chroma": { + "exact": 0.03049044206 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.864134364426 + }, + "lightness": { + "exact": 0.600878135219 + }, + "opacity": 1 + } + }, + "commentEmphasized": { + "color": { + "chroma": { + "exact": 0.03049044206 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.864134364426 + }, + "lightness": { + "exact": 0.600878135219 + }, + "opacity": 1 + } + }, + "markdown": { + "color": { + "chroma": { + "exact": 0.03049044206 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.864134364426 + }, + "lightness": { + "exact": 0.600878135219 + }, + "opacity": 1 + } + }, + "markdownEmphasized": { + "color": { + "chroma": { + "exact": 0.03049044206 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.864134364426 + }, + "lightness": { + "exact": 0.600878135219 + }, + "opacity": 1 + } + }, + "keyword": { + "color": { + "chroma": { + "exact": 0.250346058195 + }, + "gamut": "sRGB", + "hue": { + "radians": 5.18390100327 + }, + "lightness": { + "exact": 0.554669846336 + }, + "opacity": 1 + } + }, + "keyword.attribute": { + "color": { + "chroma": { + "exact": 0.098114947537 + }, + "gamut": "sRGB", + "hue": { + "radians": 3.509939792044 + }, + "lightness": { + "exact": 0.602268964521 + }, + "opacity": 1 + } + }, + "string": { + "color": { + "chroma": { + "exact": 0.177158173631 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.45122471128 + }, + "lightness": { + "exact": 0.625044386121 + }, + "opacity": 1 + } + }, + "string.regex": { + "color": { + "chroma": { + "exact": 0.173932630663 + }, + "gamut": "sRGB", + "hue": { + "radians": 5.906776259674 + }, + "lightness": { + "exact": 0.72555972711 + }, + "opacity": 1 + } + }, + "number": { + "color": { + "chroma": { + "exact": 0.204051580714 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.740530490898 + }, + "lightness": { + "exact": 0.691976639258 + }, + "opacity": 1 + } + }, + "number.character": { + "color": { + "chroma": { + "exact": 0.177158173631 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.45122471128 + }, + "lightness": { + "exact": 0.625044386121 + }, + "opacity": 1 + } + }, + "link": { + "color": { + "chroma": { + "exact": 0.225502502377 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.574274949402 + }, + "lightness": { + "exact": 0.558616849692 + }, + "opacity": 1 + } + }, + "preprocessor": { + "color": { + "chroma": { + "exact": 0.098114947537 + }, + "gamut": "sRGB", + "hue": { + "radians": 3.509939792044 + }, + "lightness": { + "exact": 0.602268964521 + }, + "opacity": 1 + } + }, + "preprocessor.macro": { + "color": { + "chroma": { + "exact": 0.225502502377 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.574274949402 + }, + "lightness": { + "exact": 0.558616849692 + }, + "opacity": 1 + } + }, + "preprocessor.macroSystem": { + "color": { + "chroma": { + "exact": 0.225502502377 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.574274949402 + }, + "lightness": { + "exact": 0.558616849692 + }, + "opacity": 1 + } + }, + "typeDeclaration": { + "color": { + "chroma": { + "exact": 0.149441664583 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.182925866908 + }, + "lightness": { + "exact": 0.713991726411 + }, + "opacity": 1 + } + }, + "memberDeclaration": { + "color": { + "chroma": { + "exact": 0.04300794191 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.875141346558 + }, + "lightness": { + "exact": 0.435469625385 + }, + "opacity": 1 + } + }, + "projectType": { + "color": { + "chroma": { + "exact": 0.149441664583 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.182925866908 + }, + "lightness": { + "exact": 0.713991726411 + }, + "opacity": 1 + } + }, + "projectType.class": { + "color": { + "chroma": { + "exact": 0.149441664583 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.182925866908 + }, + "lightness": { + "exact": 0.713991726411 + }, + "opacity": 1 + } + }, + "projectType.type": { + "color": { + "chroma": { + "exact": 0.149441664583 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.182925866908 + }, + "lightness": { + "exact": 0.713991726411 + }, + "opacity": 1 + } + }, + "projectMember": { + "color": { + "chroma": { + "exact": 0.225502502377 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.574274949402 + }, + "lightness": { + "exact": 0.558616849692 + }, + "opacity": 1 + } + }, + "projectMember.function": { + "color": { + "chroma": { + "exact": 0.225502502377 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.574274949402 + }, + "lightness": { + "exact": 0.558616849692 + }, + "opacity": 1 + } + }, + "projectMember.constant": { + "color": { + "chroma": { + "exact": 0.204051580714 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.740530490898 + }, + "lightness": { + "exact": 0.691976639258 + }, + "opacity": 1 + } + }, + "projectMember.variable": { + "color": { + "chroma": { + "exact": 0.04300794191 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.875141346558 + }, + "lightness": { + "exact": 0.435469625385 + }, + "opacity": 1 + } + }, + "otherType": { + "color": { + "chroma": { + "exact": 0.149441664583 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.182925866908 + }, + "lightness": { + "exact": 0.713991726411 + }, + "opacity": 1 + } + }, + "otherType.class": { + "color": { + "chroma": { + "exact": 0.149441664583 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.182925866908 + }, + "lightness": { + "exact": 0.713991726411 + }, + "opacity": 1 + } + }, + "otherType.type": { + "color": { + "chroma": { + "exact": 0.149441664583 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.182925866908 + }, + "lightness": { + "exact": 0.713991726411 + }, + "opacity": 1 + } + }, + "otherMember": { + "color": { + "chroma": { + "exact": 0.225502502377 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.574274949402 + }, + "lightness": { + "exact": 0.558616849692 + }, + "opacity": 1 + } + }, + "otherMember.function": { + "color": { + "chroma": { + "exact": 0.225502502377 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.574274949402 + }, + "lightness": { + "exact": 0.558616849692 + }, + "opacity": 1 + } + }, + "otherMember.constant": { + "color": { + "chroma": { + "exact": 0.204051580714 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.740530490898 + }, + "lightness": { + "exact": 0.691976639258 + }, + "opacity": 1 + } + }, + "otherMember.variable": { + "color": { + "chroma": { + "exact": 0.04300794191 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.875141346558 + }, + "lightness": { + "exact": 0.435469625385 + }, + "opacity": 1 + } + }, + "selectedTextBackgroundColor": { + "colorWithOpacity": { + "chroma": { + "exact": 0.017393278726 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.733300769853 + }, + "lightness": { + "exact": 0.808307005781 + }, + "opacity": 1 + } + }, + "insertionPointColor": { + "color": { + "chroma": { + "exact": 0.034342768273 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.87092948521 + }, + "lightness": { + "exact": 0.547077634493 + }, + "opacity": 1 + } + }, + "currentLineHighlight": { + "colorWithOpacity": { + "chroma": { + "exact": 0.014479952517 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.685782976702 + }, + "lightness": { + "exact": 0.857477079255 + }, + "opacity": 1 + } + }, + "invisibles": { + "color": { + "chroma": { + "exact": 0.02045341206 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.767428920257 + }, + "lightness": { + "exact": 0.758394347257 + }, + "opacity": 1 + } + }, + "diffAddition": { + "color": { + "chroma": { + "exact": 0.177158173631 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.45122471128 + }, + "lightness": { + "exact": 0.625044386121 + }, + "opacity": 1 + } + }, + "diffDeletion": { + "color": { + "chroma": { + "exact": 0.215514307706 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.345740464421 + }, + "lightness": { + "exact": 0.550474411283 + }, + "opacity": 1 + } + }, + "debugger": { + "color": { + "chroma": { + "exact": 0.177158173631 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.45122471128 + }, + "lightness": { + "exact": 0.625044386121 + }, + "opacity": 1 + } + } + }, + "primary": { + "custom": { + "chroma": { + "exact": 0.175103278892 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.767098124047 + }, + "lightness": { + "exact": 0.663762896054 + }, + "opacity": 1 + } + }, + "secondary": { + "custom": { + "chroma": { + "exact": 0.005766766878 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.616956443496 + }, + "lightness": { + "exact": 0.957760880836 + }, + "opacity": 1 + } + } + } + } +} diff --git a/themes/xcode-27/Catppuccin Macchiato.xcworkspacecolortheme b/themes/xcode-27/Catppuccin Macchiato.xcworkspacecolortheme new file mode 100644 index 0000000..14a3b16 --- /dev/null +++ b/themes/xcode-27/Catppuccin Macchiato.xcworkspacecolortheme @@ -0,0 +1,625 @@ +{ + "fileVersion": 1, + "recipe": { + "background": { + "customColor": { + "chroma": { + "exact": 0.035341148006 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.833459270729 + }, + "lightness": { + "exact": 0.278808296167 + }, + "opacity": 1 + } + }, + "colorScheme": "dark", + "palette": { + "colorOverrides": { + "plainText": { + "color": { + "chroma": { + "exact": 0.048077489247 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.776356914726 + }, + "lightness": { + "exact": 0.870825079953 + }, + "opacity": 1 + } + }, + "comment": { + "color": { + "chroma": { + "exact": 0.043334704734 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.791605518335 + }, + "lightness": { + "exact": 0.690488286537 + }, + "opacity": 1 + } + }, + "commentEmphasized": { + "color": { + "chroma": { + "exact": 0.043334704734 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.791605518335 + }, + "lightness": { + "exact": 0.690488286537 + }, + "opacity": 1 + } + }, + "markdown": { + "color": { + "chroma": { + "exact": 0.043334704734 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.791605518335 + }, + "lightness": { + "exact": 0.690488286537 + }, + "opacity": 1 + } + }, + "markdownEmphasized": { + "color": { + "chroma": { + "exact": 0.043334704734 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.791605518335 + }, + "lightness": { + "exact": 0.690488286537 + }, + "opacity": 1 + } + }, + "keyword": { + "color": { + "chroma": { + "exact": 0.125895609518 + }, + "gamut": "sRGB", + "hue": { + "radians": 5.30402768172 + }, + "lightness": { + "exact": 0.771522603451 + }, + "opacity": 1 + } + }, + "keyword.attribute": { + "color": { + "chroma": { + "exact": 0.075505990938 + }, + "gamut": "sRGB", + "hue": { + "radians": 3.213151236796 + }, + "lightness": { + "exact": 0.821357769805 + }, + "opacity": 1 + } + }, + "string": { + "color": { + "chroma": { + "exact": 0.107909795615 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.411177882127 + }, + "lightness": { + "exact": 0.834984963782 + }, + "opacity": 1 + } + }, + "string.regex": { + "color": { + "chroma": { + "exact": 0.083027493858 + }, + "gamut": "sRGB", + "hue": { + "radians": 5.867446348931 + }, + "lightness": { + "exact": 0.860804107824 + }, + "opacity": 1 + } + }, + "number": { + "color": { + "chroma": { + "exact": 0.106055575626 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.866339505793 + }, + "lightness": { + "exact": 0.798823064916 + }, + "opacity": 1 + } + }, + "number.character": { + "color": { + "chroma": { + "exact": 0.107909795615 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.411177882127 + }, + "lightness": { + "exact": 0.834984963782 + }, + "opacity": 1 + } + }, + "link": { + "color": { + "chroma": { + "exact": 0.110095548291 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.604358811067 + }, + "lightness": { + "exact": 0.749727817731 + }, + "opacity": 1 + } + }, + "preprocessor": { + "color": { + "chroma": { + "exact": 0.075505990938 + }, + "gamut": "sRGB", + "hue": { + "radians": 3.213151236796 + }, + "lightness": { + "exact": 0.821357769805 + }, + "opacity": 1 + } + }, + "preprocessor.macro": { + "color": { + "chroma": { + "exact": 0.110095548291 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.604358811067 + }, + "lightness": { + "exact": 0.749727817731 + }, + "opacity": 1 + } + }, + "preprocessor.macroSystem": { + "color": { + "chroma": { + "exact": 0.110095548291 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.604358811067 + }, + "lightness": { + "exact": 0.749727817731 + }, + "opacity": 1 + } + }, + "typeDeclaration": { + "color": { + "chroma": { + "exact": 0.07444197179 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.479183616662 + }, + "lightness": { + "exact": 0.87898902692 + }, + "opacity": 1 + } + }, + "memberDeclaration": { + "color": { + "chroma": { + "exact": 0.048077489247 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.776356914726 + }, + "lightness": { + "exact": 0.870825079953 + }, + "opacity": 1 + } + }, + "projectType": { + "color": { + "chroma": { + "exact": 0.07444197179 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.479183616662 + }, + "lightness": { + "exact": 0.87898902692 + }, + "opacity": 1 + } + }, + "projectType.class": { + "color": { + "chroma": { + "exact": 0.07444197179 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.479183616662 + }, + "lightness": { + "exact": 0.87898902692 + }, + "opacity": 1 + } + }, + "projectType.type": { + "color": { + "chroma": { + "exact": 0.07444197179 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.479183616662 + }, + "lightness": { + "exact": 0.87898902692 + }, + "opacity": 1 + } + }, + "projectMember": { + "color": { + "chroma": { + "exact": 0.110095548291 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.604358811067 + }, + "lightness": { + "exact": 0.749727817731 + }, + "opacity": 1 + } + }, + "projectMember.function": { + "color": { + "chroma": { + "exact": 0.110095548291 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.604358811067 + }, + "lightness": { + "exact": 0.749727817731 + }, + "opacity": 1 + } + }, + "projectMember.constant": { + "color": { + "chroma": { + "exact": 0.106055575626 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.866339505793 + }, + "lightness": { + "exact": 0.798823064916 + }, + "opacity": 1 + } + }, + "projectMember.variable": { + "color": { + "chroma": { + "exact": 0.048077489247 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.776356914726 + }, + "lightness": { + "exact": 0.870825079953 + }, + "opacity": 1 + } + }, + "otherType": { + "color": { + "chroma": { + "exact": 0.07444197179 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.479183616662 + }, + "lightness": { + "exact": 0.87898902692 + }, + "opacity": 1 + } + }, + "otherType.class": { + "color": { + "chroma": { + "exact": 0.07444197179 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.479183616662 + }, + "lightness": { + "exact": 0.87898902692 + }, + "opacity": 1 + } + }, + "otherType.type": { + "color": { + "chroma": { + "exact": 0.07444197179 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.479183616662 + }, + "lightness": { + "exact": 0.87898902692 + }, + "opacity": 1 + } + }, + "otherMember": { + "color": { + "chroma": { + "exact": 0.110095548291 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.604358811067 + }, + "lightness": { + "exact": 0.749727817731 + }, + "opacity": 1 + } + }, + "otherMember.function": { + "color": { + "chroma": { + "exact": 0.110095548291 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.604358811067 + }, + "lightness": { + "exact": 0.749727817731 + }, + "opacity": 1 + } + }, + "otherMember.constant": { + "color": { + "chroma": { + "exact": 0.106055575626 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.866339505793 + }, + "lightness": { + "exact": 0.798823064916 + }, + "opacity": 1 + } + }, + "otherMember.variable": { + "color": { + "chroma": { + "exact": 0.048077489247 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.776356914726 + }, + "lightness": { + "exact": 0.870825079953 + }, + "opacity": 1 + } + }, + "selectedTextBackgroundColor": { + "colorWithOpacity": { + "chroma": { + "exact": 0.038508563184 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.833648844337 + }, + "lightness": { + "exact": 0.425903535519 + }, + "opacity": 1 + } + }, + "insertionPointColor": { + "color": { + "chroma": { + "exact": 0.044055828805 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.774045480162 + }, + "lightness": { + "exact": 0.751280535483 + }, + "opacity": 1 + } + }, + "currentLineHighlight": { + "colorWithOpacity": { + "chroma": { + "exact": 0.036946662339 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.816848643113 + }, + "lightness": { + "exact": 0.35379036437 + }, + "opacity": 1 + } + }, + "invisibles": { + "color": { + "chroma": { + "exact": 0.038872274235 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.811581586879 + }, + "lightness": { + "exact": 0.493852276038 + }, + "opacity": 1 + } + }, + "diffAddition": { + "color": { + "chroma": { + "exact": 0.107909795615 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.411177882127 + }, + "lightness": { + "exact": 0.834984963782 + }, + "opacity": 1 + } + }, + "diffDeletion": { + "color": { + "chroma": { + "exact": 0.12515625898 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.195377929147 + }, + "lightness": { + "exact": 0.736999815371 + }, + "opacity": 1 + } + }, + "debugger": { + "color": { + "chroma": { + "exact": 0.107909795615 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.411177882127 + }, + "lightness": { + "exact": 0.834984963782 + }, + "opacity": 1 + } + } + }, + "primary": { + "custom": { + "chroma": { + "exact": 0.083351942198 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.884367968656 + }, + "lightness": { + "exact": 0.814364907951 + }, + "opacity": 1 + } + }, + "secondary": { + "custom": { + "chroma": { + "exact": 0.035341148006 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.833459270729 + }, + "lightness": { + "exact": 0.278808296167 + }, + "opacity": 1 + } + } + } + } +} diff --git a/themes/xcode-27/Catppuccin Mocha.xcworkspacecolortheme b/themes/xcode-27/Catppuccin Mocha.xcworkspacecolortheme new file mode 100644 index 0000000..b2f64fa --- /dev/null +++ b/themes/xcode-27/Catppuccin Mocha.xcworkspacecolortheme @@ -0,0 +1,625 @@ +{ + "fileVersion": 1, + "recipe": { + "background": { + "customColor": { + "chroma": { + "exact": 0.030357353938 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.95518126846 + }, + "lightness": { + "exact": 0.242866940358 + }, + "opacity": 1 + } + }, + "colorScheme": "dark", + "palette": { + "colorOverrides": { + "plainText": { + "color": { + "chroma": { + "exact": 0.042551966398 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.752125575067 + }, + "lightness": { + "exact": 0.87866007372 + }, + "opacity": 1 + } + }, + "comment": { + "color": { + "chroma": { + "exact": 0.03735487088 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.794860660785 + }, + "lightness": { + "exact": 0.686520738673 + }, + "opacity": 1 + } + }, + "commentEmphasized": { + "color": { + "chroma": { + "exact": 0.03735487088 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.794860660785 + }, + "lightness": { + "exact": 0.686520738673 + }, + "opacity": 1 + } + }, + "markdown": { + "color": { + "chroma": { + "exact": 0.03735487088 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.794860660785 + }, + "lightness": { + "exact": 0.686520738673 + }, + "opacity": 1 + } + }, + "markdownEmphasized": { + "color": { + "chroma": { + "exact": 0.03735487088 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.794860660785 + }, + "lightness": { + "exact": 0.686520738673 + }, + "opacity": 1 + } + }, + "keyword": { + "color": { + "chroma": { + "exact": 0.118670085944 + }, + "gamut": "sRGB", + "hue": { + "radians": 5.319227938682 + }, + "lightness": { + "exact": 0.787146247854 + }, + "opacity": 1 + } + }, + "keyword.attribute": { + "color": { + "chroma": { + "exact": 0.079206696649 + }, + "gamut": "sRGB", + "hue": { + "radians": 3.189580301374 + }, + "lightness": { + "exact": 0.858489034205 + }, + "opacity": 1 + } + }, + "string": { + "color": { + "chroma": { + "exact": 0.109228597155 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.49085143217 + }, + "lightness": { + "exact": 0.857704217374 + }, + "opacity": 1 + } + }, + "string.regex": { + "color": { + "chroma": { + "exact": 0.07515773902 + }, + "gamut": "sRGB", + "hue": { + "radians": 5.86961394146 + }, + "lightness": { + "exact": 0.870032601565 + }, + "opacity": 1 + } + }, + "number": { + "color": { + "chroma": { + "exact": 0.101460364818 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.918556801761 + }, + "lightness": { + "exact": 0.823678228403 + }, + "opacity": 1 + } + }, + "number.character": { + "color": { + "chroma": { + "exact": 0.109228597155 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.49085143217 + }, + "lightness": { + "exact": 0.857704217374 + }, + "opacity": 1 + } + }, + "link": { + "color": { + "chroma": { + "exact": 0.111344238876 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.535848458237 + }, + "lightness": { + "exact": 0.766420356986 + }, + "opacity": 1 + } + }, + "preprocessor": { + "color": { + "chroma": { + "exact": 0.079206696649 + }, + "gamut": "sRGB", + "hue": { + "radians": 3.189580301374 + }, + "lightness": { + "exact": 0.858489034205 + }, + "opacity": 1 + } + }, + "preprocessor.macro": { + "color": { + "chroma": { + "exact": 0.111344238876 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.535848458237 + }, + "lightness": { + "exact": 0.766420356986 + }, + "opacity": 1 + } + }, + "preprocessor.macroSystem": { + "color": { + "chroma": { + "exact": 0.111344238876 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.535848458237 + }, + "lightness": { + "exact": 0.766420356986 + }, + "opacity": 1 + } + }, + "typeDeclaration": { + "color": { + "chroma": { + "exact": 0.070414661541 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.51019995624 + }, + "lightness": { + "exact": 0.919302847744 + }, + "opacity": 1 + } + }, + "memberDeclaration": { + "color": { + "chroma": { + "exact": 0.042551966398 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.752125575067 + }, + "lightness": { + "exact": 0.87866007372 + }, + "opacity": 1 + } + }, + "projectType": { + "color": { + "chroma": { + "exact": 0.070414661541 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.51019995624 + }, + "lightness": { + "exact": 0.919302847744 + }, + "opacity": 1 + } + }, + "projectType.class": { + "color": { + "chroma": { + "exact": 0.070414661541 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.51019995624 + }, + "lightness": { + "exact": 0.919302847744 + }, + "opacity": 1 + } + }, + "projectType.type": { + "color": { + "chroma": { + "exact": 0.070414661541 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.51019995624 + }, + "lightness": { + "exact": 0.919302847744 + }, + "opacity": 1 + } + }, + "projectMember": { + "color": { + "chroma": { + "exact": 0.111344238876 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.535848458237 + }, + "lightness": { + "exact": 0.766420356986 + }, + "opacity": 1 + } + }, + "projectMember.function": { + "color": { + "chroma": { + "exact": 0.111344238876 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.535848458237 + }, + "lightness": { + "exact": 0.766420356986 + }, + "opacity": 1 + } + }, + "projectMember.constant": { + "color": { + "chroma": { + "exact": 0.101460364818 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.918556801761 + }, + "lightness": { + "exact": 0.823678228403 + }, + "opacity": 1 + } + }, + "projectMember.variable": { + "color": { + "chroma": { + "exact": 0.042551966398 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.752125575067 + }, + "lightness": { + "exact": 0.87866007372 + }, + "opacity": 1 + } + }, + "otherType": { + "color": { + "chroma": { + "exact": 0.070414661541 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.51019995624 + }, + "lightness": { + "exact": 0.919302847744 + }, + "opacity": 1 + } + }, + "otherType.class": { + "color": { + "chroma": { + "exact": 0.070414661541 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.51019995624 + }, + "lightness": { + "exact": 0.919302847744 + }, + "opacity": 1 + } + }, + "otherType.type": { + "color": { + "chroma": { + "exact": 0.070414661541 + }, + "gamut": "sRGB", + "hue": { + "radians": 1.51019995624 + }, + "lightness": { + "exact": 0.919302847744 + }, + "opacity": 1 + } + }, + "otherMember": { + "color": { + "chroma": { + "exact": 0.111344238876 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.535848458237 + }, + "lightness": { + "exact": 0.766420356986 + }, + "opacity": 1 + } + }, + "otherMember.function": { + "color": { + "chroma": { + "exact": 0.111344238876 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.535848458237 + }, + "lightness": { + "exact": 0.766420356986 + }, + "opacity": 1 + } + }, + "otherMember.constant": { + "color": { + "chroma": { + "exact": 0.101460364818 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.918556801761 + }, + "lightness": { + "exact": 0.823678228403 + }, + "opacity": 1 + } + }, + "otherMember.variable": { + "color": { + "chroma": { + "exact": 0.042551966398 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.752125575067 + }, + "lightness": { + "exact": 0.87866007372 + }, + "opacity": 1 + } + }, + "selectedTextBackgroundColor": { + "colorWithOpacity": { + "chroma": { + "exact": 0.031954626534 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.889574938936 + }, + "lightness": { + "exact": 0.403691417154 + }, + "opacity": 1 + } + }, + "insertionPointColor": { + "color": { + "chroma": { + "exact": 0.039564958111 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.781015198465 + }, + "lightness": { + "exact": 0.750960542462 + }, + "opacity": 1 + } + }, + "currentLineHighlight": { + "colorWithOpacity": { + "chroma": { + "exact": 0.031884540574 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.92145229199 + }, + "lightness": { + "exact": 0.324021885433 + }, + "opacity": 1 + } + }, + "invisibles": { + "color": { + "chroma": { + "exact": 0.033993522916 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.863238547898 + }, + "lightness": { + "exact": 0.476506463651 + }, + "opacity": 1 + } + }, + "diffAddition": { + "color": { + "chroma": { + "exact": 0.109228597155 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.49085143217 + }, + "lightness": { + "exact": 0.857704217374 + }, + "opacity": 1 + } + }, + "diffDeletion": { + "color": { + "chroma": { + "exact": 0.129702139791 + }, + "gamut": "sRGB", + "hue": { + "radians": 0.048243990839 + }, + "lightness": { + "exact": 0.755592006491 + }, + "opacity": 1 + } + }, + "debugger": { + "color": { + "chroma": { + "exact": 0.109228597155 + }, + "gamut": "sRGB", + "hue": { + "radians": 2.49085143217 + }, + "lightness": { + "exact": 0.857704217374 + }, + "opacity": 1 + } + } + }, + "primary": { + "custom": { + "chroma": { + "exact": 0.090951799105 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.839959363353 + }, + "lightness": { + "exact": 0.816596002026 + }, + "opacity": 1 + } + }, + "secondary": { + "custom": { + "chroma": { + "exact": 0.030357353938 + }, + "gamut": "sRGB", + "hue": { + "radians": 4.95518126846 + }, + "lightness": { + "exact": 0.242866940358 + }, + "opacity": 1 + } + } + } + } +}