✨ Add support for filters and license info
This commit is contained in:
parent
61e61a4e2c
commit
4542a9f6b2
5 changed files with 280 additions and 3 deletions
|
@ -8,4 +8,6 @@ Not everything is supported yet, but currently the following features are suppor
|
||||||
- Definition support for the layer names
|
- Definition support for the layer names
|
||||||
- Definintion support for icons
|
- Definintion support for icons
|
||||||
- Autocompletion for tagRenderings in questions.json
|
- Autocompletion for tagRenderings in questions.json
|
||||||
- Definition support for tagRenderings in questions.json
|
- Definition support for tagRenderings
|
||||||
|
- Autocompletion for filter keys in questions.json
|
||||||
|
- Definition support for filter keys
|
||||||
|
|
|
@ -1,14 +1,28 @@
|
||||||
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 { iconDefinitionProvider } from "./generic";
|
||||||
import { tagRenderingCompletionProvider } from "./layers";
|
import {
|
||||||
|
filterCompletionProvider,
|
||||||
|
filterDefinitionProvider,
|
||||||
|
tagRenderingCompletionProvider,
|
||||||
|
tagRenderingDefinitionProvider,
|
||||||
|
} from "./layers";
|
||||||
|
import { pathDefinitionProvider } from "./license_info";
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
// Activate all theme related features
|
// Activate all theme related features
|
||||||
context.subscriptions.push(layerCompletionProvider, layerDefinitionProvider);
|
context.subscriptions.push(layerCompletionProvider, layerDefinitionProvider);
|
||||||
|
|
||||||
// Activate all layer related features
|
// Activate all layer related features
|
||||||
context.subscriptions.push(tagRenderingCompletionProvider);
|
context.subscriptions.push(
|
||||||
|
tagRenderingCompletionProvider,
|
||||||
|
tagRenderingDefinitionProvider,
|
||||||
|
filterCompletionProvider,
|
||||||
|
filterDefinitionProvider
|
||||||
|
);
|
||||||
|
|
||||||
|
// Activate all license info related features
|
||||||
|
context.subscriptions.push(pathDefinitionProvider);
|
||||||
|
|
||||||
// Activate all generic features
|
// Activate all generic features
|
||||||
context.subscriptions.push(iconDefinitionProvider);
|
context.subscriptions.push(iconDefinitionProvider);
|
||||||
|
|
166
src/layers.ts
166
src/layers.ts
|
@ -11,6 +11,7 @@
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import {
|
import {
|
||||||
getCursorPath,
|
getCursorPath,
|
||||||
|
getFilters,
|
||||||
getRawCursorPath,
|
getRawCursorPath,
|
||||||
getStartEnd,
|
getStartEnd,
|
||||||
getTagRenderings,
|
getTagRenderings,
|
||||||
|
@ -18,6 +19,14 @@ import {
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
import { JSONPath } from "jsonc-parser";
|
import { JSONPath } from "jsonc-parser";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag rendering completion provider
|
||||||
|
*
|
||||||
|
* This provider will provide a list of existing tagRenderings for autocompletion
|
||||||
|
*
|
||||||
|
* JSON path:
|
||||||
|
* - (layers.{index}.)tagRenderings.{index}(.builtin)
|
||||||
|
*/
|
||||||
export const tagRenderingCompletionProvider =
|
export const tagRenderingCompletionProvider =
|
||||||
vscode.languages.registerCompletionItemProvider(
|
vscode.languages.registerCompletionItemProvider(
|
||||||
{
|
{
|
||||||
|
@ -55,6 +64,11 @@ export const tagRenderingCompletionProvider =
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag rendering definition provider
|
* Tag rendering definition provider
|
||||||
|
*
|
||||||
|
* This provider will provide a definition for tagRenderings, allowing users to jump to the tagRendering definition
|
||||||
|
*
|
||||||
|
* JSON path:
|
||||||
|
* - (layers.{index}.)tagRenderings.{index}(.builtin)
|
||||||
*/
|
*/
|
||||||
export const tagRenderingDefinitionProvider =
|
export const tagRenderingDefinitionProvider =
|
||||||
vscode.languages.registerDefinitionProvider(
|
vscode.languages.registerDefinitionProvider(
|
||||||
|
@ -154,3 +168,155 @@ export const tagRenderingDefinitionProvider =
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter completion provider
|
||||||
|
*
|
||||||
|
* This provider will provide a list of existing filters for autocompletion
|
||||||
|
*
|
||||||
|
* JSON path:
|
||||||
|
* - (layers.{index}.)filter.{index}
|
||||||
|
*/
|
||||||
|
export const filterCompletionProvider =
|
||||||
|
vscode.languages.registerCompletionItemProvider(
|
||||||
|
{
|
||||||
|
language: "json",
|
||||||
|
scheme: "file",
|
||||||
|
pattern: "**/assets/layers/*/*.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
async provideCompletionItems(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
position: vscode.Position
|
||||||
|
) {
|
||||||
|
// Stop running if the file is called license_info.json
|
||||||
|
if (document.fileName.includes("license_info")) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("filterCompletionProvider");
|
||||||
|
const text = document.getText();
|
||||||
|
const jsonPath = getCursorPath(text, position);
|
||||||
|
|
||||||
|
console.log(jsonPath);
|
||||||
|
|
||||||
|
const regex = /^(layers.\d+.)?filter\.\d+$/;
|
||||||
|
if (regex.exec(jsonPath)) {
|
||||||
|
const filters = await getFilters();
|
||||||
|
console.log(`Got ${filters.length} filters`);
|
||||||
|
|
||||||
|
// Now we need to return the completion items
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter definition provider
|
||||||
|
*
|
||||||
|
* This provider will provide a definition for filters, allowing users to jump to the filter definition
|
||||||
|
*
|
||||||
|
* JSON path:
|
||||||
|
* - (layers.{index}.)filter.{index}
|
||||||
|
*/
|
||||||
|
export const filterDefinitionProvider =
|
||||||
|
vscode.languages.registerDefinitionProvider(
|
||||||
|
{
|
||||||
|
language: "json",
|
||||||
|
scheme: "file",
|
||||||
|
pattern: "**/assets/layers/*/*.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
async provideDefinition(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
position: vscode.Position
|
||||||
|
) {
|
||||||
|
console.log("filterDefinitionProvider");
|
||||||
|
const text = document.getText();
|
||||||
|
const jsonPath = getCursorPath(text, position);
|
||||||
|
const rawJsonPath = getRawCursorPath(text, position);
|
||||||
|
|
||||||
|
const regex = /^(layers.\d.)?filter.\d*$/;
|
||||||
|
|
||||||
|
if (regex.exec(jsonPath)) {
|
||||||
|
const filter = getValueFromPath(text, rawJsonPath);
|
||||||
|
|
||||||
|
if (typeof filter === "string") {
|
||||||
|
console.log("Found reference to filter", filter);
|
||||||
|
if (filter.indexOf(".") === -1) {
|
||||||
|
console.log("This is a built-in filter");
|
||||||
|
// This is a built-in filter
|
||||||
|
// Read the built-in filters file
|
||||||
|
const layerFile = await vscode.workspace.findFiles(
|
||||||
|
"assets/layers/filters/filters.json"
|
||||||
|
);
|
||||||
|
if (layerFile.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const layerText = await vscode.workspace.fs.readFile(
|
||||||
|
layerFile[0]
|
||||||
|
);
|
||||||
|
const layerTextString = new TextDecoder().decode(layerText);
|
||||||
|
const layer = JSON.parse(layerTextString);
|
||||||
|
|
||||||
|
const filterIndex = layer.filter.findIndex(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(f: any) => f.id === filter
|
||||||
|
);
|
||||||
|
|
||||||
|
const path: JSONPath = ["filter", filterIndex];
|
||||||
|
const startEnd = getStartEnd(layerTextString, path);
|
||||||
|
|
||||||
|
const link: vscode.DefinitionLink = {
|
||||||
|
targetUri: layerFile[0],
|
||||||
|
targetRange: startEnd,
|
||||||
|
originSelectionRange: getStartEnd(text, rawJsonPath),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [link];
|
||||||
|
} else {
|
||||||
|
// This is a reference to a filter in another layer
|
||||||
|
// We need to find the layer and the filter
|
||||||
|
const layerName = filter.split(".")[0];
|
||||||
|
const filterName = filter.split(".")[1];
|
||||||
|
|
||||||
|
const layerFile = await vscode.workspace.findFiles(
|
||||||
|
`assets/layers/${layerName}/${layerName}.json`
|
||||||
|
);
|
||||||
|
if (layerFile.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const layerText = await vscode.workspace.fs.readFile(
|
||||||
|
layerFile[0]
|
||||||
|
);
|
||||||
|
const layerTextString = new TextDecoder().decode(layerText);
|
||||||
|
const layer = JSON.parse(layerTextString);
|
||||||
|
|
||||||
|
const filterIndex = layer.filter.findIndex(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(f: any) => f.id === filterName
|
||||||
|
);
|
||||||
|
|
||||||
|
const path: JSONPath = ["filter", filterIndex];
|
||||||
|
const startEnd = getStartEnd(layerTextString, path);
|
||||||
|
|
||||||
|
const link: vscode.DefinitionLink = {
|
||||||
|
targetUri: layerFile[0],
|
||||||
|
targetRange: startEnd,
|
||||||
|
originSelectionRange: getStartEnd(text, rawJsonPath),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
63
src/license_info.ts
Normal file
63
src/license_info.ts
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* This file contains all functions that should be used when editing license_info files
|
||||||
|
* License info files are located in the /assets/{themes/layers}/{name}/license_info.json file
|
||||||
|
*
|
||||||
|
* This consists of the following functions:
|
||||||
|
* - pathDefinitionProvider: Provides a definition for paths, allowing users to jump to the image file
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import * as path from "path";
|
||||||
|
import {
|
||||||
|
getCursorPath,
|
||||||
|
getRawCursorPath,
|
||||||
|
getStartEnd,
|
||||||
|
getValueFromPath,
|
||||||
|
} from "./utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path definition provider
|
||||||
|
*
|
||||||
|
* This provider will provide a definition for paths, allowing users to jump to the image file
|
||||||
|
*
|
||||||
|
* JSON path:
|
||||||
|
* - {index}.path
|
||||||
|
*/
|
||||||
|
export const pathDefinitionProvider =
|
||||||
|
vscode.languages.registerDefinitionProvider(
|
||||||
|
{
|
||||||
|
language: "json",
|
||||||
|
scheme: "file",
|
||||||
|
pattern: "**/assets/*/*/license_info.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provideDefinition(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
position: vscode.Position
|
||||||
|
) {
|
||||||
|
console.log("pathDefinitionProvider");
|
||||||
|
const text = document.getText();
|
||||||
|
const jsonPath = getCursorPath(text, position);
|
||||||
|
const rawPath = getRawCursorPath(text, position);
|
||||||
|
|
||||||
|
const regex = /^\d+.path$/;
|
||||||
|
if (regex.exec(jsonPath)) {
|
||||||
|
const imageFile = getValueFromPath(text, rawPath);
|
||||||
|
console.log("Found reference to filw", imageFile);
|
||||||
|
|
||||||
|
const imagePath = path.join(
|
||||||
|
path.dirname(document.fileName),
|
||||||
|
imageFile
|
||||||
|
);
|
||||||
|
|
||||||
|
const link: vscode.LocationLink = {
|
||||||
|
originSelectionRange: getStartEnd(text, rawPath),
|
||||||
|
targetUri: vscode.Uri.file(imagePath),
|
||||||
|
targetRange: new vscode.Range(0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
32
src/utils.ts
32
src/utils.ts
|
@ -187,3 +187,35 @@ export async function getTagRenderings(): Promise<vscode.CompletionItem[]> {
|
||||||
|
|
||||||
return tagRenderings;
|
return tagRenderings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to get the filters from the filters layer
|
||||||
|
* //TODO: This should get ALL filters, not just from the filters layer
|
||||||
|
*
|
||||||
|
* @returns List of CompletionItems for tagRenderings
|
||||||
|
*/
|
||||||
|
export async function getFilters(): Promise<vscode.CompletionItem[]> {
|
||||||
|
const filtersList: vscode.CompletionItem[] = [];
|
||||||
|
|
||||||
|
// Open the filters layer file
|
||||||
|
const filtersFile = await vscode.workspace.findFiles(
|
||||||
|
"assets/layers/filters/filters.json",
|
||||||
|
"**/node_modules/**"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filtersFile.length === 0) {
|
||||||
|
console.error("filters.json not found");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = await vscode.workspace.fs.readFile(filtersFile[0]);
|
||||||
|
const filters = JSON.parse(new TextDecoder().decode(content));
|
||||||
|
|
||||||
|
for (const filter of filters.filter) {
|
||||||
|
filtersList.push(
|
||||||
|
new vscode.CompletionItem(filter.id, vscode.CompletionItemKind.Value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtersList;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue