aboutsummaryrefslogtreecommitdiffstats
path: root/qt-qml/src/color-provider.ts
blob: 9fa6dc493c302095b1aaf9520380c2c2d202cd92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only

import * as vscode from 'vscode';

export function registerColorProvider() {
  return vscode.languages.registerColorProvider(
    'qml',
    createArgbHexColorProvider()
  );
}

function createArgbHexColorProvider() {
  return {
    provideDocumentColors(document: vscode.TextDocument) {
      const regex = /#[0-9a-f]{3,8}\b/gi;
      const matches = document.getText().matchAll(regex);
      const info: vscode.ColorInformation[] = [];

      Array.from(matches).forEach((m) => {
        const color = hexToColor(m.toString());
        const r = new vscode.Range(
          document.positionAt(m.index),
          document.positionAt(m.index + m[0].length)
        );

        if (color) {
          info.push(new vscode.ColorInformation(r, color));
        }
      });

      return info;
    },

    provideColorPresentations(color: vscode.Color) {
      return [new vscode.ColorPresentation(colorToHex(color))];
    }
  };
}

function hexToColor(hex: string): vscode.Color | undefined {
  if (!hex.startsWith('#')) {
    return undefined;
  }

  if (hex.length === 4) {
    const r = parseInt(hex.substring(1, 2), 16) / 15;
    const g = parseInt(hex.substring(2, 3), 16) / 15;
    const b = parseInt(hex.substring(3, 4), 16) / 15;

    return new vscode.Color(r, g, b, 1);
  }

  if (hex.length === 7 || hex.length == 9) {
    const rgb = hex.slice(-6);

    const r = parseInt(rgb.substring(0, 2), 16) / 255;
    const g = parseInt(rgb.substring(2, 4), 16) / 255;
    const b = parseInt(rgb.substring(4, 6), 16) / 255;
    const a = hex.length === 9 ? parseInt(hex.substring(1, 3), 16) / 255 : 1;

    return new vscode.Color(r, g, b, a);
  }

  return undefined;
}

function colorToHex(color: vscode.Color) {
  function fractionToHexDigits(f: number): string {
    const s = Math.round(f * 255)
      .toString(16)
      .substring(0, 2);
    return s.length < 2 ? '0' + s : s;
  }

  const a = fractionToHexDigits(color.alpha);
  const r = fractionToHexDigits(color.red);
  const g = fractionToHexDigits(color.green);
  const b = fractionToHexDigits(color.blue);

  return color.alpha === 1 ? `#${r}${g}${b}` : `#${a}${r}${g}${b}`;
}