diff --git a/.claude/CODING_GUIDE.md b/.claude/CODING_GUIDE.md
new file mode 100644
index 00000000..661ba764
--- /dev/null
+++ b/.claude/CODING_GUIDE.md
@@ -0,0 +1,23 @@
+## Coding Style & Guidelines
+
+- Whenever possible, prioritize code readability over code efficiency.
+- Always write code that's short and concise. Make good use of early return techniques, and be careful not to create too much depth in conditional statements or loops.
+- For object-type properties or types or interfaces, always sort in alphabetical order whenever possible.
+- Always keep variable and property names concise but clear.
+- Always maintain a clear separation of concerns. However, be careful not to over-segregate, such as through premature optimization.
+- You should always write your code in a way that makes it easy to unit test.
+- Comments shouldn't be used unless absolutely necessary. Write readable code that can be understood without comments, and only include comments for unavoidable business logic.
+- Variable values should be separated into constants whenever possible. Avoid creating magic numbers.
+- If a complex implementation is required, always consider using a commercial library or tool instead of coding it yourself.
+- Work should always be done agilely, in small units, and in meaningful change units.
+- Instead of rushing to implement it, you should always focus on writing clean code that doesn't create bugs and is easy to maintain.
+- If you feel like there's too much code in a single file, you should first review the overall structure and figure out how to neatly separate the files.
+- Always understand the surrounding code context, and when you see signs of reuse, modularize it to avoid code duplication.
+- The depth of loops and conditional statements should be as minimal as possible. It's best to avoid them altogether.
+- If a function is likely to have more than three arguments, always consider making them object or struct arguments.
+
+## TypeScript Coding Guidelines
+
+- When using TypeScript, avoid using unsafe type systems such as the any type and type assertions whenever possible.
+- Always use Type instead of Interface
+- Always use arrow functions outside of a class.
diff --git a/.vscodeignore b/.vscodeignore
index b1ee4106..674fc386 100644
--- a/.vscodeignore
+++ b/.vscodeignore
@@ -7,7 +7,6 @@ src/extension/*.spec.ts
src/extension/*.spec.js
# Development dependencies
-src/extension/node_modules/
src/web-view/node_modules/
# Development config files
@@ -37,9 +36,6 @@ public/*.gif
node_modules/
frontend/
-# Old build outputs (no longer used)
-src/extension/out/
-
# Development files
.env
.env.*
@@ -94,4 +90,4 @@ coverage/
.nyc_output/
# Logs
-*.log
\ No newline at end of file
+*.log
diff --git a/README.md b/README.md
index 255c40d4..6879aad4 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,7 @@ _Execute any command instantly from your status bar - no more hunting through me
- ⚡ **Instant Access**: Click any button to run terminal commands or VS Code functions
- 🎨 **Color-Coded**: Distinguish different command types with custom colors
- 📱 **Smart Terminals**: Each command gets its own named terminal session
+- ⌨️ **Multi-Language Keyboard Shortcuts**: Use shortcuts in your native keyboard layout - Korean `ㅅ` automatically maps to English `t`, Japanese `あ` to `a`, etc. Supports 15 languages including Korean, Japanese, Chinese, Hindi, Russian, Arabic, and more
@@ -161,12 +162,23 @@ Use `Ctrl+Shift+P` → `Toggle Configuration Target` or the button in Configurat
- **`Ctrl+Shift+;`** - Open command palette
- **Single keys** - Quick command execution in groups (e.g., press `g` then `s` for Git Status)
+### Multi-Language Keyboard Support
+
+- **🌐 Global Compatibility** - Works seamlessly with 15 keyboard layouts and input methods: Korean, Russian, Arabic, Hebrew, German, Spanish, Czech, Greek, Persian, Belarusian, Ukrainian, Kazakh, Japanese, Chinese, and Hindi
+- **🔄 Auto-Translation** - Shortcuts automatically map between keyboard layouts and transliteration systems
+- **⌨️ Natural Typing** - Use your native keyboard layout without switching to English
+- **🎯 Smart Matching** - Type `ㅂ` on Korean keyboard to trigger `q` shortcuts, or `あ` in Japanese to match romaji equivalents
+- **🇯🇵 Japanese Support** - Hiragana, Katakana, and Romaji conversion using WanaKana library
+- **🇨🇳 Chinese Support** - Traditional and Simplified Chinese with Pinyin conversion
+- **🇮🇳 Hindi Support** - Devanagari script with IAST transliteration support
+
### Pro Tips
- Use `$(icon-name)` syntax for VS Code icons in button names
- Group related commands to keep status bar clean
- Use `executeAll: true` for monitoring multiple processes
- Mix terminal commands with VS Code API calls seamlessly
+- Type shortcuts in your native keyboard layout - no need to switch to English!
### 📚 Helpful References
@@ -226,14 +238,15 @@ _Comprehensive sidebar panel for command management_
## 🆚 Why Choose Quick Command Buttons?
-| Feature | Quick Command Buttons | Other Extensions |
-| ----------------------------- | ------------------------------ | -------------------- |
-| **Intelligent Grouping** | ✅ Unlimited nesting | ❌ Limited or none |
-| **Visual Configuration** | ✅ Drag & drop UI | ❌ Manual JSON only |
-| **Multiple Access Points** | ✅ Status bar + Tree + Palette | ❌ Single method |
-| **Smart Terminal Management** | ✅ Named, organized terminals | ❌ Generic terminals |
-| **Mixed Command Types** | ✅ Terminal + VS Code API | ❌ Usually one type |
-| **Real-time Updates** | ✅ Instant configuration sync | ❌ Restart required |
+| Feature | Quick Command Buttons | Other Extensions |
+| ----------------------------- | -------------------------------------------------------- | -------------------- |
+| **Intelligent Grouping** | ✅ Unlimited nesting | ❌ Limited or none |
+| **Visual Configuration** | ✅ Drag & drop UI | ❌ Manual JSON only |
+| **Multiple Access Points** | ✅ Status bar + Tree + Palette | ❌ Single method |
+| **Smart Terminal Management** | ✅ Named, organized terminals | ❌ Generic terminals |
+| **Mixed Command Types** | ✅ Terminal + VS Code API | ❌ Usually one type |
+| **Multi-Language Keyboards** | ✅ 15 languages (Korean, Japanese, Chinese, Hindi, etc.) | ❌ English only |
+| **Real-time Updates** | ✅ Instant configuration sync | ❌ Restart required |
## 🛠️ Commands Reference
diff --git a/package.json b/package.json
index e41999ef..755096be 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"activationEvents": [
"onStartupFinished"
],
- "main": "./out/src/main.js",
+ "main": "./src/extension/out/src/main.js",
"contributes": {
"commands": [
{
diff --git a/src/extension/package.json b/src/extension/package.json
index 13ae601d..be4f9519 100644
--- a/src/extension/package.json
+++ b/src/extension/package.json
@@ -17,5 +17,11 @@
"jest": "^30.1.3",
"ts-jest": "^29.4.1",
"typescript": "5.9.2"
+ },
+ "dependencies": {
+ "@indic-transliteration/sanscript": "^1.3.3",
+ "convert-layout": "^0.11.1",
+ "pinyin": "^4.0.0",
+ "wanakana": "^5.3.1"
}
}
diff --git a/src/extension/src/command-executor.test.ts b/src/extension/src/command-executor.test.ts
index 39ae3bb7..604e8c19 100644
--- a/src/extension/src/command-executor.test.ts
+++ b/src/extension/src/command-executor.test.ts
@@ -207,6 +207,50 @@ describe("command-executor", () => {
expect(result).toBeUndefined();
});
+
+ it("should find item with Korean character matching English shortcut", () => {
+ const result = findShortcutItem(items, "ㅁ");
+
+ expect(result).toEqual(items[0]);
+ });
+
+ it("should find item with Korean character ㅠ matching English shortcut b", () => {
+ const result = findShortcutItem(items, "ㅠ");
+
+ expect(result).toEqual(items[1]);
+ });
+
+ it("should find item with Russian character matching English shortcut", () => {
+ const result = findShortcutItem(items, "ф");
+
+ expect(result).toEqual(items[0]);
+ });
+
+ it("should handle Arabic characters", () => {
+ const arabicItems = [
+ {
+ command: { name: "test1", shortcut: "z" } as ButtonConfig,
+ description: "",
+ label: "Test 1",
+ },
+ ];
+ const result = findShortcutItem(arabicItems, "ض");
+
+ expect(result).toEqual(arabicItems[0]);
+ });
+
+ it("should handle Hebrew characters", () => {
+ const hebrewItems = [
+ {
+ command: { name: "test1", shortcut: "e" } as ButtonConfig,
+ description: "",
+ label: "Test 1",
+ },
+ ];
+ const result = findShortcutItem(hebrewItems, "ק");
+
+ expect(result).toEqual(hebrewItems[0]);
+ });
});
describe("determineButtonExecutionType", () => {
diff --git a/src/extension/src/command-executor.ts b/src/extension/src/command-executor.ts
index f3b4814a..1ffac6cb 100644
--- a/src/extension/src/command-executor.ts
+++ b/src/extension/src/command-executor.ts
@@ -1,6 +1,7 @@
import * as vscode from "vscode";
import { ButtonConfig } from "./types";
import { TerminalExecutor, QuickPickCreator } from "./adapters";
+import { findMatchingShortcut } from "./keyboard-layout-converter";
export type QuickPickItem = {
label: string;
@@ -32,8 +33,17 @@ export const findShortcutItem = (
): QuickPickItem | undefined => {
if (inputValue.length !== 1) return undefined;
+ const shortcuts = items
+ .map((item) => item.command.shortcut)
+ .filter((shortcut): shortcut is string => Boolean(shortcut));
+
+ const matchingShortcut = findMatchingShortcut(inputValue, shortcuts);
+
+ if (!matchingShortcut) return undefined;
+
return items.find(
- (item) => item.command.shortcut?.toLowerCase() === inputValue.toLowerCase()
+ (item) =>
+ item.command.shortcut?.toLowerCase() === matchingShortcut.toLowerCase()
);
};
diff --git a/src/extension/src/keyboard-layout-converter.test.ts b/src/extension/src/keyboard-layout-converter.test.ts
new file mode 100644
index 00000000..b1d9fb78
--- /dev/null
+++ b/src/extension/src/keyboard-layout-converter.test.ts
@@ -0,0 +1,143 @@
+import {
+ generateKeyVariants,
+ findMatchingShortcut,
+} from "./keyboard-layout-converter";
+
+describe("generateKeyVariants", () => {
+ it("should return input key with case variations for single character", () => {
+ const variants = generateKeyVariants("q");
+ expect(variants).toContain("q");
+ expect(variants).toContain("Q");
+ });
+
+ it("should include Korean conversion for q key", () => {
+ const variants = generateKeyVariants("q");
+ expect(variants).toContain("ㅂ");
+ });
+
+ it("should include English conversion for Korean key", () => {
+ const variants = generateKeyVariants("ㅂ");
+ expect(variants).toContain("q");
+ });
+
+ it("should return original input for non-single character input", () => {
+ const variants = generateKeyVariants("abc");
+ expect(variants).toEqual(["abc"]);
+ });
+
+ it("should return original input for empty string", () => {
+ const variants = generateKeyVariants("");
+ expect(variants).toEqual([""]);
+ });
+
+ it("should handle Russian characters", () => {
+ const variants = generateKeyVariants("й");
+ expect(variants).toContain("q");
+ });
+
+ it("should handle Arabic characters", () => {
+ const variants = generateKeyVariants("ض");
+ expect(variants).toContain("z");
+ });
+
+ it("should handle Hebrew characters", () => {
+ const variants = generateKeyVariants("ק");
+ expect(variants).toContain("e");
+ });
+
+ it("should handle German characters", () => {
+ const variants = generateKeyVariants("ü");
+ expect(variants).toContain("[");
+ });
+
+ it("should handle Spanish characters", () => {
+ const variants = generateKeyVariants("ñ");
+ expect(variants).toContain(";");
+ });
+
+ it("should handle Greek characters", () => {
+ const variants = generateKeyVariants("θ");
+ expect(variants).toContain("u");
+ });
+
+ it("should handle Japanese hiragana characters", () => {
+ const variants = generateKeyVariants("あ");
+ expect(variants).toContain("a");
+ });
+
+ it("should handle Japanese katakana characters", () => {
+ const variants = generateKeyVariants("ア");
+ expect(variants).toContain("a");
+ });
+
+ it("should handle Chinese characters", () => {
+ const variants = generateKeyVariants("你");
+ expect(variants).toContain("你");
+ });
+
+ it("should handle Hindi Devanagari characters", () => {
+ const variants = generateKeyVariants("अ");
+ expect(variants).toContain("a");
+ });
+
+ it("should handle numbers and special characters", () => {
+ const variants = generateKeyVariants("1");
+ expect(variants).toContain("1");
+ });
+});
+
+describe("findMatchingShortcut", () => {
+ const shortcuts = ["q", "t", "g", "n"];
+
+ it("should find exact match for English character", () => {
+ const result = findMatchingShortcut("q", shortcuts);
+ expect(result).toBe("q");
+ });
+
+ it("should find match for Korean character mapping to English", () => {
+ const result = findMatchingShortcut("ㅂ", shortcuts);
+ expect(result).toBe("q");
+ });
+
+ it("should find match for Russian character mapping to English", () => {
+ const result = findMatchingShortcut("й", shortcuts);
+ expect(result).toBe("q");
+ });
+
+ it("should return undefined for non-matching character", () => {
+ const result = findMatchingShortcut("x", shortcuts);
+ expect(result).toBeUndefined();
+ });
+
+ it("should return undefined for multi-character input", () => {
+ const result = findMatchingShortcut("qt", shortcuts);
+ expect(result).toBeUndefined();
+ });
+
+ it("should handle case insensitive matching", () => {
+ const result = findMatchingShortcut("Q", shortcuts);
+ expect(result).toBe("q");
+ });
+
+ it("should handle empty shortcuts array", () => {
+ const result = findMatchingShortcut("q", []);
+ expect(result).toBeUndefined();
+ });
+
+ it("should handle shortcuts with undefined values", () => {
+ const result = findMatchingShortcut("q", ["q", undefined as any, "t"]);
+ expect(result).toBe("q");
+ });
+
+ it("should match Korean ㅅ with t shortcut", () => {
+ const shortcutsWithT = ["s", "t", "g"];
+ const result = findMatchingShortcut("ㅅ", shortcutsWithT);
+ expect(result).toBe("t");
+ });
+
+ it("should match Korean ㄴ with s shortcut", () => {
+ const shortcutsWithS = ["s", "t", "g"];
+ const result = findMatchingShortcut("ㄴ", shortcutsWithS);
+ expect(result).toBe("s");
+ });
+});
diff --git a/src/extension/src/keyboard-layout-converter.ts b/src/extension/src/keyboard-layout-converter.ts
new file mode 100644
index 00000000..b3c0de5e
--- /dev/null
+++ b/src/extension/src/keyboard-layout-converter.ts
@@ -0,0 +1,180 @@
+import kr from "convert-layout/kr";
+import ru from "convert-layout/ru";
+import ar from "convert-layout/ar";
+import he from "convert-layout/he";
+import de from "convert-layout/de";
+import es from "convert-layout/es";
+import cs from "convert-layout/cs";
+import gr from "convert-layout/gr";
+import fa from "convert-layout/fa";
+import by from "convert-layout/by";
+import uk from "convert-layout/uk";
+import kk from "convert-layout/kk";
+import * as wanakana from "wanakana";
+import pinyin from "pinyin";
+import * as sanscript from "@indic-transliteration/sanscript";
+
+type LayoutConverter = {
+ toEn: (text: string) => string;
+ fromEn: (text: string) => string;
+};
+
+const LAYOUT_CONVERTERS: Array<{ converter: LayoutConverter; name: string }> = [
+ { converter: kr, name: "kr" }, // Korean (한국어)
+ { converter: ru, name: "ru" }, // Russian (русский)
+ { converter: ar, name: "ar" }, // Arabic (العربية)
+ { converter: he, name: "he" }, // Hebrew (עברית)
+ { converter: de, name: "de" }, // German (Deutsch)
+ { converter: es, name: "es" }, // Spanish (Español)
+ { converter: cs, name: "cs" }, // Czech (Čeština)
+ { converter: gr, name: "gr" }, // Greek (Ελληνικά)
+ { converter: fa, name: "fa" }, // Persian/Farsi (فارسی)
+ { converter: by, name: "by" }, // Belarusian (Беларуская)
+ { converter: uk, name: "uk" }, // Ukrainian (Українська)
+ { converter: kk, name: "kk" }, // Kazakh (Қазақша)
+];
+
+const japaneseConverter: LayoutConverter = {
+ toEn: (text: string): string => {
+ if (wanakana.isJapanese(text)) {
+ return wanakana.toRomaji(text);
+ }
+ return text;
+ },
+ fromEn: (text: string): string => {
+ if (wanakana.isRomaji(text)) {
+ return wanakana.toHiragana(text);
+ }
+ return text;
+ },
+};
+
+const chineseConverter: LayoutConverter = {
+ toEn: (text: string): string => {
+ try {
+ const pinyinResult = pinyin(text, {
+ style: pinyin.STYLE_NORMAL,
+ heteronym: false,
+ segment: false,
+ });
+ return pinyinResult.flat().join("");
+ } catch {
+ return text;
+ }
+ },
+ fromEn: (text: string): string => {
+ return text;
+ },
+};
+
+const hindiConverter: LayoutConverter = {
+ toEn: (text: string): string => {
+ try {
+ return sanscript.t(text, "devanagari", "iast");
+ } catch {
+ return text;
+ }
+ },
+ fromEn: (text: string): string => {
+ try {
+ return sanscript.t(text, "iast", "devanagari");
+ } catch {
+ return text;
+ }
+ },
+};
+
+const ADVANCED_CONVERTERS: Array<{ converter: LayoutConverter; name: string }> =
+ [
+ { converter: japaneseConverter, name: "ja" }, // Japanese (日本語)
+ { converter: chineseConverter, name: "zh" }, // Chinese (中文)
+ { converter: hindiConverter, name: "hi" }, // Hindi (हिन्दी)
+ ];
+
+const ALL_CONVERTERS = [...LAYOUT_CONVERTERS, ...ADVANCED_CONVERTERS];
+
+export const generateKeyVariants = (inputKey: string): string[] => {
+ if (!inputKey || inputKey.length !== 1) {
+ return [inputKey];
+ }
+
+ const variants = new Set();
+ variants.add(inputKey.toLowerCase());
+ variants.add(inputKey.toUpperCase());
+
+ const processConversion = (conversionFn: (text: string) => string) => {
+ const convertedKey = conversionFn(inputKey);
+ if (
+ convertedKey &&
+ convertedKey !== inputKey &&
+ convertedKey.length === 1
+ ) {
+ variants.add(convertedKey.toLowerCase());
+ variants.add(convertedKey.toUpperCase());
+ }
+ };
+
+ try {
+ for (const layout of ALL_CONVERTERS) {
+ try {
+ processConversion(layout.converter.toEn);
+ processConversion(layout.converter.fromEn);
+ } catch (error) {
+ console.warn(`Error in layout converter "${layout.name}":`, error);
+ continue;
+ }
+ }
+ } catch (error) {
+ console.warn("Error generating key variants:", error);
+ }
+
+ return Array.from(variants);
+};
+
+export const findMatchingShortcut = (
+ inputValue: string,
+ shortcuts: string[]
+): string | undefined => {
+ if (inputValue.length !== 1) {
+ return undefined;
+ }
+
+ try {
+ const inputVariants = new Set(
+ generateKeyVariants(inputValue).map((v) => v.toLowerCase())
+ );
+
+ const exactCaseMatch = shortcuts.find((shortcut) => {
+ if (!shortcut) return false;
+ return shortcut === inputValue;
+ });
+ if (exactCaseMatch) {
+ return exactCaseMatch;
+ }
+
+ const directCaseMatch = shortcuts.find((shortcut) => {
+ if (!shortcut) return false;
+ return shortcut.toLowerCase() === inputValue.toLowerCase();
+ });
+ if (directCaseMatch) {
+ return directCaseMatch;
+ }
+
+ const layoutMatch = shortcuts.find((shortcut) => {
+ if (!shortcut) return false;
+
+ const shortcutVariants = generateKeyVariants(shortcut);
+ return shortcutVariants.some((variant) =>
+ inputVariants.has(variant.toLowerCase())
+ );
+ });
+
+ return layoutMatch;
+ } catch (error) {
+ console.warn("Error in findMatchingShortcut:", error);
+ return shortcuts.find(
+ (shortcut) =>
+ shortcut && shortcut.toLowerCase() === inputValue.toLowerCase()
+ );
+ }
+};
diff --git a/src/extension/src/types/convert-layout.d.ts b/src/extension/src/types/convert-layout.d.ts
new file mode 100644
index 00000000..39496b58
--- /dev/null
+++ b/src/extension/src/types/convert-layout.d.ts
@@ -0,0 +1,91 @@
+type LayoutConverter = {
+ toEn(text: string): string;
+ fromEn(text: string): string;
+};
+
+declare module "convert-layout/kr" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/ru" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/ar" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/he" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/de" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/es" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/cs" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/gr" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/fa" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/by" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/uk" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "convert-layout/kk" {
+ const converter: LayoutConverter;
+ export default converter;
+}
+
+declare module "wanakana" {
+ export const isJapanese: (text: string) => boolean;
+ export const isRomaji: (text: string) => boolean;
+ export const toRomaji: (text: string) => string;
+ export const toHiragana: (text: string) => string;
+}
+
+declare module "pinyin" {
+ type PinyinOptions = {
+ style?: number;
+ heteronym?: boolean;
+ segment?: boolean;
+ };
+
+ type PinyinFunction = {
+ (text: string, options?: PinyinOptions): string[][];
+ STYLE_NORMAL: number;
+ };
+
+ const pinyin: PinyinFunction;
+ export default pinyin;
+}
+
+declare module "@indic-transliteration/sanscript" {
+ export const t: (text: string, from: string, to: string) => string;
+}
diff --git a/src/extension/tsconfig.json b/src/extension/tsconfig.json
index 7468fc1f..09480ada 100644
--- a/src/extension/tsconfig.json
+++ b/src/extension/tsconfig.json
@@ -2,7 +2,7 @@
"compilerOptions": {
"module": "commonjs",
"target": "ES2020",
- "outDir": "../../out",
+ "outDir": "./out",
"lib": ["ES2020", "dom"],
"sourceMap": true,
"rootDir": ".",
diff --git a/src/extension/yarn.lock b/src/extension/yarn.lock
index 6fb040ea..5588a299 100644
--- a/src/extension/yarn.lock
+++ b/src/extension/yarn.lock
@@ -292,6 +292,19 @@
dependencies:
tslib "^2.4.0"
+"@indic-transliteration/common_maps@^1.0.2":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@indic-transliteration/common_maps/-/common_maps-1.0.5.tgz#a63e653fbf6e15e8152086044e1bae2c24c1f3ee"
+ integrity sha512-XbWDA5AXGE+Nh4uGr/yN9ZM8avRBy4F1KQL+DLgQGOdsQ390lcW4fga0NSjg4C/rOpMd0rHZv2YFV3Bq3UbpkQ==
+
+"@indic-transliteration/sanscript@^1.3.3":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@indic-transliteration/sanscript/-/sanscript-1.3.3.tgz#2d70995b8efde50035cd89b0b33516c0e8d8b568"
+ integrity sha512-zNGeARmQTPIlubwgEhl/JumpwTPHrdT/cNsQeCL+G67SQmjJe3qRnMIYghXiVt7+KDso/pU1Ky2ZfD/RBISfJQ==
+ dependencies:
+ "@indic-transliteration/common_maps" "^1.0.2"
+ toml "^2.3.6"
+
"@isaacs/cliui@^8.0.2":
version "8.0.2"
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
@@ -1064,11 +1077,23 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+commander@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-1.1.1.tgz#50d1651868ae60eccff0a2d9f34595376bc6b041"
+ integrity sha512-71Rod2AhcH3JhkBikVpNd0pA+fWsmAaVoti6OR38T76chA7vE3pSerS0Jor4wDw+tOueD2zLVvFOw5H0Rcj7rA==
+ dependencies:
+ keypress "0.1.x"
+
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+convert-layout@^0.11.1:
+ version "0.11.1"
+ resolved "https://registry.yarnpkg.com/convert-layout/-/convert-layout-0.11.1.tgz#823bd72268e1a959f2433348a44a9c7185bba22e"
+ integrity sha512-Zy+yE2AqFZUYZxvwS/He7DmnwEahGdy/GyiM33YdxoixyI1YZCYYup2OEYnrhn5r34L9YRa+PZC2ooVmQHY9oQ==
+
convert-source-map@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
@@ -1796,6 +1821,11 @@ json5@^2.2.3:
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+keypress@0.1.x:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.1.0.tgz#4a3188d4291b66b4f65edb99f806aa9ae293592a"
+ integrity sha512-x0yf9PL/nx9Nw9oLL8ZVErFAk85/lslwEP7Vz7s5SI1ODXZIgit3C5qyWjw4DxOuO/3Hb4866SQh28a1V1d+WA==
+
leven@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
@@ -2026,6 +2056,13 @@ picomatch@^4.0.2:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042"
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
+pinyin@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/pinyin/-/pinyin-4.0.0.tgz#9c15fd9d45c08b6813221fc602f77759429bfa4f"
+ integrity sha512-vHpV5K+vpp6XUUpZNGRDuHoN+1xcmieM3EWlH4QjSX2kkpG/gVOwpqwV9EOJ9x9c9UERFKeLml5XVSukE/PLgQ==
+ dependencies:
+ commander "~1.1.1"
+
pirates@^4.0.7:
version "4.0.7"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22"
@@ -2249,6 +2286,11 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
+toml@^2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.6.tgz#25b0866483a9722474895559088b436fd11f861b"
+ integrity sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==
+
ts-jest@^29.4.1:
version "29.4.1"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.4.1.tgz#42d33beb74657751d315efb9a871fe99e3b9b519"
@@ -2355,6 +2397,11 @@ walker@^1.0.8:
dependencies:
makeerror "1.0.12"
+wanakana@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/wanakana/-/wanakana-5.3.1.tgz#e20798fb9687d926d4aad25874bc8e66096818ed"
+ integrity sha512-OSDqupzTlzl2LGyqTdhcXcl6ezMiFhcUwLBP8YKaBIbMYW1wAwDvupw2T9G9oVaKT9RmaSpyTXjxddFPUcFFIw==
+
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
diff --git a/versions/quick-command-buttons-0.2.3.vsix b/versions/quick-command-buttons-0.2.3.vsix
index fa13a93c..e1db72cb 100644
Binary files a/versions/quick-command-buttons-0.2.3.vsix and b/versions/quick-command-buttons-0.2.3.vsix differ