LSP
LSP copied to clipboard
Investigate the possibility to trigger a color picker on clicking color boxes
It would be neat to be able to trigger a color picker by clicking a color box. This probably means LSP should ship with or download platform-dependent color picker executables, and add anchor tags to all color boxes phantoms.
I was looking into this. A popular color picker on packagecontrol.io is this one: https://github.com/weslly/ColorPicker
That package puts compiled binaries in the git repo. The source code is seemingly:
https://github.com/jnordberg/color-pick/blob/master/colorpick.m (macOS)
I think this can be done a lot easier for macOS at least... here's a plugin that does about the same thing
import sublime
import subprocess
import json
__script = '''
function run(argv) {{
var app = Application.currentApplication();
app.includeStandardAdditions = true;
var color = app.chooseColor({{defaultColor: [{red}, {green}, {blue}]}});
console.log(JSON.stringify(color));
}}
'''
def plugin_loaded():
script = __script.format(red=0.5, green=0.2, blue=0.1)
args = ("/usr/bin/osascript", "-l", "JavaScript", "-e", script)
output = subprocess.check_output(args, stderr=subprocess.STDOUT)
color = json.loads(output.decode('ascii').strip())
print("color:", color)
Here is the essential code for Windows, extracted from that package. It uses the native color picker from the win32 API (no additional binary required) and doesn't support an alpha channel for colors. ST becomes unresponsive as long as the color picker dialog is open, which probably could be avoided by using a separate thread for the color picker, but more code would be required then before inserting the color result into the buffer if the buffer was changed in the meantime. So it's a poor mans "modal dialog" solution for now ;)
import sublime
import sublime_plugin
import ctypes
CC_SOLIDCOLOR = 0x80
CC_RGBINIT = 0x01
CC_FULLOPEN = 0x02
red = 0.5
green = 0.2
blue = 0.1
default_color = (round(255*blue) << 16) | (round(255*green) << 8) | round(255*red)
class CHOOSECOLOR(ctypes.Structure):
_fields_ = [
("lStructSize", ctypes.c_uint32),
("hwndOwner", ctypes.c_void_p),
("hInstance", ctypes.c_void_p),
("rgbResult", ctypes.c_uint32),
("lpCustColors", ctypes.POINTER(ctypes.c_uint32)),
("Flags", ctypes.c_uint32),
("lCustData", ctypes.c_void_p),
("lpfnHook", ctypes.c_void_p),
("lpTemplateName", ctypes.c_wchar_p)]
def bgr2hexcolor(bgr):
# 0x00BBGGRR
byte_table = list(["{0:02X}".format(b) for b in range(256)])
b = byte_table[(bgr >> 16) & 0xff]
g = byte_table[(bgr >> 8) & 0xff]
r = byte_table[(bgr) & 0xff]
return "#" + (r + g + b).lower()
def plugin_loaded():
ChooseColorW = ctypes.windll.Comdlg32.ChooseColorW
ChooseColorW.argtypes = [ctypes.POINTER(CHOOSECOLOR)]
ChooseColorW.restype = ctypes.c_int32
cc = CHOOSECOLOR()
ctypes.memset(ctypes.byref(cc), 0, ctypes.sizeof(cc))
cc.lStructSize = ctypes.sizeof(cc)
cc.hwndOwner = None
CustomColors = ctypes.c_uint32 * 16
cc.lpCustColors = CustomColors() # uses 0 (black) for all 16 predefined custom colors
cc.rgbResult = ctypes.c_uint32(default_color)
cc.Flags = CC_SOLIDCOLOR | CC_FULLOPEN | CC_RGBINIT
# ST window will become unresponsive until color picker dialog is closed
result = ChooseColorW(ctypes.byref(cc))
if result == 1: # user clicked OK
print(bgr2hexcolor(cc.rgbResult))
elif result == 0:
print("User clicked Cancel or closed the dialog")
Relevant request: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_colorPresentation