Skip to content

Commit 3e608ad

Browse files
authored
Merge pull request #2131 from fesily/ffi-plugin-lazyload
command:add reloadFFIMeta
2 parents 556be25 + acf091c commit 3e608ad

File tree

6 files changed

+165
-92
lines changed

6 files changed

+165
-92
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
local config = require 'config'
2+
local ws = require 'workspace'
3+
local fs = require 'bee.filesystem'
4+
local scope = require 'workspace.scope'
5+
local SDBMHash = require 'SDBMHash'
6+
local searchCode = require 'plugins.ffi.searchCode'
7+
local cdefRerence = require 'plugins.ffi.cdefRerence'
8+
local ffi = require 'plugins.ffi'
9+
10+
local function createDir(uri)
11+
local dir = scope.getScope(uri).uri or 'default'
12+
local fileDir = fs.path(METAPATH) / ('%08x'):format(SDBMHash():hash(dir))
13+
if fs.exists(fileDir) then
14+
return fileDir, true
15+
end
16+
fs.create_directories(fileDir)
17+
return fileDir
18+
end
19+
20+
---@async
21+
return function (uri)
22+
if config.get(uri, 'Lua.runtime.version') ~= 'LuaJIT' then
23+
return
24+
end
25+
26+
ws.awaitReady(uri)
27+
28+
local fileDir, exists = createDir(uri)
29+
30+
local refs = cdefRerence()
31+
if not refs or #refs == 0 then
32+
return
33+
end
34+
35+
for i, v in ipairs(refs) do
36+
local target_uri = v.uri
37+
local codes = searchCode(refs, target_uri)
38+
if not codes then
39+
return
40+
end
41+
42+
ffi.build_single(codes, fileDir, target_uri)
43+
end
44+
45+
if not exists then
46+
local client = require 'client'
47+
client.setConfig {
48+
{
49+
key = 'Lua.workspace.library',
50+
action = 'add',
51+
value = tostring(fileDir),
52+
uri = uri,
53+
}
54+
}
55+
end
56+
end

script/plugins/ffi/cdefRerence.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ end
2020
return function ()
2121
local ffi_state
2222
for uri in files.eachFile() do
23-
if find(uri, "/ffi.lua", 0, true) then
23+
if find(uri, "ffi.lua", 0, true) and find(uri, "lua-language-server", 0, true) then
2424
ffi_state = files.getState(uri)
2525
break
2626
end

script/plugins/ffi/init.lua

Lines changed: 63 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
local searchCode = require 'plugins.ffi.searchCode'
2-
local cdefRerence = require 'plugins.ffi.cdefRerence'
3-
local cdriver = require 'plugins.ffi.c-parser.cdriver'
4-
local util = require 'plugins.ffi.c-parser.util'
5-
local utility = require 'utility'
6-
local SDBMHash = require 'SDBMHash'
7-
local ws = require 'workspace'
8-
local files = require 'files'
9-
local await = require 'await'
10-
local config = require 'config'
11-
local fs = require 'bee.filesystem'
12-
local scope = require 'workspace.scope'
1+
local searchCode = require 'plugins.ffi.searchCode'
2+
local cdefRerence = require 'plugins.ffi.cdefRerence'
3+
local cdriver = require 'plugins.ffi.c-parser.cdriver'
4+
local util = require 'plugins.ffi.c-parser.util'
5+
local utility = require 'utility'
6+
local SDBMHash = require 'SDBMHash'
7+
local config = require 'config'
8+
local fs = require 'bee.filesystem'
9+
local scope = require 'workspace.scope'
1310

14-
local namespace <const> = 'ffi.namespace*.'
11+
local namespace <const> = 'ffi.namespace*.'
1512

