🚧 Colour picker
This commit is contained in:
parent
8bdc9f16d8
commit
6457bfa63d
5 changed files with 138 additions and 5 deletions
11
package-lock.json
generated
11
package-lock.json
generated
|
@ -1,14 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "mapcompletevscode",
|
"name": "mapcompletevscode",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mapcompletevscode",
|
"name": "mapcompletevscode",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"colortranslator": "^4.1.0",
|
||||||
"jsonc-parser": "^3.3.1"
|
"jsonc-parser": "^3.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -673,6 +674,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/colortranslator": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/colortranslator/-/colortranslator-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-bwa5awaMnQ6dpm9D3nbsFwUr6x6FrTKmxPdolNtSYfxCNR7ZM93GG1OF5Y3Sy1LvYdalb3riKC9uTn0X5NB36g==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
"typescript-eslint": "^8.16.0"
|
"typescript-eslint": "^8.16.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"colortranslator": "^4.1.0",
|
||||||
"jsonc-parser": "^3.3.1"
|
"jsonc-parser": "^3.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { layerCompletionProvider, layerDefinitionProvider } from "./theme";
|
import { layerCompletionProvider, layerDefinitionProvider } from "./theme";
|
||||||
import { iconDefinitionProvider } from "./generic";
|
import { colorProvider, iconDefinitionProvider } from "./generic";
|
||||||
import {
|
import {
|
||||||
filterCompletionProvider,
|
filterCompletionProvider,
|
||||||
filterDefinitionProvider,
|
filterDefinitionProvider,
|
||||||
|
@ -25,5 +25,5 @@ export function activate(context: vscode.ExtensionContext) {
|
||||||
context.subscriptions.push(pathDefinitionProvider);
|
context.subscriptions.push(pathDefinitionProvider);
|
||||||
|
|
||||||
// Activate all generic features
|
// Activate all generic features
|
||||||
context.subscriptions.push(iconDefinitionProvider);
|
context.subscriptions.push(iconDefinitionProvider, colorProvider);
|
||||||
}
|
}
|
||||||
|
|
113
src/generic.ts
113
src/generic.ts
|
@ -8,7 +8,9 @@ import {
|
||||||
getRawCursorPath,
|
getRawCursorPath,
|
||||||
getStartEnd,
|
getStartEnd,
|
||||||
getValueFromPath,
|
getValueFromPath,
|
||||||
|
pathToJSONPath,
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
|
import { ColorTranslator } from "colortranslator";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,3 +80,114 @@ export const iconDefinitionProvider =
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color provider
|
||||||
|
*
|
||||||
|
* Some fields in MapComplete actually represent colors, this provider will provide a color presentation for these fields
|
||||||
|
* Colours can be represented in two ways:
|
||||||
|
* - As a hex color, like #ff0000ff or #ff0000
|
||||||
|
* - As a color name, like red
|
||||||
|
*
|
||||||
|
* JSON paths:
|
||||||
|
* - (layers.{index}.)lineRendering.{index}.color
|
||||||
|
* - (layers.{index}.)lineRendering.{index}.color.render
|
||||||
|
* - (layers.{index}.)lineRendering.{index}.color.mappings.{index}.then
|
||||||
|
* - (layers.{index}.)lineRendering.{index}.fillColor
|
||||||
|
* - (layers.{index}.)lineRendering.{index}.fillColor.render
|
||||||
|
* - (layers.{index}.)lineRendering.{index}.fillColor.mappings.{index}.then
|
||||||
|
* - (layers.{index}.)pointRendering.{index}.marker.{index}.color
|
||||||
|
* - (layers.{index}.)pointRendering.{index}.marker.{index}.color.render
|
||||||
|
* - (layers.{index}.)pointRendering.{index}.marker.{index}.color.mappings.{index}.then
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const colorProvider = vscode.languages.registerColorProvider(
|
||||||
|
{
|
||||||
|
language: "json",
|
||||||
|
scheme: "file",
|
||||||
|
pattern: "**/assets/*/*/*.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provideColorPresentations(color, _context, _token) {
|
||||||
|
console.log("colorProvider.provideColorPresentations");
|
||||||
|
|
||||||
|
const colorHex = new ColorTranslator(
|
||||||
|
`rgba(${color.red * 255}, ${color.green * 255}, ${color.blue * 255}, ${
|
||||||
|
color.alpha
|
||||||
|
})`
|
||||||
|
).HEXA;
|
||||||
|
|
||||||
|
// If the color is fully opaque (AKA it ends with FF), we can remove the alpha channel
|
||||||
|
const colorHexString = colorHex.endsWith("FF")
|
||||||
|
? colorHex.substring(0, 7)
|
||||||
|
: colorHex;
|
||||||
|
|
||||||
|
// TODO: Add color names, maybe convert to short-hand hex
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: colorHexString,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
provideDocumentColors(document, _token) {
|
||||||
|
console.log("colorProvider.provideDocumentColors");
|
||||||
|
|
||||||
|
const text = document.getText();
|
||||||
|
const colors: vscode.ColorInformation[] = [];
|
||||||
|
const jsonParsed = JSON.parse(text);
|
||||||
|
const allPaths: string[] = [];
|
||||||
|
|
||||||
|
// Find all paths in the JSON
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const findPaths = (obj: any, path = "") => {
|
||||||
|
for (const key in obj) {
|
||||||
|
if (typeof obj[key] === "object") {
|
||||||
|
findPaths(obj[key], path + key + ".");
|
||||||
|
} else {
|
||||||
|
allPaths.push(path + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
findPaths(jsonParsed);
|
||||||
|
|
||||||
|
const regexes = [
|
||||||
|
/^(layers.\d+.)?lineRendering.\d+.color((.render)|(.mappings.\d+.then))?$/,
|
||||||
|
/^(layers.\d+.)?lineRendering.\d+.fillColor((.render)|(.mappings.\d+.then))?$/,
|
||||||
|
/^(layers.\d+.)?pointRendering.\d+.marker.\d+.color((.render)|(.mappings.\d+.then))?$/,
|
||||||
|
];
|
||||||
|
|
||||||
|
regexes.forEach((regex) => {
|
||||||
|
allPaths.forEach((path) => {
|
||||||
|
if (regex.exec(path)) {
|
||||||
|
const colorValue = getValueFromPath(text, pathToJSONPath(path));
|
||||||
|
|
||||||
|
let colorRgba;
|
||||||
|
try {
|
||||||
|
colorRgba = new ColorTranslator(colorValue).RGBAObject;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error translating color value:", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Output color: ${colorRgba.R}, ${colorRgba.G}, ${colorRgba.B}, ${colorRgba.A}`
|
||||||
|
);
|
||||||
|
|
||||||
|
colors.push({
|
||||||
|
color: new vscode.Color(
|
||||||
|
colorRgba.R / 255,
|
||||||
|
colorRgba.G / 255,
|
||||||
|
colorRgba.B / 255,
|
||||||
|
colorRgba.A ?? 1
|
||||||
|
),
|
||||||
|
range: getStartEnd(text, pathToJSONPath(path)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return colors;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
12
src/utils.ts
12
src/utils.ts
|
@ -219,3 +219,15 @@ export async function getFilters(): Promise<vscode.CompletionItem[]> {
|
||||||
|
|
||||||
return filtersList;
|
return filtersList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to convert a string path to a JSON path
|
||||||
|
*
|
||||||
|
* @param path String path, separated by dots
|
||||||
|
* @returns JSON path
|
||||||
|
*/
|
||||||
|
export function pathToJSONPath(path: string): JSONPath {
|
||||||
|
return path.split(".").map((str) => {
|
||||||
|
return isNaN(parseInt(str)) ? str : parseInt(str);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue