Document Color¶
This implements the textDocument/documentColor and textDocument/colorPresentation requests.
Together these methods allow you to teach a language client how to recognise and display colors that may appear in your document. As an example, think of the different ways you can write a color in a CSS file
black#000#000000rgb(0, 0, 0)hsl(...)etc.
By implementing the textDocument/documentColor request you can tell the client about
all the places within a document that represent a color, and what its equivalent RGBA
value is.
In VSCode
these locations will be represented by a small colored square next to the color value.
Some editors (like VSCode) also provide a color picker.
By implementing the textDocument/colorPresentation request, you provide the
conversion from an RGBA color value into its equivalent representation in your document’s
syntax.
This will allow the user to easily choose new color values from within their text editor.
This server implements the requests defined above for CSS’s hex color code syntax
(#000 and #000000).
import logging
import re
from lsprotocol import types
from pygls.cli import start_server
from pygls.lsp.server import LanguageServer
COLOR = re.compile(r"""\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})(?!\w)""")
server = LanguageServer("color-server", "v1")
@server.feature(
types.TEXT_DOCUMENT_DOCUMENT_COLOR,
)
def document_color(params: types.CodeActionParams):
"""Return a list of colors declared in the document."""
items = []
document_uri = params.text_document.uri
document = server.workspace.get_text_document(document_uri)
for linum, line in enumerate(document.lines):
for match in COLOR.finditer(line.strip()):
start_char, end_char = match.span()
# Is this a short form color?
if (end_char - start_char) == 4:
color = "".join(c * 2 for c in match.group(1))
value = int(color, 16)
else:
value = int(match.group(1), 16)
# Split the single color value into a value for each color channel.
blue = (value & 0xFF) / 0xFF
green = (value & (0xFF << 8)) / (0xFF << 8)
red = (value & (0xFF << 16)) / (0xFF << 16)
items.append(
types.ColorInformation(
color=types.Color(red=red, green=green, blue=blue, alpha=1.0),
range=types.Range(
start=types.Position(line=linum, character=start_char),
end=types.Position(line=linum, character=end_char),
),
)
)
return items
@server.feature(
types.TEXT_DOCUMENT_COLOR_PRESENTATION,
)
def color_presentation(params: types.ColorPresentationParams):
"""Given a color, instruct the client how to insert the representation of that
color into the document"""
color = params.color
b = int(color.blue * 255)
g = int(color.green * 255)
r = int(color.red * 255)
# Combine each color channel into a single value
value = (r << 16) | (g << 8) | b
return [types.ColorPresentation(label=f"#{value:0{6}x}")]
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, format="%(message)s")
start_server(server)