Sublime Forum

Reliably resolve the background color of a theme?

#1

So I accidentally managed (thanks to some help from ChatGPT) to write a sublime plugin that categorizes all color schemes into light and dark, and lists them in 2 separate lists in command palette.

There is only one small issue:

I load both .sublime-color-scheme and .tmTheme and parse them manually (as json and xml respectively). However, the background that I get from them is not always what sublime displays. That’s for 3 reasons.

  1. Sometimes it’s a variable (I hacked a workaround where I just regex match certain common colors, that are typically used in the var name).
  2. Sometimes it’s a calculation / formula.
  3. Sometimes there are multiple mentions of the background in the tmTheme file. I tried getting the first instance, and the last instance, but sometimes Sublime seems to pick neither when you set the theme.

My question is: is there a way to reliably get the resolved main background color (in hex) as sublime would actually apply it? Any help much appreciated.

0 Likes

#2
view.style()['background']
0 Likes

#3

@deathaxe Nice thank you! Is this only available after theme has been applied? Is there a way to get it before applying? (I can still work with that but would be so much better).

0 Likes

#4

Looking at API reference, I could probably create a blank view and apply themes to its private settings, collecting backgrounds, but ideally it would be more direct.

0 Likes

#5

My god, it’s working. Can’t believe I am seeing this feature, been wanting to have this for like 10 years. :joy:

0 Likes

#6

You could also create an unlisted output panel, alter its color scheme setting, and use the API mentioned above. The effect would be the same, without needing an extra tab or for colors to flash.

0 Likes

#7

@OdatNurd Thanks! I did the following:

self.temp_view = self.window.new_file()
self.temp_view.set_scratch(True)

# for each theme:
  self.temp_view.settings().set('color_scheme', scheme_path)
  background = self.temp_view.style()['background']

self.temp_view.close()

And weirdly (but happily for me) it doesn’t show anything on the screen. No tab, no flashing. It’s also pretty fast (even though I have the entire Colorsublime cache). Do you think unlisted output panel is still better for some technical reason?

0 Likes

#8

I suppose in theory even if you don’t see any updates happening, creating and then closing the tab might get in the way of something else, like the tab navigation order or something (though offhand I don’t know what those things would be).

If what you’re doing works for you, I wouldn’t go out of my way to change it.

0 Likes

#9

Decided to heed the advice, and switch to unlisted panel for good measure. Works great.

1 Like

#10

Hi @hakunin do you have this somewhere available, sounds like something that I would like too

0 Likes

#11

I’m thinking to publish it as a plugin soon, so stay tuned. Will mention it here when I do.

0 Likes

#12

I made a package and submitted it to package control, waiting for PR merge, hopefully it’s all good. It’s a small piece of Python, any code review would be highly appreciated.

0 Likes

#13

Your package could possibly be improved by respecting the (undocumented) "show_legacy_color_schemes" user setting, which should default to false to comply with the behavior of the builtin color scheme picker. Currently, all color schemes are shown.

The builtin picker also uses a debounce time of 250 ms before changing the color scheme when you scroll through the list with the arrow keys (that’s frankly not a necessary feature, but rather nice to have).

For more information, run “View Package File” from the command palette and select Default/ui.py.

0 Likes

#14

Great, debounce sounds useful.

One other thing I was wondering is scheme names. Currently they don’t look as neat as the ones shown by other tools, and I bet there is a better way to obtain them than what I’m doing:

def get_scheme_name(self, scheme_path):
    name_with_extension = scheme_path.split('/')[-1]
    name = name_with_extension.split('.')[0]
    return name
0 Likes

#16

This is essentially what the builtin command is doing. Although the builtin command is using a more streamlined approach

for f in sublime.find_resources('*.sublime-color-scheme'):
        basename = os.path.basename(f)
        name = os.path.splitext(basename)[0]
        if name not in nameset:
            nameset.add(name)
            files.append((f, basename))
1 Like

#17

Alright, you can now install Color Scheme Categorizer via Package Control. Then you’ll get 2 new menu command palette items:

  • UI: Select Color Scheme: Light
  • UI: Select Color Scheme: Dark

/cc @bempelise

1 Like

#18

Thank you very much!

0 Likes