11use std:: { borrow:: Cow , ops:: Deref } ;
22
3- use anyhow:: { Context , Result , bail} ;
3+ use anyhow:: { Context , Result , bail, ensure } ;
44use hashbrown:: HashMap ;
55use mlua:: { ChunkMode , ExternalError , Lua , Table } ;
66use parking_lot:: RwLock ;
77use yazi_boot:: BOOT ;
88use yazi_fs:: provider:: local:: Local ;
99use yazi_macro:: plugin_preset as preset;
10- use yazi_shared:: { LOG_LEVEL , RoCell } ;
10+ use yazi_shared:: { BytesExt , LOG_LEVEL , RoCell } ;
1111
1212use super :: Chunk ;
1313
@@ -20,7 +20,6 @@ pub struct Loader {
2020impl Deref for Loader {
2121 type Target = RwLock < HashMap < String , Chunk > > ;
2222
23- #[ inline]
2423 fn deref ( & self ) -> & Self :: Target { & self . cache }
2524}
2625
@@ -52,26 +51,29 @@ impl Default for Loader {
5251}
5352
5453impl Loader {
55- pub async fn ensure < F , T > ( & self , name : & str , f : F ) -> Result < T >
54+ pub async fn ensure < F , T > ( & self , id : & str , f : F ) -> Result < T >
5655 where
5756 F : FnOnce ( & Chunk ) -> T ,
5857 {
59- if let Some ( c) = self . cache . read ( ) . get ( name) {
60- return Self :: compatible_or_error ( name, c) . map ( |_| f ( c) ) ;
58+ let ( id, plugin, entry) = Self :: normalize_id ( id) ?;
59+ if let Some ( c) = self . cache . read ( ) . get ( id) {
60+ return Self :: compatible_or_error ( id, c) . map ( |_| f ( c) ) ;
6161 }
6262
63- let p = BOOT . plugin_dir . join ( format ! ( "{name }.yazi/main .lua" ) ) ;
63+ let p = BOOT . plugin_dir . join ( format ! ( "{plugin }.yazi/{entry} .lua" ) ) ;
6464 let chunk =
6565 Local :: read ( & p) . await . with_context ( || format ! ( "Failed to load plugin from {p:?}" ) ) ?. into ( ) ;
6666
67- let result = Self :: compatible_or_error ( name , & chunk) ;
67+ let result = Self :: compatible_or_error ( id , & chunk) ;
6868 let inspect = f ( & chunk) ;
6969
70- self . cache . write ( ) . insert ( name . to_owned ( ) , chunk) ;
70+ self . cache . write ( ) . insert ( id . to_owned ( ) , chunk) ;
7171 result. map ( |_| inspect)
7272 }
7373
7474 pub fn load ( & self , lua : & Lua , id : & str ) -> mlua:: Result < Table > {
75+ let ( id, ..) = Self :: normalize_id ( id) ?;
76+
7577 let loaded: Table = lua. globals ( ) . raw_get :: < Table > ( "package" ) ?. raw_get ( "loaded" ) ?;
7678 if let Ok ( t) = loaded. raw_get ( id) {
7779 return Ok ( t) ;
@@ -85,18 +87,20 @@ impl Loader {
8587 }
8688
8789 pub fn load_once ( & self , lua : & Lua , id : & str ) -> mlua:: Result < Table > {
90+ let ( id, ..) = Self :: normalize_id ( id) ?;
91+
8892 let mut mode = ChunkMode :: Text ;
89- let f = match self . read ( ) . get ( id) {
93+ let f = match self . cache . read ( ) . get ( id) {
9094 Some ( c) => {
9195 mode = c. mode ;
9296 lua. load ( c) . set_name ( id) . into_function ( )
9397 }
94- None => Err ( format ! ( "plugin `{id}` not found" ) . into_lua_err ( ) ) ,
98+ None => Err ( format ! ( "Plugin `{id}` not found" ) . into_lua_err ( ) ) ,
9599 } ?;
96100
97101 if mode != ChunkMode :: Binary {
98102 let b = f. dump ( LOG_LEVEL . get ( ) . is_none ( ) ) ;
99- if let Some ( c) = self . write ( ) . get_mut ( id) {
103+ if let Some ( c) = self . cache . write ( ) . get_mut ( id) {
100104 c. mode = ChunkMode :: Binary ;
101105 c. bytes = Cow :: Owned ( b) ;
102106 }
@@ -106,10 +110,13 @@ impl Loader {
106110 }
107111
108112 pub fn try_load ( & self , lua : & Lua , id : & str ) -> mlua:: Result < Table > {
113+ let ( id, ..) = Self :: normalize_id ( id) ?;
109114 lua. globals ( ) . raw_get :: < Table > ( "package" ) ?. raw_get :: < Table > ( "loaded" ) ?. raw_get ( id)
110115 }
111116
112117 pub fn load_with ( & self , lua : & Lua , id : & str , chunk : & Chunk ) -> mlua:: Result < Table > {
118+ let ( id, ..) = Self :: normalize_id ( id) ?;
119+
113120 let loaded: Table = lua. globals ( ) . raw_get :: < Table > ( "package" ) ?. raw_get ( "loaded" ) ?;
114121 if let Ok ( t) = loaded. raw_get ( id) {
115122 return Ok ( t) ;
@@ -122,15 +129,24 @@ impl Loader {
122129 Ok ( t)
123130 }
124131
125- pub fn compatible_or_error ( name : & str , chunk : & Chunk ) -> Result < ( ) > {
132+ pub fn compatible_or_error ( id : & str , chunk : & Chunk ) -> Result < ( ) > {
126133 if chunk. compatible ( ) {
127134 return Ok ( ( ) ) ;
128135 }
129136
130137 bail ! (
131- "Plugin `{name }` requires at least Yazi {}, but your current version is Yazi {}." ,
138+ "Plugin `{id }` requires at least Yazi {}, but your current version is Yazi {}." ,
132139 chunk. since,
133140 yazi_boot:: actions:: Actions :: version( )
134141 ) ;
135142 }
143+
144+ pub fn normalize_id ( id : & str ) -> anyhow:: Result < ( & str , & str , & str ) > {
145+ let id = id. trim_end_matches ( ".main" ) ;
146+ let ( plugin, entry) = if let Some ( ( a, b) ) = id. split_once ( "." ) { ( a, b) } else { ( id, "main" ) } ;
147+
148+ ensure ! ( plugin. as_bytes( ) . kebab_cased( ) , "Plugin name `{plugin}` must be in kebab-case" ) ;
149+ ensure ! ( entry. as_bytes( ) . kebab_cased( ) , "Entry name `{entry}` must be in kebab-case" ) ;
150+ Ok ( ( id, plugin, entry) )
151+ }
136152}
0 commit comments