Skip to content

Commit 882bfbb

Browse files
feat(js): plugin utilities
close #89
1 parent b61d769 commit 882bfbb

File tree

4 files changed

+131
-1
lines changed

4 files changed

+131
-1
lines changed

scripts/bindgen/quickjs-types.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,25 @@ declare module "mshell" {
1313
type uintptr_t = number;
1414
type ssize_t = number;
1515
}
16+
17+
// helper to access field based on dot path
18+
type FieldPath<T, K extends string> = K extends keyof T ? T[K] : K extends `${infer K1}.${infer K2}` ? K1 extends keyof T ? FieldPath<T[K1], K2> : never : never;
19+
20+
declare function plugin<T = object>(import_meta: { name: string; url: string }, default_config?: T): {
21+
i18n: {
22+
define(lang: string, data: { [key: string]: string }): void;
23+
t(key: string): string;
24+
};
25+
set_on_menu(callback: (m:
26+
import('mshell').menu_controller
27+
) => void): void;
28+
config_directory: string;
29+
config: {
30+
read_config(): void;
31+
write_config(): void;
32+
get<K extends string>(key: K): FieldPath<T, K>;
33+
set<K extends string>(key: K, value: FieldPath<T, K>): void;
34+
all(): T;
35+
};
36+
log(...args: any[]): void;
37+
};

src/shell/script/binding_qjs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ template <> struct qjs::js_traits<mb_shell::js::folder_view_folder_item> {
5656

5757
obj.index = js_traits<int>::unwrap(ctx, JS_GetPropertyStr(ctx, v, "index"));
5858

59+
obj.parent_path = js_traits<std::string>::unwrap(ctx, JS_GetPropertyStr(ctx, v, "parent_path"));
60+
5961
return obj;
6062
}
6163

@@ -64,6 +66,8 @@ template <> struct qjs::js_traits<mb_shell::js::folder_view_folder_item> {
6466

6567
JS_SetPropertyStr(ctx, obj, "index", js_traits<int>::wrap(ctx, val.index));
6668

69+
JS_SetPropertyStr(ctx, obj, "parent_path", js_traits<std::string>::wrap(ctx, val.parent_path));
70+
6771
return obj;
6872
}
6973
};
@@ -78,6 +82,7 @@ template<> struct js_bind<mb_shell::js::folder_view_folder_item> {
7882
.fun<&mb_shell::js::folder_view_folder_item::type>("type")
7983
.fun<&mb_shell::js::folder_view_folder_item::select>("select")
8084
.fun<&mb_shell::js::folder_view_folder_item::index>("index")
85+
.fun<&mb_shell::js::folder_view_folder_item::parent_path>("parent_path")
8186
;
8287
}
8388

src/shell/script/binding_types.d.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export class example_struct_jni {
2828

2929
export class folder_view_folder_item {
3030
index: number
31+
parent_path: string
3132

3233
/**
3334
*
@@ -1342,3 +1343,25 @@ declare module "mshell" {
13421343
type uintptr_t = number;
13431344
type ssize_t = number;
13441345
}
1346+
1347+
// helper to access field based on dot path
1348+
type FieldPath<T, K extends string> = K extends keyof T ? T[K] : K extends `${infer K1}.${infer K2}` ? K1 extends keyof T ? FieldPath<T[K1], K2> : never : never;
1349+
1350+
declare function plugin<T = object>(import_meta: { name: string; url: string }, default_config?: T): {
1351+
i18n: {
1352+
define(lang: string, data: { [key: string]: string }): void;
1353+
t(key: string): string;
1354+
};
1355+
set_on_menu(callback: (m:
1356+
import('mshell').menu_controller
1357+
) => void): void;
1358+
config_directory: string;
1359+
config: {
1360+
read_config(): void;
1361+
write_config(): void;
1362+
get<K extends string>(key: K): FieldPath<T, K>;
1363+
set<K extends string>(key: K, value: FieldPath<T, K>): void;
1364+
all(): T;
1365+
};
1366+
log(...args: any[]): void;
1367+
};

src/shell/script/script.js

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,88 @@ const splitIntoLines = (str, maxLen) => {
4545
return lines
4646
}
4747

48+
// Breeze infrastructure
49+
4850
globalThis.on_plugin_menu = {};
4951

52+
const plugin = (import_meta, default_config = {}) => {
53+
const CONFIG_FILE = '/config.json'
54+
55+
const { name, url } = import_meta
56+
const languages = {}
57+
58+
const nameNoExt = name.endsWith('.js') ? name.slice(0, -3) : name
59+
60+
let config = default_config
61+
62+
const plugin = {
63+
i18n: {
64+
define: (lang, data) => {
65+
languages[lang] = data
66+
},
67+
t: (key) => {
68+
return languages[shell.breeze.user_language()][key] || key
69+
}
70+
},
71+
set_on_menu: (callback) => {
72+
on_plugin_menu[nameNoExt] = callback
73+
},
74+
config_directory: shell.breeze.data_directory() + '/config/' + nameNoExt,
75+
config: {
76+
read_config() {
77+
if (shell.fs.exists(plugin.config_directory + CONFIG_FILE)) {
78+
try {
79+
config = JSON.parse(shell.fs.read(config_dir + CONFIG_FILE))
80+
} catch (e) {
81+
shell.println(`[${name}] 配置文件解析失败: ${e}`)
82+
}
83+
}
84+
},
85+
write_config() {
86+
shell.fs.write(plugin.config_directory + CONFIG_FILE, JSON.stringify(config, null, 4))
87+
},
88+
get(key) {
89+
const read = (keys, obj) => {
90+
if (keys.length === 1) {
91+
return obj[keys[0]]
92+
}
93+
if (!obj[keys[0]]) {
94+
return undefined
95+
}
96+
return read(keys.slice(1), obj[keys[0]])
97+
}
98+
99+
return read(key.split('.'), config)
100+
},
101+
set(key, value) {
102+
let obj = config
103+
104+
const keys = key.split('.')
105+
for (let i = 0; i < keys.length - 1; i++) {
106+
if (!obj[keys[i]]) {
107+
obj[keys[i]] = {}
108+
}
109+
obj = obj[keys[i]]
110+
}
111+
obj[keys[keys.length - 1]] = value
112+
113+
plugin.config.write_config()
114+
},
115+
all() {
116+
return config
117+
}
118+
},
119+
log(...args) {
120+
shell.println(`[${name}]`, ...args)
121+
}
122+
}
123+
124+
shell.fs.mkdir(plugin.config_directory)
125+
return plugin
126+
}
127+
128+
globalThis.plugin = plugin
129+
50130
const languages = {
51131
'zh-CN': {
52132
},
@@ -93,7 +173,7 @@ shell.menu_controller.add_menu_listener(ctx => {
93173
sub.append_menu({
94174
name: t('加载中...')
95175
})
96-
176+
97177
if (!cached_plugin_index) {
98178
cached_plugin_index = await get_async(PLUGIN_SOURCES[current_source] + 'plugins-index.json')
99179
}

0 commit comments

Comments
 (0)