From c9dbe1a7ef8b4aac7e336bec6d210d254986ab9e Mon Sep 17 00:00:00 2001 From: Joelant05 <64587014+Joelant05@users.noreply.github.com> Date: Tue, 23 Aug 2022 16:13:49 +0100 Subject: [PATCH] feat: quick fix for lang files --- src/components/Languages/Lang.ts | 73 ++++++++++++--------- src/components/Languages/Lang/guessValue.ts | 29 ++++++++ 2 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 src/components/Languages/Lang/guessValue.ts diff --git a/src/components/Languages/Lang.ts b/src/components/Languages/Lang.ts index d13a118d6..c9932b2ed 100644 --- a/src/components/Languages/Lang.ts +++ b/src/components/Languages/Lang.ts @@ -1,9 +1,10 @@ -import type { languages, editor } from 'monaco-editor' +import type { languages, editor, Range } from 'monaco-editor' import { BedrockProject } from '/@/components/Projects/Project/BedrockProject' import { colorCodes } from './Common/ColorCodes' import { Language } from './Language' import { App } from '/@/App' import { useMonaco } from '/@/utils/libs/useMonaco' +import { guessValue } from './Lang/guessValue' export const config: languages.LanguageConfiguration = { comments: { @@ -77,7 +78,6 @@ const completionItemProvider: languages.CompletionItemProvider = { ) } else { // Generate a value based on the key - // 1. Check whether the cursor is after a key and equals sign, but no value yet (e.g. "tile.minecraft:dirt.name=") const line = model .getValueInRange( new Range( @@ -88,37 +88,10 @@ const completionItemProvider: languages.CompletionItemProvider = { ) ) .toLowerCase() - if (line[line.length - 1] === '=') { - // 2. Find the part of the key that isn't a common key prefix/suffix (e.g. the identifier) - const commonParts = ['name', 'tile', 'item', 'entity', 'action'] - const key = line.substring(0, line.length - 1) - let uniqueParts = key - .split('.') - .filter((part) => !commonParts.includes(part)) - - // 3. If there are 2 parts and one is spawn_egg, then state that "Spawn " should be added to the front of the value - const spawnEggIndex = uniqueParts.indexOf('spawn_egg') - const isSpawnEgg = - uniqueParts.length === 2 && spawnEggIndex >= 0 - if (isSpawnEgg) - uniqueParts.slice(spawnEggIndex, spawnEggIndex + 1) - - // 4. If there is still multiple parts left, search for the part with a namespaced identifier, as that is commonly the bit being translated (e.g. "minecraft:pig" -> "Pig") - if (uniqueParts.length > 1) { - const id = uniqueParts.find((part) => part.includes(':')) - if (id) uniqueParts = [id] - } - - // 5. Hopefully there is only one part left now, if there isn't, the first value will be used. If the value is a namespace (contains a colon), remove the namespace, then capitalise and propose - if (uniqueParts[0].includes(':')) - uniqueParts[0] = uniqueParts[0].split(':').pop() ?? '' - const translation = `${ - isSpawnEgg ? 'Spawn ' : '' - }${uniqueParts[0] - .split('_') - .map((val) => `${val[0].toUpperCase()}${val.slice(1)}`) - .join(' ')}` + // Check whether the cursor is after a key and equals sign, but no value yet (e.g. "tile.minecraft:dirt.name=") + if (line[line.length - 1] === '=') { + const translation = (await guessValue(line)) ?? '' suggestions.push({ label: translation, insertText: translation, @@ -138,6 +111,41 @@ const completionItemProvider: languages.CompletionItemProvider = { } }, } +const codeActionProvider: languages.CodeActionProvider = { + provideCodeActions: async ( + model: editor.ITextModel, + range: Range, + context: languages.CodeActionContext + ) => { + const actions: languages.CodeAction[] = [] + for (const marker of context.markers) { + const line = model.getLineContent(marker.startLineNumber) + const val = await guessValue(line) + + actions.push({ + title: 'Add value to key', + diagnostics: [marker], + kind: 'quickfix', + edit: { + edits: [ + { + resource: model.uri, + edit: { + range, + text: `${line}=${val}`, + }, + }, + ], + }, + isPreferred: true, + }) + } + return { + actions: actions, + dispose: () => {}, + } + }, +} export class LangLanguage extends Language { constructor() { @@ -147,6 +155,7 @@ export class LangLanguage extends Language { config, tokenProvider, completionItemProvider, + codeActionProvider, }) // Highlight namespaces diff --git a/src/components/Languages/Lang/guessValue.ts b/src/components/Languages/Lang/guessValue.ts new file mode 100644 index 000000000..a4bb9d781 --- /dev/null +++ b/src/components/Languages/Lang/guessValue.ts @@ -0,0 +1,29 @@ +export async function guessValue(line: string) { + // 1. Find the part of the key that isn't a common key prefix/suffix (e.g. the identifier) + const commonParts = ['name', 'tile', 'item', 'entity', 'action'] + const key = line.substring(0, line.length - 1) + let uniqueParts = key + .split('.') + .filter((part) => !commonParts.includes(part)) + + // 2. If there are 2 parts and one is spawn_egg, then state that "Spawn " should be added to the front of the value + const spawnEggIndex = uniqueParts.indexOf('spawn_egg') + const isSpawnEgg = uniqueParts.length === 2 && spawnEggIndex >= 0 + if (isSpawnEgg) uniqueParts.slice(spawnEggIndex, spawnEggIndex + 1) + + // 3. If there is still multiple parts left, search for the part with a namespaced identifier, as that is commonly the bit being translated (e.g. "minecraft:pig" -> "Pig") + if (uniqueParts.length > 1) { + const id = uniqueParts.find((part) => part.includes(':')) + if (id) uniqueParts = [id] + } + + // 4. Hopefully there is only one part left now, if there isn't, the first value will be used. If the value is a namespace (contains a colon), remove the namespace, then capitalise and propose + if (uniqueParts[0].includes(':')) + uniqueParts[0] = uniqueParts[0].split(':').pop() ?? '' + const translation = `${isSpawnEgg ? 'Spawn ' : ''}${uniqueParts[0] + .split('_') + .map((val) => `${val[0].toUpperCase()}${val.slice(1)}`) + .join(' ')}` + + return translation +}