aviutl2_macros/lib.rs
1//! # aviutl2-macros
2//!
3//! [aviutl2-rs](https://docs.rs/aviutl2)のためのproc macroを提供するクレート。
4//! 詳細は[aviutl2-rs](https://docs.rs/aviutl2)のドキュメントを参照してください。
5
6mod filter_config_items;
7mod filter_config_select_items;
8mod from_script_module_param;
9mod generic_menus;
10mod into_script_module_return_value;
11mod module_functions;
12mod plugin;
13mod utils;
14
15/// `FilterConfigItems` を自動で実装するためのマクロ。
16///
17/// このマクロは他の`derive`などのマクロより先に適用する必要があります。
18///
19/// # Attributes
20///
21/// - structのフィールドはすべてちょうど1つの属性を持つ必要があります。
22///
23/// ## `track`
24///
25/// ```rust
26/// # #[aviutl2_macros::filter_config_items]
27/// # struct S {
28/// #[track(name = "サンプル整数", range = 0..=100, default = 50, step = 1.0)]
29/// int_field: i32,
30/// #[track(name = "サンプル小数", range = 0.0..=1.0, default = 0.5, step = 0.01)]
31/// float_field: f64,
32/// # }
33/// ```
34///
35/// - `name`: トラックバーの名前。省略した場合、フィールド名が使用されます。
36/// - `range`: トラックバーの範囲。閉区間で指定します(例: `0.0..=1.0`)。
37/// - `default`: トラックバーの初期値。
38/// - `step`: トラックバーのステップ値。`1.0`, `0.1`, `0.01`, `0.001` のいずれかを指定します。
39///
40/// - `range`、`default`は`step`で割り切れる値である必要があります。
41/// - 値の型はプリミティブ、厳密には`value as _`で変換可能な型である必要があります。
42///
43/// ## `check`
44///
45/// ```rust
46/// # #[aviutl2_macros::filter_config_items]
47/// # struct S {
48/// #[check(name = "サンプルチェックボックス", default = true)]
49/// bool_field: bool,
50/// # }
51/// ```
52///
53/// - `name`: チェックボックスの名前。省略した場合、フィールド名が使用されます。
54/// - `default`: チェックボックスの初期値。
55///
56/// - 値の型は`bool`である必要があります。
57///
58/// ## `color`
59///
60/// ```rust
61/// # #[aviutl2_macros::filter_config_items]
62/// # struct S {
63/// #[color(name = "サンプルカラー", default = 0x48b0d5)]
64/// color_field: aviutl2::filter::FilterConfigColorValue,
65/// #[color(name = "サンプルカラー2", default = "#48b0d5")]
66/// color_field2: aviutl2::filter::FilterConfigColorValue,
67/// #[color(name = "サンプルカラー3", default = (72, 176, 213))]
68/// color_field3: aviutl2::filter::FilterConfigColorValue,
69/// # }
70/// ```
71///
72/// - `name`: 色選択の名前。省略した場合、フィールド名が使用されます。
73/// - `default`: 色の初期値。`0xRRGGBB`形式の整数、`"#RRGGBB"`形式の文字列、または`(R, G, B)`形式のタプルで指定します。
74///
75/// - 値の型は`From<aviutl2::filter::FilterConfigColorValue>`を実装している必要があります。
76///
77/// ## `select`
78///
79/// ```rust
80/// # #[aviutl2_macros::filter_config_items]
81/// # struct S {
82/// #[select(
83/// name = "サンプルセレクトボックス",
84/// items = ["オプション1", "オプション2", "オプション3"],
85/// default = 0
86/// )]
87/// select_field: usize,
88/// # }
89/// ```
90///
91/// ```rust
92/// #[derive(aviutl2::filter::FilterConfigSelectItems)]
93/// enum MySelectItem {
94/// #[item(name = "Hoge")]
95/// Hoge,
96/// #[item(name = "Fuga")]
97/// Fuga,
98/// }
99///
100/// #[aviutl2_macros::filter_config_items]
101/// struct MyConfig {
102/// #[select(
103/// name = "サンプルセレクトボックス",
104/// items = MySelectItem,
105/// default = MySelectItem::Hoge
106/// )]
107/// select_field: MySelectItem,
108/// }
109/// ```
110///
111/// - `name`: セレクトボックスの名前。省略した場合、フィールド名が使用されます。
112/// - `items`: セレクトボックスの項目のリスト、または`aviutl2::filter::FilterConfigSelectItems`を実装したenumの名前。
113/// - `default`: セレクトボックスの初期値。`items`のインデックス、またはenumのVariantを指定します。
114///
115/// - 値の型は`default`が`items`のインデックスの場合は`usize`、
116/// `default`がenumのVariantの場合はそのenumである必要があります。
117///
118/// ## `file`
119///
120/// ```rust
121/// # #[aviutl2_macros::filter_config_items]
122/// # struct S {
123/// #[file(name = "サンプルファイル", filters = {
124/// "テキストファイル" => ["txt"],
125/// "すべてのファイル" => []
126/// })]
127/// file_field: std::path::PathBuf,
128/// # }
129/// ```
130///
131/// - `name`: ファイル選択の名前。省略した場合、フィールド名が使用されます。
132/// - `filters`: ファイルフィルタのリスト。キーがフィルタ名、値が拡張子のリストです。
133///
134/// - 値の型は`std::path::PathBuf`である必要があります。
135///
136/// ## `string`
137///
138/// ```rust
139/// # #[aviutl2_macros::filter_config_items]
140/// # struct S {
141/// #[string(name = "サンプル文字列", default = "初期値")]
142/// string_field: String,
143/// # }
144/// ```
145///
146/// - `name`: 文字列項目の名前。省略した場合、フィールド名が使用されます。
147/// - `default`: 文字列の初期値。省略した場合、空文字列になります。
148///
149/// - 値の型は`String`である必要があります。
150///
151/// ## `text`
152///
153/// ```rust
154/// # #[aviutl2_macros::filter_config_items]
155/// # struct S {
156/// #[text(name = "サンプルテキスト", default = "複数行テキスト")]
157/// text_field: String,
158/// # }
159/// ```
160///
161/// - `name`: テキスト項目の名前。省略した場合、フィールド名が使用されます。
162/// - `default`: テキストの初期値。省略した場合、空文字列になります。
163///
164/// - 値の型は`String`である必要があります。
165///
166/// ## `folder`
167///
168/// ```rust
169/// # #[aviutl2_macros::filter_config_items]
170/// # struct S {
171/// #[folder(name = "サンプルフォルダ", default = "C:\\\\")]
172/// folder_field: String,
173/// # }
174/// ```
175///
176/// - `name`: フォルダ選択の名前。省略した場合、フィールド名が使用されます。
177/// - `default`: フォルダの初期値。省略した場合、空文字列になります。
178///
179/// - 値の型は`String`である必要があります。
180///
181/// ## `data`
182///
183/// ```rust
184/// # use aviutl2::filter::FilterConfigDataHandle;
185/// # #[derive(Debug, Default, Clone, Copy)]
186/// # struct MyData {
187/// # value: i32,
188/// # }
189/// # #[aviutl2_macros::filter_config_items]
190/// # struct S {
191/// #[data(name = "サンプルデータ", default = MyData { value: 0 })]
192/// data_field: FilterConfigDataHandle<MyData>,
193/// # }
194/// ```
195///
196/// - `name`: データの名前。省略した場合、フィールド名が使用されます。
197/// - `default`: データの初期値。省略した場合、`Default::default()`が使用されます。
198///
199/// - 値の型は`aviutl2::filter::FilterConfigDataHandle<T>`である必要があります。
200///
201/// ## `group`
202///
203/// ```rust
204/// # #[aviutl2_macros::filter_config_items]
205/// # struct S {
206/// #[group(name = "サンプルグループ", opened = true)]
207/// group: group! {
208/// // ...
209/// # #[check(name = "フィールド", default = false)]
210/// # field: bool,
211/// },
212/// # }
213/// ```
214///
215/// グループとしてフィールドをまとめます。
216///
217/// - `name`: グループの名前。省略した場合、フィールド名が使用されます。
218/// - `opened`: グループが初期状態で開いているかどうか。省略した場合、`true`になります。
219///
220/// - 型には`group! { ... }`と記述する必要があります。
221/// - `group! { ... }`の中には他のフィールドを同様に記述します。
222/// - このフィールドは削除されます。
223///
224/// ## `button`
225///
226/// ```rust,ignore
227/// # #[aviutl2_macros::filter_config_items]
228/// # struct S {
229/// #[button(name = "サンプルボタン")]
230/// button: on_button_pressed,
231/// # }
232/// ```
233///
234/// `aviutl2::filter::FilterConfigItem::Button`を挿入します。
235///
236/// - `name`: ボタンの名前。省略した場合、フィールド名が使用されます。
237/// - 型には関数名を指定します。また、関数名とフィールド名が同じ場合は`fn()`と省略できます。
238/// - 関数のシグネチャは以下のようになります。
239///
240/// ```rust
241/// fn on_button_pressed(handle: &mut aviutl2::generic::EditSection) { /* ... */ }
242/// ```
243///
244/// - このフィールドは削除されます。
245///
246/// # Example
247///
248/// ```rust
249/// use aviutl2::filter::FilterConfigDataHandle;
250///
251/// #[derive(Debug, Default, Clone, Copy)]
252/// struct MyData {
253/// value: i32,
254/// }
255///
256/// fn my_button_handler(handle: &mut aviutl2::generic::EditSection) {
257/// // ボタンが押されたときの処理
258/// }
259///
260/// #[aviutl2_macros::filter_config_items]
261/// #[derive(Debug)]
262/// struct FilterConfig {
263/// #[group(name = "サンプルグループ", opened = true)]
264/// sample_group: group! {
265/// #[track(name = "サンプル整数", range = -100..=100, default = 0, step = 1.0)]
266/// sample_integer: i32,
267/// #[track(name = "サンプル小数", range = -1.0..=1.0, default = 0.0, step = 0.01)]
268/// sample_float: f64,
269/// },
270/// #[check(name = "サンプルチェックボックス", default = true)]
271/// sample_checkbox: bool,
272/// #[select(
273/// name = "サンプルセレクトボックス",
274/// items = ["オプション1", "オプション2", "オプション3"],
275/// default = 0
276/// )]
277/// sample_select: usize,
278/// #[color(name = "サンプルカラー", default = 0x48b0d5)]
279/// sample_color: aviutl2::filter::FilterConfigColorValue,
280/// #[file(name = "サンプルファイル", filters = {
281/// "テキストファイル" => ["txt"],
282/// "すべてのファイル" => [],
283/// })]
284/// sample_file: std::path::PathBuf,
285/// #[data(name = "サンプルデータ")]
286/// sample_data: FilterConfigDataHandle<MyData>,
287///
288/// #[button(name = "サンプルボタン")]
289/// on_button_pressed: my_button_handler,
290/// }
291/// ```
292///
293/// # See Also
294///
295/// - [`FilterConfigSelectItems`]
296#[proc_macro_attribute]
297pub fn filter_config_items(
298 _attr: proc_macro::TokenStream,
299 item: proc_macro::TokenStream,
300) -> proc_macro::TokenStream {
301 filter_config_items::filter_config_items(item.into())
302 .unwrap_or_else(|e| e)
303 .into()
304}
305
306/// `FilterConfigSelectItems` を自動で実装するためのマクロ。
307///
308/// # Attributes
309///
310/// - enumのフィールドはすべて最大1つのitem属性を持つことができます。
311/// - enumは値を持つことができません(Unit-only Enumである必要があります)。
312///
313/// ## `item`
314///
315/// ```rust
316/// # #[derive(aviutl2::filter::FilterConfigSelectItems)]
317/// # enum MySelectItem {
318/// #[item(name = "hoge")]
319/// Hoge,
320/// #[item(name = "fuga")]
321/// Fuga = 4,
322/// Piyo,
323/// # }
324/// ```
325///
326/// - `name`: AviUtl2上で表示されるテキスト。省略された場合はVariantの名前になります。
327///
328/// # Example
329///
330/// ```rust
331/// #[derive(Debug, aviutl2::filter::FilterConfigSelectItems)]
332/// enum MySelectItem {
333/// #[item(name = "Hoge")]
334/// Hoge,
335/// #[item(name = "Fuga")]
336/// Fuga,
337/// }
338/// ```
339#[proc_macro_derive(FilterConfigSelectItems, attributes(item))]
340pub fn filter_config_select_items(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
341 filter_config_select_items::filter_config_select_items(item.into())
342 .unwrap_or_else(|e| e)
343 .into()
344}
345
346/// `FromScriptModuleParam` を自動で実装するためのマクロ。
347///
348/// このマクロを利用するには、構造体の各フィールドが `aviutl2::module::FromScriptModuleParamValue`
349/// トレイトを実装している必要があります。
350///
351/// # Example
352///
353/// ```rust
354/// #[derive(aviutl2::module::FromScriptModuleParam)]
355/// struct MyStruct {
356/// foo: i32,
357/// bar: String,
358/// }
359/// ```
360#[proc_macro_derive(FromScriptModuleParam)]
361pub fn from_script_module_param(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
362 from_script_module_param::from_script_module_param(item.into())
363 .unwrap_or_else(|e| e)
364 .into()
365}
366
367/// `IntoScriptModuleReturnValue` を自動で実装するためのマクロ。
368///
369/// このマクロを利用するには、
370///
371/// - 構造体のすべてのフィールドが同じ`T`または`Option<T>`型、かつ
372/// - `std::collections::HashMap<String, T>`が`IntoScriptModuleReturnValue`を実装している
373///
374/// 必要があります。
375///
376/// # Example
377///
378/// ```rust
379/// #[derive(aviutl2::module::IntoScriptModuleReturnValue)]
380/// struct MyStruct {
381/// foo: Option<String>,
382/// bar: String,
383/// }
384/// ```
385///
386/// 以下は動きません:
387///
388/// ```rust,compile_fail
389/// #[derive(aviutl2::module::IntoScriptModuleReturnValue)]
390/// struct MyBadStruct {
391/// foo: String,
392/// bar: i32, // 異なる型
393/// }
394/// ```
395///
396/// # See Also
397///
398/// - [`FromScriptModuleParam`]
399#[proc_macro_derive(IntoScriptModuleReturnValue)]
400pub fn into_script_module_return_value(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
401 into_script_module_return_value::into_script_module_return_value(item.into())
402 .unwrap_or_else(|e| e)
403 .into()
404}
405
406/// `ScriptModuleFunctions` を実装するためのマクロ。
407///
408/// このマクロは`impl`ブロックに対して適用されます。
409/// `impl`ブロック内で定義された関数がスクリプトモジュールの関数として登録されます。
410///
411/// # Attributes
412///
413/// ### `direct`
414///
415/// 関数の引数を手動で処理する関数として登録します。
416/// 関数のシグネチャは以下のようになります。
417///
418/// ```rust
419/// # use aviutl2::module::IntoScriptModuleReturnValue;
420/// # #[aviutl2::plugin(ScriptModule)]
421/// # struct MyModule {
422/// # counter: std::sync::atomic::AtomicI32,
423/// # }
424/// # impl aviutl2::module::ScriptModule for MyModule {
425/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
426/// # unimplemented!()
427/// # }
428/// # fn plugin_info(&self) -> aviutl2::module::ScriptModuleTable {
429/// # unimplemented!()
430/// # }
431/// # }
432/// # #[aviutl2::module::functions]
433/// # impl MyModule {
434/// # #[direct]
435/// fn function_name(params: &mut aviutl2::module::ScriptModuleCallHandle) -> ()
436/// # {}
437/// # }
438/// ```
439///
440/// # Example
441///
442/// ```rust
443/// use aviutl2::module::IntoScriptModuleReturnValue;
444///
445/// #[aviutl2::plugin(ScriptModule)]
446/// struct MyModule {
447/// counter: std::sync::atomic::AtomicI32,
448/// }
449/// # impl aviutl2::module::ScriptModule for MyModule {
450/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
451/// # unimplemented!()
452/// # }
453/// # fn plugin_info(&self) -> aviutl2::module::ScriptModuleTable {
454/// # unimplemented!()
455/// # }
456/// # }
457/// #[aviutl2::module::functions]
458/// impl MyModule {
459/// fn sum(a: i32, b: i32) -> i32 {
460/// a + b
461/// }
462///
463/// fn return_overload(a: i32) -> impl aviutl2::module::IntoScriptModuleReturnValue {
464/// if a % 2 == 0 {
465/// "Even".into_return_values().map_err(anyhow::Error::from)
466/// } else {
467/// ("Odd", a).into_return_values()
468/// }
469/// }
470///
471/// fn increment_counter(&self) -> i32 {
472/// self.counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + 1
473/// }
474///
475/// #[direct]
476/// fn direct_sum(params: &mut aviutl2::module::ScriptModuleCallHandle) {
477/// let a: i32 = params.get_param(0).unwrap_or(0);
478/// let b: i32 = params.get_param(1).unwrap_or(0);
479/// params.push_result(a + b);
480/// }
481///
482/// #[direct]
483/// fn direct_sum_with_counter(
484/// &self,
485/// params: &mut aviutl2::module::ScriptModuleCallHandle,
486/// ) {
487/// let a: i32 = params.get_param(0).unwrap_or(0);
488/// let b: i32 = params.get_param(1).unwrap_or(0);
489/// let count = self.increment_counter();
490/// params.push_result((a + b, count));
491/// }
492/// }
493/// # fn main() {}
494/// ```
495#[proc_macro_attribute]
496pub fn module_functions(
497 _attr: proc_macro::TokenStream,
498 item: proc_macro::TokenStream,
499) -> proc_macro::TokenStream {
500 module_functions::module_functions(item.into())
501 .unwrap_or_else(|e| e)
502 .into()
503}
504
505/// プラグインを定義するためのマクロ。
506///
507/// # Attributes
508///
509/// - 引数には`InputPlugin`、`OutputPlugin`、`FilterPlugin`、`ScriptModule`、`GenericPlugin`のいずれかを指定します。
510///
511/// # Example
512///
513/// ```rust
514/// #[aviutl2::plugin(OutputPlugin)]
515/// struct MyOutputPlugin;
516///
517/// impl aviutl2::output::OutputPlugin for MyOutputPlugin {
518/// // ...
519/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
520/// # todo!()
521/// # }
522/// #
523/// # fn plugin_info(&self) -> aviutl2::output::OutputPluginTable {
524/// # todo!()
525/// # }
526/// #
527/// # fn output(&self, info: aviutl2::output::OutputInfo) -> aviutl2::AnyResult<()> {
528/// # todo!()
529/// # }
530/// }
531///
532/// aviutl2::register_output_plugin!(MyOutputPlugin);
533///
534/// # fn main() {}
535/// ```
536#[proc_macro_attribute]
537pub fn plugin(
538 attr: proc_macro::TokenStream,
539 item: proc_macro::TokenStream,
540) -> proc_macro::TokenStream {
541 plugin::plugin(attr.into(), item.into())
542 .unwrap_or_else(|e| e)
543 .into()
544}
545
546/// 汎用プラグインのメニュー登録実装を生成するマクロ。
547///
548/// このマクロは`impl`ブロックに対して適用されます。
549/// `impl`ブロック内で定義された関数が汎用プラグインのメニューとして登録されます。
550///
551/// # Attributes
552///
553/// ### `import`
554///
555/// インポートメニューとして登録します。
556///
557/// - `name`: メニューに表示される名前を指定します。
558/// - `error`: エラー発生時のハンドリング方法を指定します。`"alert"`、`"log"`、`"ignore"`のいずれかを指定します。
559/// - `"alert"`: エラー発生時にアラートダイアログを表示します。(デフォルト)
560/// - `"log"`: エラー発生時にログにエラーメッセージを出力します。
561/// - `"ignore"`: エラー発生時に何も行いません。
562///
563/// 関数は以下のシグネチャのうちいずれかを持つ必要があります:
564/// ```rust
565/// # #[aviutl2::plugin(GenericPlugin)]
566/// # struct MyGenericPlugin;
567/// # impl aviutl2::generic::GenericPlugin for MyGenericPlugin {
568/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
569/// # unimplemented!()
570/// # }
571/// # fn register(&mut self, _handle: &mut aviutl2::generic::HostAppHandle<'_>) {
572/// # unimplemented!()
573/// # }
574/// # }
575/// # type E = aviutl2::anyhow::Error;
576/// # #[aviutl2::generic::menus]
577/// # impl MyGenericPlugin {
578/// # #[import(name = "")]
579/// fn func1(edit_handle: &mut aviutl2::generic::EditSection) -> ()
580/// # {}
581/// # #[export(name = "")]
582/// fn func2(edit_handle: &mut aviutl2::generic::EditSection) -> Result<(), E>
583/// # { unimplemented!() }
584/// # #[layer(name = "")]
585/// fn func3(&self, edit_handle: &mut aviutl2::generic::EditSection) -> ()
586/// # {}
587/// # #[object(name = "")]
588/// fn func4(&self, edit_handle: &mut aviutl2::generic::EditSection) -> Result<(), E>
589/// # { unimplemented!() }
590/// # #[edit(name = "")]
591/// fn func5(&mut self, edit_handle: &mut aviutl2::generic::EditSection) -> ()
592/// # {}
593/// # #[edit(name = "")]
594/// fn func6(&mut self, edit_handle: &mut aviutl2::generic::EditSection) -> Result<(), E>
595/// # { unimplemented!() }
596/// # }
597/// # fn test<E>() -> Result<(), E>
598/// where
599/// Box<dyn std::error::Error>: From<E>,
600/// # { unimplemented!() }
601/// ```
602///
603/// ### `export`
604///
605/// エクスポートメニューとして登録します。
606/// パラメーター、シグネチャは`import`属性と同様です。
607///
608/// ### `layer`
609///
610/// レイヤーメニューとして登録します。
611/// パラメーター、シグネチャは`import`属性と同様です。
612///
613/// ### `object`
614///
615/// オブジェクトメニューとして登録します。
616/// パラメーター、シグネチャは`import`属性と同様です。
617///
618/// ### `edit`
619///
620/// 編集メニューとして登録します。
621/// パラメーター、シグネチャは`import`属性と同様です。
622///
623/// ### `config`
624///
625/// 設定メニューとして登録します。
626/// 設定メニューの登録後にウィンドウクライアントを登録するとシステムメニューに「設定」が追加されます。
627/// 関数は以下のシグネチャのうちいずれかを持つ必要があります:
628///
629/// ```rust
630/// # #[aviutl2::plugin(GenericPlugin)]
631/// # struct MyGenericPlugin;
632/// # impl aviutl2::generic::GenericPlugin for MyGenericPlugin {
633/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
634/// # unimplemented!()
635/// # }
636/// # fn register(&mut self, _handle: &mut aviutl2::generic::HostAppHandle<'_>) {
637/// # unimplemented!()
638/// # }
639/// # }
640/// # type E = aviutl2::anyhow::Error;
641/// # #[aviutl2::generic::menus]
642/// # impl MyGenericPlugin {
643/// # #[config(name = "")]
644/// fn func1(hwnd: aviutl2::Win32WindowHandle) -> ()
645/// # {}
646/// # #[config(name = "")]
647/// fn func2(hwnd: aviutl2::Win32WindowHandle) -> Result<(), E>
648/// # { unimplemented!() }
649/// # #[config(name = "")]
650/// fn func3(&self, hwnd: aviutl2::Win32WindowHandle) -> ()
651/// # {}
652/// # #[config(name = "")]
653/// fn func4(&self, hwnd: aviutl2::Win32WindowHandle) -> Result<(), E>
654/// # { unimplemented!() }
655/// # #[config(name = "")]
656/// fn func5(&mut self, hwnd: aviutl2::Win32WindowHandle) -> ()
657/// # {}
658/// # #[config(name = "")]
659/// fn func6(&mut self, hwnd: aviutl2::Win32WindowHandle) -> Result<(), E>
660/// # { unimplemented!() }
661/// # }
662/// # fn test<E>() -> Result<(), E>
663/// where
664/// Box<dyn std::error::Error>: From<E>,
665/// # { unimplemented!() }
666/// ```
667///
668/// # Example
669///
670/// ```rust
671/// #[aviutl2::plugin(GenericPlugin)]
672/// struct MyGenericPlugin;
673/// # impl aviutl2::generic::GenericPlugin for MyGenericPlugin {
674/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
675/// # unimplemented!()
676/// # }
677/// # fn register(&mut self, _handle: &mut aviutl2::generic::HostAppHandle<'_>) {
678/// # unimplemented!()
679/// # }
680/// # }
681///
682/// #[aviutl2::generic::menus]
683/// impl MyGenericPlugin {
684/// #[import(name = ".txtファイルをインポート")]
685/// fn import_text(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
686/// // ...
687/// # Ok(())
688/// }
689///
690/// #[export(name = ".txtファイルをエクスポート")]
691/// fn export_text(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
692/// // ...
693/// # Ok(())
694/// }
695///
696/// #[layer(name = "レイヤーを複製")]
697/// fn duplicate_layer(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
698/// // ...
699/// # Ok(())
700/// }
701///
702/// #[object(name = "オブジェクトを削除")]
703/// fn delete_object(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
704/// // ...
705/// # Ok(())
706/// }
707///
708/// #[edit(name = "BPMグリッドを消去")]
709/// fn register_edit_menu(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
710/// // ...
711/// # Ok(())
712/// }
713///
714/// #[config(name = "オブジェクトを削除")]
715/// fn show_config(hwnd: aviutl2::Win32WindowHandle) -> aviutl2::AnyResult<()> {
716/// // ...
717/// # Ok(())
718/// }
719/// }
720#[proc_macro_attribute]
721pub fn generic_menus(
722 _attr: proc_macro::TokenStream,
723 item: proc_macro::TokenStream,
724) -> proc_macro::TokenStream {
725 generic_menus::generic_menus(item.into())
726 .unwrap_or_else(|e| e)
727 .into()
728}