errno == -ERIC

itc2kc, A really limited and silly project to convert a terminal theme

Back On My Bullshit Again (fixating on my terminal setup)

Another day, another rabbit trail setting up my terminal on a new machine, sigh... But at least this time I produced a small little project out of it! Basically my favorite terminal theme, Bliss, currently only has a terminal theme for iTerm2. I've been using kitty now as my daily driver for terminal emulation and I wanted to give it a fresh coat of bliss. The problem though is that these two terminal emulators have differing formats for their themes. iTerm2 uses an XML-based .itermcolors file, while kitty uses a simple .conf. The XML format is kind of a pain to work with so I wasn't super thrilled to dive into XML parsing again. Figured I'd throw it over to Claude for a starting point.

Claude's First Attempt

I don't love handing the controls over to AI immediately so the way I've been using these tools lately is when I don't want to relearn something from scratch that I've messed with in the past. In this case, I've used lxml and the built-in Python XML module (although it's unclear if this is advisable1 any more?). To start here's the prompt I gave Claude:

I would like to convert an itermcolors file into a kitty.conf file. Could you use Python to write a short script to convert an .itermcolors to a kitty theme .conf file?

Claude's response:

I'll write a Python script to convert an .itermcolors file (which is an XML format) to a kitty theme .conf file. This will help you use your iTerm2 color schemes in the kitty terminal emulator.

This script converts iTerm2 color schemes (.itermcolors files) to Kitty terminal configuration (.conf) files. Here's how to use it:

  1. Save the script as itermcolors_to_kitty.py
  2. Make it executable: chmod +x itermcolors_to_kitty.py
  3. Run it: ./itermcolors_to_kitty.py path/to/your/theme.itermcolors [optional_output_file.conf]

The script:

  • Parses the XML structure of the iTerm2 color scheme
  • Maps the iTerm2 color keys to their Kitty equivalents
  • Converts the RGB values from 0-1 floats to hexadecimal format
  • Generates a properly formatted Kitty theme configuration

If you don't specify an output file, it will create one with the same name as the input file but with a .conf extension. The output will be a fully functional Kitty theme that you can place in your Kitty configuration directory.

Note: This implementation uses ElementTree.getnext() which might require the lxml library. If you get an error, you can install it with pip install lxml.

You can see the first result here.

Things I thought it did good on:

Things I thought it did bad on:

At this point, I wanted to give Claude another shot before I proceeded on my own.

Take 2

My next prompt was this:

This is a great structure, but the xml library used incorrect. Can you please rewrite this using lxml?2

Claude's Reponse:

You're right - the standard ElementTree doesn't have the getnext() method. Let me rewrite the script using lxml which will properly handle this XML structure.

I've rewritten the script to use lxml instead of the standard XML library. The main changes include:

  1. Changed the import from xml.etree.ElementTree to lxml.etree
  2. Completely rewrote the XML parsing logic to manually traverse the element tree instead of using getnext()
  3. Added better error handling for invalid file formats
  4. Fixed the mapping for Bold Color to use bold_color in kitty's format

To use this script:

  1. Install the lxml library first: pip install lxml
  2. Save the script as itermcolors_to_kitty.py
  3. Make it executable: chmod +x itermcolors_to_kitty.py
  4. Run it: ./itermcolors_to_kitty.py path/to/your/theme.itermcolors [optional_output_file.conf]

This implementation properly handles the plist XML structure of iTerm2 color schemes and should work with any standard .itermcolors file.

Same as before, code output for Round 2 can be found here

Things I thought it did good:

Things I thought it did bad:

Artisan Crafted Scripting

At this point, I decided that I had an okay scaffold to do the rest myself. Things that I added:

I am particularly proud of the XPath part so I'm going to walk through the expression I came up with

Xtraordinary XPaths

The annoying thing about the .itermcolors XML is that it has a flatter structure than I would expect. <keys> are on the same level as their values so we have to parse the correct sibling instead of assuming the value is a child or the tag's text. Here's a snippet:

<key>Ansi 4 Color</key>
<dict>
	<key>Alpha Component</key>
	<real>1</real>
	<key>Blue Component</key>
	<real>1</real>
	<key>Color Space</key>
	<string>sRGB</string>
	<key>Green Component</key>
	<real>0.5980377197265625</real>
	<key>Red Component</key>
	<real>0.63416916131973267</real>
</dict>

We need to select the text in the <real> tags corresponding to the RGB values. This is what I came up with after a bit of XPath learning:

key[text() = 'Red Component']/following-sibling::real[1]/text()

Note: s/Red/(Green|Blue)/ for those values respectively

This XPath string can be used from a color's <dict> element. The way this expression works is by looking for a <key> with text matching "Red Component". The expression then checks for the next <real> tag that is a sibling of the matched <key> and finally returns the text of the <real> tag.

Praise For uv

A really quick section to praise uv. I'm consistently amazed at how well this tool works for setting up Python projects. Every feature just works, and it all make sense. I wish more tooling were this good. I genuinely enjoy setting up Python projects now. I've been finding my standard setup for them to be:

Setting these up before I ran my script for the first time really limited the few bugs/typos I had to a handful and they were very easy to diagnose.

The End!

This package is now published on PyPI. I hit a few snags due to a uv misconfiguration on my part I'm open to PRs, feel free to send contributions.

  1. There's a whole table of vulnerabilities in Python's docs about the built-in XML modules. I'm not an expert so hard to say how frequent these are encountered but they don't seem great at a glance!

  2. Embarrassing typos remain because that's the level of transparency we're operating at for our dear readers of errno == -ERIC

  3. I'm a C programmer myself so I'm allowed to say this

#claude #kitty #python #uv