1613
--TODO:supprot 32bit ffi, need config
17-
local knownTypes = {
14+
local knownTypes = {
1815
["bool"] = 'boolean',
1916
["char"] = 'integer',
2017
["short"] = 'integer',
@@ -63,10 +60,33 @@ local knownTypes = {
6360
["signedlong"] = 'integer',
6461
}
6562

66-
local constName <const> = 'm'
63+
local blackKeyWord <const> = {
64+
['and'] = "_and",
65+
['do'] = "_do",
66+
['elseif'] = "_elseif",
67+
['end'] = "_end",
68+
['false'] = "_false",
69+
['function'] = "_function",
70+
['in'] = "_in",
71+
['local'] = "_local",
72+
['nil'] = "_nil",
73+
['not'] = "_not",
74+
['or'] = "_or",
75+
['repeat'] = "_repeat",
76+
['then'] = "_then",
77+
['true'] = "_true",
78+
}
79+
80+
local invaildKeyWord <const> = {
81+
const = true,
82+
restrict = true,
83+
volatile = true,
84+
}
85+
86+
local constName <const> = 'm'
6787

6888
---@class ffi.builder
69-
local builder = { switch_ast = utility.switch() }
89+
local builder = { switch_ast = utility.switch() }
7090

7191
function builder:getTypeAst(name)
7292
for i, asts in ipairs(self.globalAsts) do
@@ -98,14 +118,22 @@ function builder:getType(name)
98118
if type(name) == 'table' then
99119
local t = ""
100120
local isStruct
121+
if name.type then
122+
t = t .. name.type .. "@"
123+
name = name.name
124+
end
101125
for _, n in ipairs(name) do
102126
if type(n) == 'table' then
103127
n = n.full_name
104128
end
129+
if invaildKeyWord[n] then
130+
goto continue
131+
end
105132
if not isStruct then
106133
isStruct = self:needDeref(self:getTypeAst(n))
107134
end
108135
t = t .. n
136+
::continue::
109137
end
110138
-- deref 一级指针
111139
if isStruct and t:sub(#t) == '*' then
@@ -145,11 +173,15 @@ local function getArrayType(arr)
145173
return res
146174
end
147175

176+
local function getValidName(name)
177+
return blackKeyWord[name] or name
178+
end
179+
148180
function builder:buildStructOrUnion(lines, tt, name)
149181
lines[#lines+1] = '---@class ' .. self:getType(name)
150182
for _, field in ipairs(tt.fields or {}) do
151183
if field.name and field.type then
152-
lines[#lines+1] = ('---@field %s %s%s'):format(field.name, self:getType(field.type),
184+
lines[#lines+1] = ('---@field %s %s%s'):format(getValidName(field.name), self:getType(field.type),
153185
getArrayType(field.isarray))
154186
end
155187
end
@@ -158,8 +190,9 @@ end
158190
function builder:buildFunction(lines, tt, name)
159191
local param_names = {}
160192
for i, param in ipairs(tt.params or {}) do
161-
lines[#lines+1] = ('---@param %s %s%s'):format(param.name, self:getType(param.type), getArrayType(param.idxs))
162-
param_names[#param_names+1] = param.name
193+
local param_name = getValidName(param.name)
194+
lines[#lines+1] = ('---@param %s %s%s'):format(param_name, self:getType(param.type), getArrayType(param.idxs))
195+
param_names[#param_names+1] = param_name
163196
end
164197
if tt.vararg then
165198
param_names[#param_names+1] = '...'
@@ -178,7 +211,7 @@ function builder:buildTypedef(lines, tt, name)
178211
-- 这个时候没有主类型,只有一个别名,直接创建一个别名结构体
179212
self.switch_ast(def.type, self, lines, def, name)
180213
else
181-
lines[#lines+1] = ('---@alias %s %s'):format(name, self:getType(def))
214+
lines[#lines+1] = ('---@alias %s %s'):format(self:getType(name), self:getType(def))
182215
end
183216
end
184217

@@ -322,72 +355,18 @@ function m.compileCodes(codes)
322355
return lines
323356
end
324357

325-
local function createDir(uri)
326-
local dir = scope.getScope(uri).uri or 'default'
327-
local fileDir = fs.path(METAPATH) / ('%08x'):format(SDBMHash():hash(dir))
328-
fs.create_directories(fileDir)
329-
return fileDir
330-
end
331-
332-
local builder
333-
function m.initBuilder(fileDir)
334-
fileDir = fileDir or createDir()
335-
---@async
336-
return function (uri)
337-
local refs = cdefRerence()
338-
if not refs or #refs == 0 then
339-
return
340-
end
341-
342-
local codes = searchCode(refs, uri)
343-
if not codes then
344-
return
345-
end
346-
347-
local texts = m.compileCodes(codes)
348-
if not texts then
349-
return
350-
end
351-
local hash = ('%08x'):format(SDBMHash():hash(uri))
352-
local encoding = config.get(nil, 'Lua.runtime.fileEncoding')
353-
local filePath = fileDir / table.concat({ hash, encoding }, '_')
354-
355-
utility.saveFile(tostring(filePath) .. '.d.lua', table.concat(texts, '\n'))
358+
function m.build_single(codes, fileDir, uri)
359+
local texts = m.compileCodes(codes)
360+
if not texts then
361+
return
356362
end
357-
end
358363

359-
files.watch(function (ev, uri)
360-
if ev == 'compiler' or ev == 'update' then
361-
if builder then
362-
await.call(function () ---@async
363-
builder(uri)
364-
end)
365-
end
366-
end
367-
end)
364+
local hash = ('%08x'):format(SDBMHash():hash(uri))
365+
local encoding = config.get(nil, 'Lua.runtime.fileEncoding')
366+
local filePath = fileDir / table.concat({ hash, encoding }, '_')
368367

369-
ws.watch(function (ev, uri)
370-
-- TODO
371-
do return end
372-
if ev == 'startReload' then
373-
if config.get(uri, 'Lua.runtime.version') ~= 'LuaJIT' then
374-
return
375-
end
376-
await.call(function () ---@async
377-
ws.awaitReady(uri)
378-
local fileDir = createDir(uri)
379-
builder = m.initBuilder(fileDir)
380-
local client = require 'client'
381-
client.setConfig {
382-
{
383-
key = 'Lua.workspace.library',
384-
action = 'add',
385-
value = tostring(fileDir),
386-
uri = uri,
387-
}
388-
}
389-
end)
390-
end
391-
end)
368+
utility.saveFile(tostring(filePath) .. '.d.lua', table.concat(texts, '\n'))
369+
return true
370+
end
392371

393372
return m

script/provider/provider.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,11 @@ m.register 'workspace/executeCommand' {
982982
elseif command == 'lua.exportDocument' then
983983
local core = require 'core.command.exportDocument'
984984
core(params.arguments)
985+
elseif command == 'lua.reloadFFIMeta' then
986+
local core = require 'core.command.reloadFFIMeta'
987+
for _, scp in ipairs(workspace.folders) do
988+
core(scp.uri)
989+
end
985990
end
986991
end
987992
}

test/plugins/ffi/builder.lua

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,44 @@ function TEST(wanted)
3939
end
4040
end
4141

42+
TEST [[
43+
---@alias ffi.namespace*.EVP_MD ffi.namespace*.struct@env_md_st
44+
45+
---@return ffi.namespace*.EVP_MD
46+
function m.EVP_md5() end
47+
]] [[
48+
typedef struct env_md_st EVP_MD;
49+
const EVP_MD *EVP_md5(void);
50+
]]
51+
52+
TEST [[
53+
---@class ffi.namespace*.struct@a
54+
---@field _in integer
55+
]] [[
56+
struct a {
57+
int in;
58+
};
59+
]]
60+
61+
TEST [[
62+
---@param _in integer
63+
function m.test(_in) end
64+
]] [[
65+
void test(int in);
66+
]]
67+
68+
TEST [[
69+
---@alias ffi.namespace*.ENGINE ffi.namespace*.struct@engine_st
70+
---@alias ffi.namespace*.ENGINE1 ffi.namespace*.enum@engine_st1
71+
]] [[
72+
typedef struct engine_st ENGINE;
73+
typedef enum engine_st1 ENGINE1;
74+
]]
75+
4276
TEST [[
4377
---@param a integer[][]
4478
function m.test(a) end
45-
]][[
79+
]] [[
4680
void test(int a[][]);
4781
]]
4882

@@ -76,7 +110,7 @@ TEST [[
76110
m.A = 1
77111
m.C = 5
78112
---@alias ffi.namespace*.enum@a 1 | 2 | 'B' | 'A' | 5 | 'C'
79-
]][[
113+
]] [[
80114
enum a {
81115
A = 1,
82116
B = 2,
@@ -165,7 +199,7 @@ TEST [[
165199
]]
166200

167201
TEST [[
168-
---@alias H ffi.namespace*.void
202+
---@alias ffi.namespace*.H ffi.namespace*.void
169203
170204
function m.test() end
171205
]] [[

test/plugins/ffi/test.lua

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,15 @@ local template = require 'config.template'
88

99
template['Lua.runtime.version'].default = 'LuaJIT'
1010

11-
1211
---@async
1312
local function TestBuilder()
14-
local builder = require 'plugins.ffi'.initBuilder()
13+
local builder = require 'core.command.reloadFFIMeta'
1514
files.setText(TESTURI, [[
1615
local ffi = require 'ffi'
1716
ffi.cdef 'void test();'
1817
]])
19-
20-
builder(TESTURI)
18+
local uri = ws.getFirstScope().uri
19+
builder(uri)
2120
end
2221

2322
---@async

0 commit comments

Comments
 (0)