Skip to content

Commit ef7157c

Browse files
authored
Merge pull request #2485 from fesily/support-multi-plugins
support multi plugins
2 parents 4432dfe + cfeac1c commit ef7157c

File tree

2 files changed

+83
-57
lines changed

2 files changed

+83
-57
lines changed

script/config/template.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ local template = {
223223
'||', '&&', '!', '!=',
224224
'continue',
225225
}),
226-
['Lua.runtime.plugin'] = Type.String,
227-
['Lua.runtime.pluginArgs'] = Type.Array(Type.String),
226+
['Lua.runtime.plugin'] = Type.Or(Type.String, Type.Array(Type.String)) ,
227+
['Lua.runtime.pluginArgs'] = Type.Or(Type.Array(Type.String), Type.Hash(Type.String, Type.String)),
228228
['Lua.runtime.fileEncoding'] = Type.String >> 'utf8' << {
229229
'utf8',
230230
'ansi',

script/plugin.lua

Lines changed: 81 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,37 @@ function m.showError(scp, err)
1818
client.showMessage('Error', lang.script('PLUGIN_RUNTIME_ERROR', scp:get('pluginPath'), err))
1919
end
2020

21+
---@alias plugin.event 'OnSetText' | 'OnTransformAst'
22+
23+
---@param event plugin.event
2124
function m.dispatch(event, uri, ...)
2225
local scp = scope.getScope(uri)
23-
local interface = scp:get('pluginInterface')
24-
if not interface then
25-
return false
26-
end
27-
local method = interface[event]
28-
if type(method) ~= 'function' then
26+
local interfaces = scp:get('pluginInterfaces')
27+
if not interfaces then
2928
return false
3029
end
31-
local clock = os.clock()
32-
tracy.ZoneBeginN('plugin dispatch:' .. event)
33-
local suc, res1, res2 = xpcall(method, log.error, uri, ...)
34-
tracy.ZoneEnd()
35-
local passed = os.clock() - clock
36-
if passed > 0.1 then
37-
log.warn(('Call plugin event [%s] takes [%.3f] sec'):format(event, passed))
38-
end
39-
if suc then
40-
return true, res1, res2
41-
else
42-
m.showError(scp, res1)
30+
local failed = 0
31+
local res1, res2
32+
for i, interface in ipairs(interfaces) do
33+
local method = interface[event]
34+
if type(method) ~= 'function' then
35+
return false
36+
end
37+
local clock = os.clock()
38+
tracy.ZoneBeginN('plugin dispatch:' .. event)
39+
local suc
40+
suc, res1, res2 = xpcall(method, log.error, uri, ...)
41+
tracy.ZoneEnd()
42+
local passed = os.clock() - clock
43+
if passed > 0.1 then
44+
log.warn(('Call plugin event [%s] takes [%.3f] sec'):format(event, passed))
45+
end
46+
if not suc then
47+
m.showError(scp, res1)
48+
failed = failed + 1
49+
end
4350
end
44-
return false, res1
51+
return failed == 0, res1, res2
4552
end
4653

4754
---@async
@@ -75,53 +82,72 @@ end
7582
local function initPlugin(uri)
7683
await.call(function () ---@async
7784
local scp = scope.getScope(uri)
78-
local interface = {}
79-
scp:set('pluginInterface', interface)
85+
local interfaces = {}
86+
scp:set('pluginInterfaces', interfaces)
8087

8188
if not scp.uri then
8289
return
8390
end
84-
85-
local pluginPath = ws.getAbsolutePath(scp.uri, config.get(scp.uri, 'Lua.runtime.plugin'))
86-
log.info('plugin path:', pluginPath)
87-
if not pluginPath then
91+
---@type string[]|string
92+
local pluginConfigPaths = config.get(scp.uri, 'Lua.runtime.plugin')
93+
if not pluginConfigPaths then
8894
return
8995
end
90-
91-
--Adding the plugins path to package.path allows for requires in files
92-
--to find files relative to itself.
93-
local oldPath = package.path
94-
local path = fs.path(pluginPath):parent_path() / '?.lua'
95-
if not package.path:find(path:string(), 1, true) then
96-
package.path = package.path .. ';' .. path:string()
96+
local args = config.get(scp.uri, 'Lua.runtime.pluginArgs')
97+
if type(pluginConfigPaths) == 'string' then
98+
pluginConfigPaths = { pluginConfigPaths }
9799
end
100+
for i, pluginConfigPath in ipairs(pluginConfigPaths) do
101+
local myArgs = args
102+
if args then
103+
for k, v in pairs(args) do
104+
if pluginConfigPath:find(k, 1, true) then
105+
myArgs = v
106+
break
107+
end
108+
end
109+
end
98110

99-
local pluginLua = util.loadFile(pluginPath)
100-
if not pluginLua then
101-
log.warn('plugin not found:', pluginPath)
102-
package.path = oldPath
103-
return
104-
end
111+
local pluginPath = ws.getAbsolutePath(scp.uri, pluginConfigPath)
112+
log.info('plugin path:', pluginPath)
113+
if not pluginPath then
114+
return
115+
end
105116

106-
scp:set('pluginPath', pluginPath)
117+
--Adding the plugins path to package.path allows for requires in files
118+
--to find files relative to itself.
119+
local oldPath = package.path
120+
local path = fs.path(pluginPath):parent_path() / '?.lua'
121+
if not package.path:find(path:string(), 1, true) then
122+
package.path = package.path .. ';' .. path:string()
123+
end
107124

108-
local env = setmetatable(interface, { __index = _ENV })
109-
local f, err = load(pluginLua, '@'..pluginPath, "t", env)
110-
if not f then
111-
log.error(err)
112-
m.showError(scp, err)
113-
return
114-
end
115-
if not client.isVSCode() and not checkTrustLoad(scp) then
116-
return
117-
end
118-
local pluginArgs = config.get(scp.uri, 'Lua.runtime.pluginArgs')
119-
local suc, err = xpcall(f, log.error, f, uri, pluginArgs)
120-
if not suc then
121-
m.showError(scp, err)
122-
return
123-
end
125+
local pluginLua = util.loadFile(pluginPath)
126+
if not pluginLua then
127+
log.warn('plugin not found:', pluginPath)
128+
package.path = oldPath
129+
return
130+
end
124131

132+
scp:set('pluginPath', pluginPath)
133+
134+
local interface = setmetatable({}, { __index = _ENV })
135+
local f, err = load(pluginLua, '@' .. pluginPath, "t", interface)
136+
if not f then
137+
log.error(err)
138+
m.showError(scp, err)
139+
return
140+
end
141+
if not client.isVSCode() and not checkTrustLoad(scp) then
142+
return
143+
end
144+
local suc, err = xpcall(f, log.error, f, uri, myArgs)
145+
if not suc then
146+
m.showError(scp, err)
147+
return
148+
end
149+
interfaces[#interfaces+1] = interface
150+
end
125151
ws.resetFiles(scp)
126152
end)
127153
end

0 commit comments

Comments
 (0)