From 86dcb1a7e5eed8cf2e1b7109b4c0debf6967c485 Mon Sep 17 00:00:00 2001 From: fesily Date: Fri, 12 May 2023 15:19:09 +0800 Subject: link server by plugin --- script/plugins/ffi/init.lua | 398 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 script/plugins/ffi/init.lua (limited to 'script/plugins/ffi/init.lua') diff --git a/script/plugins/ffi/init.lua b/script/plugins/ffi/init.lua new file mode 100644 index 00000000..57a64958 --- /dev/null +++ b/script/plugins/ffi/init.lua @@ -0,0 +1,398 @@ +local searchCode = require 'plugins.ffi.searchCode' +local cdefRerence = require 'plugins.ffi.cdefRerence' +local cdriver = require 'plugins.ffi.c-parser.cdriver' +local util = require 'utility' +local SDBMHash = require 'SDBMHash' +local ws = require 'workspace' +local files = require 'files' +local await = require 'await' +local config = require 'config' +local fs = require 'bee.filesystem' +local scope = require 'workspace.scope' + +local namespace = 'ffi.namespace*.' + +local function nkeys(t) + local n = 0 + for key, value in pairs(t) do + n = n + 1 + end + return n +end + +local function isSingleNode(ast) + if type(ast) ~= 'table' then + return false + end + local len = #ast + return len == 1 and len == nkeys(ast) +end + +--TODO:supprot 32bit ffi, need config +local knownTypes = { + ["bool"] = 'boolean', + ["char"] = 'integer', + ["short"] = 'integer', + ["int"] = 'integer', + ["long"] = 'integer', + ["float"] = 'number', + ["double"] = 'number', + ["signed"] = 'integer', + ["__signed"] = 'integer', + ["__signed__"] = 'integer', + ["unsigned"] = 'integer', + ["ptrdiff_t"] = 'integer', + ["size_t"] = 'integer', + ["ssize_t"] = 'integer', + ["wchar_t"] = 'integer', + ["int8_t"] = 'integer', + ["int16_t"] = 'integer', + ["int32_t"] = 'integer', + ["int64_t"] = 'integer', + ["uint8_t"] = 'integer', + ["uint16_t"] = 'integer', + ["uint32_t"] = 'integer', + ["uint64_t"] = 'integer', + ["intptr_t"] = 'integer', + ["uintptr_t"] = 'integer', + ["__int8"] = 'integer', + ["__int16"] = 'integer', + ["__int32"] = 'integer', + ["__int64"] = 'integer', + ["_Bool"] = 'boolean', + ["__ptr32"] = 'integer', + ["__ptr64"] = 'integer', + --[[ + ["_Complex"] = 1, + ["complex"] = 1, + ["__complex"] = 1, + ["__complex__"] = 1, +]] + ["unsignedchar"] = 'integer', + ["unsignedshort"] = 'integer', + ["unsignedint"] = 'integer', + ["unsignedlong"] = 'integer', + ["signedchar"] = 'integer', + ["signedshort"] = 'integer', + ["signedint"] = 'integer', + ["signedlong"] = 'integer', +} + +local constName = 'm' + +---@class ffi.builder +local builder = { switch_ast = util.switch() } + +function builder:getTypeAst(name) + for i, asts in ipairs(self.globalAsts) do + if asts[name] then + return asts[name] + end + end +end + +function builder:needDeref(ast) + if not ast then + return false + end + if ast.type == 'typedef' then + -- maybe no name + ast = ast.def[1] + if type(ast) ~= 'table' then + return self:needDeref(self:getTypeAst(ast)) + end + end + if ast.type == 'struct' or ast.type == 'union' then + return true + else + return false + end +end + +function builder:getType(name) + if type(name) == 'table' then + local t = "" + local isStruct + for _, n in ipairs(name) do + if type(n) == 'table' then + n = n.full_name + end + if not isStruct then + isStruct = self:needDeref(self:getTypeAst(n)) + end + t = t .. n + end + -- deref 一级指针 + if isStruct and t:sub(#t) == '*' then + t = t:sub(1, #t - 1) + end + name = t + end + if knownTypes[name] then + return knownTypes[name] + end + return namespace .. name +end + +function builder:isVoid(ast) + if not ast then + return false + end + if ast.type == 'typedef' then + return self:isVoid(self:getTypeAst(ast.def[1]) or ast.def[1]) + end + + local typename = type(ast.type) == 'table' and ast.type[1] or ast + if typename == 'void' then + return true + end + return self:isVoid(self:getTypeAst(typename)) +end + +function builder:buildStructOrUnion(lines, tt, name) + lines[#lines+1] = '---@class ' .. self:getType(name) + for _, field in ipairs(tt.fields or {}) do + if field.name and field.type then + lines[#lines+1] = ('---@field %s %s'):format(field.name, self:getType(field.type)) + end + end +end + +function builder:buildFunction(lines, tt, name) + local param_names = {} + for i, param in ipairs(tt.params or {}) do + lines[#lines+1] = ('---@param %s %s'):format(param.name, self:getType(param.type)) + param_names[#param_names+1] = param.name + end + if tt.vararg then + param_names[#param_names+1] = '...' + end + if tt.ret then + if not self:isVoid(tt.ret) then + lines[#lines+1] = ('---@return %s'):format(self:getType(tt.ret.type)) + end + end + lines[#lines+1] = ('function m.%s(%s) end'):format(name, table.concat(param_names, ', ')) +end + +function builder:buildTypedef(lines, tt, name) + local def = tt.def[1] + if type(def) == 'table' and not def.name then + -- 这个时候没有主类型,只有一个别名,直接创建一个别名结构体 + self.switch_ast(def.type, self, lines, def, name) + else + lines[#lines+1] = ('---@alias %s %s'):format(name, self:getType(def)) + end +end + +local calculate + +local function binop(enumer, val, fn) + local e1, e2 = calculate(enumer, val[1]), calculate(enumer, val[2]) + if type(e1) == "number" and type(e2) == "number" then + return fn(e1, e2) + else + return { e1, e2, op = val.op } + end +end +do + local ops = { + ['+'] = function (a, b) return a + b end, + ['-'] = function (a, b) return a - b end, + ['*'] = function (a, b) return a * b end, + ['/'] = function (a, b) return a / b end, + ['&'] = function (a, b) return a & b end, + ['|'] = function (a, b) return a | b end, + ['~'] = function (a, b) + if not b then + return ~a + end + return a ~ b + end, + ['<<'] = function (a, b) return a << b end, + ['>>'] = function (a, b) return a >> b end, + } + calculate = function (enumer, val) + if ops[val.op] then + return binop(enumer, val, ops[val.op]) + end + if isSingleNode(val) then + val = val[1] + end + if type(val) == "string" then + if enumer[val] then + return enumer[val] + end + return tonumber(val) + end + return val + end +end + +local function pushEnumValue(enumer, name, v) + if isSingleNode(v) then + v = tonumber(v[1]) + end + enumer[name] = v + enumer[#enumer+1] = v + return v +end + +function builder:buildEnum(lines, tt, name) + local enumer = {} + for i, val in ipairs(tt.values) do + local name = val.name + local v = val.value + if not v then + if i == 1 then + v = 0 + else + v = tt.values[i - 1].realValue + 1 + end + end + if type(v) == 'table' and v.op then + v = calculate(enumer, v) + end + if v then + val.realValue = pushEnumValue(enumer, name, v) + end + end + local alias = {} + for k, v in pairs(enumer) do + alias[#alias+1] = type(k) == 'number' and v or ([['%s']]):format(k) + if type(k) ~= 'number' then + lines[#lines+1] = ('m.%s = %s'):format(k, v) + end + end + if name then + lines[#lines+1] = ('---@alias %s %s'):format(self:getType(name), table.concat(alias, ' | ')) + end +end + +builder.switch_ast + :case 'struct' + :case 'union' + :call(builder.buildStructOrUnion) + :case 'enum' + :call(builder.buildEnum) + : case 'function' + :call(builder.buildFunction) + :case 'typedef' + :call(builder.buildTypedef) + +local function stringStartsWith(self, searchString, position) + if position == nil or position < 0 then + position = 0 + end + return string.sub(self, position + 1, #searchString + position) == searchString +end +local firstline = ('---@meta \n ---@class %s \n local %s = {}'):format(namespace, constName) +local m = {} +local function compileCode(lines, asts, b) + for _, ast in ipairs(asts) do + local tt = ast.type + + if tt.type == 'enum' and not stringStartsWith(ast.name, 'enum@') then + goto continue + end + if not tt.name then + if tt.type ~= 'enum' then + goto continue + end + --匿名枚举也要创建具体的值 + lines = lines or { firstline } + builder.switch_ast(tt.type, b, lines, tt) + else + tt.full_name = ast.name + lines = lines or { firstline } + builder.switch_ast(tt.type, b, lines, tt, tt.full_name) + lines[#lines+1] = '\n' + end + ::continue:: + end + return lines +end +function m.compileCodes(codes) + ---@class ffi.builder + local b = setmetatable({ globalAsts = {}, cacheEnums = {} }, { __index = builder }) + + local lines + for _, code in ipairs(codes) do + local asts = cdriver.process_context(code) + if not asts then + goto continue + end + table.insert(b.globalAsts, asts) + lines = compileCode(lines, asts, b) + ::continue:: + end + return lines +end + +local function createDir(uri) + local dir = scope.getScope(uri).uri or 'default' + local fileDir = fs.path(METAPATH) / ('%08x'):format(SDBMHash():hash(dir)) + fs.create_directories(fileDir) + return fileDir +end + +local builder +function m.initBuilder(fileDir) + fileDir = fileDir or createDir() + ---@async + return function (uri) + local refs = cdefRerence() + if not refs or #refs == 0 then + return + end + + local codes = searchCode(refs, uri) + if not codes then + return + end + + local texts = m.compileCodes(codes) + if not texts then + return + end + local hash = ('%08x'):format(SDBMHash():hash(uri)) + local encoding = config.get(nil, 'Lua.runtime.fileEncoding') + local filePath = fileDir / table.concat({ hash, encoding }, '_') + + util.saveFile(tostring(filePath) .. '.d.lua', table.concat(texts, '\n')) + end +end + +files.watch(function (ev, uri) + if ev == 'compiler' or ev == 'update' then + if builder then + await.call(function () ---@async + builder(uri) + end) + end + end +end) + +ws.watch(function (ev, uri) + if ev == 'startReload' then + if config.get(uri, 'Lua.runtime.version') ~= 'LuaJIT' then + return + end + await.call(function () ---@async + ws.awaitReady(uri) + local fileDir = createDir(uri) + builder = m.initBuilder(fileDir) + local client = require 'client' + client.setConfig { + { + key = 'Lua.workspace.library', + action = 'add', + value = tostring(fileDir), + uri = uri, + } + } + end) + end +end) + +return m -- cgit v1.2.3 From 74328ad18382623635f614fd31f559fe90469333 Mon Sep 17 00:00:00 2001 From: fesily Date: Fri, 12 May 2023 16:12:55 +0800 Subject: add expandSingle --- script/plugins/ffi/init.lua | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) (limited to 'script/plugins/ffi/init.lua') diff --git a/script/plugins/ffi/init.lua b/script/plugins/ffi/init.lua index 57a64958..66101f90 100644 --- a/script/plugins/ffi/init.lua +++ b/script/plugins/ffi/init.lua @@ -1,7 +1,8 @@ local searchCode = require 'plugins.ffi.searchCode' local cdefRerence = require 'plugins.ffi.cdefRerence' local cdriver = require 'plugins.ffi.c-parser.cdriver' -local util = require 'utility' +local util = require 'plugins.ffi.c-parser.util' +local utility = require 'utility' local SDBMHash = require 'SDBMHash' local ws = require 'workspace' local files = require 'files' @@ -12,22 +13,6 @@ local scope = require 'workspace.scope' local namespace = 'ffi.namespace*.' -local function nkeys(t) - local n = 0 - for key, value in pairs(t) do - n = n + 1 - end - return n -end - -local function isSingleNode(ast) - if type(ast) ~= 'table' then - return false - end - local len = #ast - return len == 1 and len == nkeys(ast) -end - --TODO:supprot 32bit ffi, need config local knownTypes = { ["bool"] = 'boolean', @@ -81,7 +66,7 @@ local knownTypes = { local constName = 'm' ---@class ffi.builder -local builder = { switch_ast = util.switch() } +local builder = { switch_ast = utility.switch() } function builder:getTypeAst(name) for i, asts in ipairs(self.globalAsts) do @@ -216,9 +201,7 @@ do if ops[val.op] then return binop(enumer, val, ops[val.op]) end - if isSingleNode(val) then - val = val[1] - end + val = util.expandSingle(val) if type(val) == "string" then if enumer[val] then return enumer[val] @@ -230,9 +213,7 @@ do end local function pushEnumValue(enumer, name, v) - if isSingleNode(v) then - v = tonumber(v[1]) - end + v = tonumber(util.expandSingle(v)) enumer[name] = v enumer[#enumer+1] = v return v @@ -359,7 +340,7 @@ function m.initBuilder(fileDir) local encoding = config.get(nil, 'Lua.runtime.fileEncoding') local filePath = fileDir / table.concat({ hash, encoding }, '_') - util.saveFile(tostring(filePath) .. '.d.lua', table.concat(texts, '\n')) + utility.saveFile(tostring(filePath) .. '.d.lua', table.concat(texts, '\n')) end end -- cgit v1.2.3 From 9cc197aa5ca6c5e0314ec38266a2c0e022025307 Mon Sep 17 00:00:00 2001 From: fesily Date: Fri, 12 May 2023 16:54:03 +0800 Subject: support array --- script/plugins/ffi/init.lua | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'script/plugins/ffi/init.lua') diff --git a/script/plugins/ffi/init.lua b/script/plugins/ffi/init.lua index 66101f90..a551973a 100644 --- a/script/plugins/ffi/init.lua +++ b/script/plugins/ffi/init.lua @@ -2,7 +2,7 @@ local searchCode = require 'plugins.ffi.searchCode' local cdefRerence = require 'plugins.ffi.cdefRerence' local cdriver = require 'plugins.ffi.c-parser.cdriver' local util = require 'plugins.ffi.c-parser.util' -local utility = require 'utility' +local utility = require 'utility' local SDBMHash = require 'SDBMHash' local ws = require 'workspace' local files = require 'files' @@ -134,11 +134,23 @@ function builder:isVoid(ast) return self:isVoid(self:getTypeAst(typename)) end +local function getArrayType(arr) + if type(arr) ~= "table" then + return arr and '[]' or '' + end + local res = '' + for i, v in ipairs(arr) do + res = res .. '[]' + end + return res +end + function builder:buildStructOrUnion(lines, tt, name) lines[#lines+1] = '---@class ' .. self:getType(name) for _, field in ipairs(tt.fields or {}) do if field.name and field.type then - lines[#lines+1] = ('---@field %s %s'):format(field.name, self:getType(field.type)) + lines[#lines+1] = ('---@field %s %s%s'):format(field.name, self:getType(field.type), + getArrayType(field.isarray)) end end end @@ -146,7 +158,7 @@ end function builder:buildFunction(lines, tt, name) local param_names = {} for i, param in ipairs(tt.params or {}) do - lines[#lines+1] = ('---@param %s %s'):format(param.name, self:getType(param.type)) + lines[#lines+1] = ('---@param %s %s%s'):format(param.name, self:getType(param.type), getArrayType(param.idxs)) param_names[#param_names+1] = param.name end if tt.vararg then @@ -213,7 +225,7 @@ do end local function pushEnumValue(enumer, name, v) - v = tonumber(util.expandSingle(v)) + v = tonumber(util.expandSingle(v)) enumer[name] = v enumer[#enumer+1] = v return v -- cgit v1.2.3 From 622b1745973b409e16a9a0db5ed25a0548337e59 Mon Sep 17 00:00:00 2001 From: fesily Date: Thu, 25 May 2023 15:52:12 +0800 Subject: command:add reloadFFIMeta --- script/plugins/ffi/init.lua | 75 ++++++--------------------------------------- 1 file changed, 10 insertions(+), 65 deletions(-) (limited to 'script/plugins/ffi/init.lua') diff --git a/script/plugins/ffi/init.lua b/script/plugins/ffi/init.lua index a551973a..e79be759 100644 --- a/script/plugins/ffi/init.lua +++ b/script/plugins/ffi/init.lua @@ -4,9 +4,6 @@ local cdriver = require 'plugins.ffi.c-parser.cdriver' local util = require 'plugins.ffi.c-parser.util' local utility = require 'utility' local SDBMHash = require 'SDBMHash' -local ws = require 'workspace' -local files = require 'files' -local await = require 'await' local config = require 'config' local fs = require 'bee.filesystem' local scope = require 'workspace.scope' @@ -322,70 +319,18 @@ function m.compileCodes(codes) return lines end -local function createDir(uri) - local dir = scope.getScope(uri).uri or 'default' - local fileDir = fs.path(METAPATH) / ('%08x'):format(SDBMHash():hash(dir)) - fs.create_directories(fileDir) - return fileDir -end - -local builder -function m.initBuilder(fileDir) - fileDir = fileDir or createDir() - ---@async - return function (uri) - local refs = cdefRerence() - if not refs or #refs == 0 then - return - end - - local codes = searchCode(refs, uri) - if not codes then - return - end - - local texts = m.compileCodes(codes) - if not texts then - return - end - local hash = ('%08x'):format(SDBMHash():hash(uri)) - local encoding = config.get(nil, 'Lua.runtime.fileEncoding') - local filePath = fileDir / table.concat({ hash, encoding }, '_') - - utility.saveFile(tostring(filePath) .. '.d.lua', table.concat(texts, '\n')) +function m.build_single(codes, fileDir, uri) + local texts = m.compileCodes(codes) + if not texts then + return end -end -files.watch(function (ev, uri) - if ev == 'compiler' or ev == 'update' then - if builder then - await.call(function () ---@async - builder(uri) - end) - end - end -end) + local hash = ('%08x'):format(SDBMHash():hash(uri)) + local encoding = config.get(nil, 'Lua.runtime.fileEncoding') + local filePath = fileDir / table.concat({ hash, encoding }, '_') -ws.watch(function (ev, uri) - if ev == 'startReload' then - if config.get(uri, 'Lua.runtime.version') ~= 'LuaJIT' then - return - end - await.call(function () ---@async - ws.awaitReady(uri) - local fileDir = createDir(uri) - builder = m.initBuilder(fileDir) - local client = require 'client' - client.setConfig { - { - key = 'Lua.workspace.library', - action = 'add', - value = tostring(fileDir), - uri = uri, - } - } - end) - end -end) + utility.saveFile(tostring(filePath) .. '.d.lua', table.concat(texts, '\n')) + return true +end return m -- cgit v1.2.3 From acf091c44826846a059a0f62a43c06a0c0b278ff Mon Sep 17 00:00:00 2001 From: fesily Date: Fri, 26 May 2023 10:07:11 +0800 Subject: fix output error --- script/plugins/ffi/init.lua | 70 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 17 deletions(-) (limited to 'script/plugins/ffi/init.lua') diff --git a/script/plugins/ffi/init.lua b/script/plugins/ffi/init.lua index e79be759..f835d73f 100644 --- a/script/plugins/ffi/init.lua +++ b/script/plugins/ffi/init.lua @@ -1,17 +1,17 @@ -local searchCode = require 'plugins.ffi.searchCode' -local cdefRerence = require 'plugins.ffi.cdefRerence' -local cdriver = require 'plugins.ffi.c-parser.cdriver' -local util = require 'plugins.ffi.c-parser.util' -local utility = require 'utility' -local SDBMHash = require 'SDBMHash' -local config = require 'config' -local fs = require 'bee.filesystem' -local scope = require 'workspace.scope' +local searchCode = require 'plugins.ffi.searchCode' +local cdefRerence = require 'plugins.ffi.cdefRerence' +local cdriver = require 'plugins.ffi.c-parser.cdriver' +local util = require 'plugins.ffi.c-parser.util' +local utility = require 'utility' +local SDBMHash = require 'SDBMHash' +local config = require 'config' +local fs = require 'bee.filesystem' +local scope = require 'workspace.scope' -local namespace = 'ffi.namespace*.' +local namespace = 'ffi.namespace*.' --TODO:supprot 32bit ffi, need config -local knownTypes = { +local knownTypes = { ["bool"] = 'boolean', ["char"] = 'integer', ["short"] = 'integer', @@ -60,10 +60,33 @@ local knownTypes = { ["signedlong"] = 'integer', } -local constName = 'm' +local blackKeyWord = { + ['and'] = "_and", + ['do'] = "_do", + ['elseif'] = "_elseif", + ['end'] = "_end", + ['false'] = "_false", + ['function'] = "_function", + ['in'] = "_in", + ['local'] = "_local", + ['nil'] = "_nil", + ['not'] = "_not", + ['or'] = "_or", + ['repeat'] = "_repeat", + ['then'] = "_then", + ['true'] = "_true", +} + +local invaildKeyWord = { + const = true, + restrict = true, + volatile = true, +} + +local constName = 'm' ---@class ffi.builder -local builder = { switch_ast = utility.switch() } +local builder = { switch_ast = utility.switch() } function builder:getTypeAst(name) for i, asts in ipairs(self.globalAsts) do @@ -95,14 +118,22 @@ function builder:getType(name) if type(name) == 'table' then local t = "" local isStruct + if name.type then + t = t .. name.type .. "@" + name = name.name + end for _, n in ipairs(name) do if type(n) == 'table' then n = n.full_name end + if invaildKeyWord[n] then + goto continue + end if not isStruct then isStruct = self:needDeref(self:getTypeAst(n)) end t = t .. n + ::continue:: end -- deref 一级指针 if isStruct and t:sub(#t) == '*' then @@ -142,11 +173,15 @@ local function getArrayType(arr) return res end +local function getValidName(name) + return blackKeyWord[name] or name +end + function builder:buildStructOrUnion(lines, tt, name) lines[#lines+1] = '---@class ' .. self:getType(name) for _, field in ipairs(tt.fields or {}) do if field.name and field.type then - lines[#lines+1] = ('---@field %s %s%s'):format(field.name, self:getType(field.type), + lines[#lines+1] = ('---@field %s %s%s'):format(getValidName(field.name), self:getType(field.type), getArrayType(field.isarray)) end end @@ -155,8 +190,9 @@ end function builder:buildFunction(lines, tt, name) local param_names = {} for i, param in ipairs(tt.params or {}) do - lines[#lines+1] = ('---@param %s %s%s'):format(param.name, self:getType(param.type), getArrayType(param.idxs)) - param_names[#param_names+1] = param.name + local param_name = getValidName(param.name) + lines[#lines+1] = ('---@param %s %s%s'):format(param_name, self:getType(param.type), getArrayType(param.idxs)) + param_names[#param_names+1] = param_name end if tt.vararg then param_names[#param_names+1] = '...' @@ -175,7 +211,7 @@ function builder:buildTypedef(lines, tt, name) -- 这个时候没有主类型,只有一个别名,直接创建一个别名结构体 self.switch_ast(def.type, self, lines, def, name) else - lines[#lines+1] = ('---@alias %s %s'):format(name, self:getType(def)) + lines[#lines+1] = ('---@alias %s %s'):format(self:getType(name), self:getType(def)) end end -- cgit v1.2.3 From 7e56bc0fab89dc34f009a18f066a08e23f6e4838 Mon Sep 17 00:00:00 2001 From: fesily Date: Thu, 1 Jun 2023 10:45:16 +0800 Subject: ffi:fix build path --- script/plugins/ffi/init.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'script/plugins/ffi/init.lua') diff --git a/script/plugins/ffi/init.lua b/script/plugins/ffi/init.lua index f835d73f..17159ff2 100644 --- a/script/plugins/ffi/init.lua +++ b/script/plugins/ffi/init.lua @@ -1,12 +1,11 @@ -local searchCode = require 'plugins.ffi.searchCode' -local cdefRerence = require 'plugins.ffi.cdefRerence' local cdriver = require 'plugins.ffi.c-parser.cdriver' local util = require 'plugins.ffi.c-parser.util' local utility = require 'utility' local SDBMHash = require 'SDBMHash' local config = require 'config' local fs = require 'bee.filesystem' -local scope = require 'workspace.scope' +local ws = require 'workspace' +local furi = require 'file-uri' local namespace = 'ffi.namespace*.' @@ -360,12 +359,15 @@ function m.build_single(codes, fileDir, uri) if not texts then return end + local fullPath = fileDir /ws.getRelativePath(uri) - local hash = ('%08x'):format(SDBMHash():hash(uri)) - local encoding = config.get(nil, 'Lua.runtime.fileEncoding') - local filePath = fileDir / table.concat({ hash, encoding }, '_') + if fullPath:stem():string():find '%.' then + local newPath = fullPath:parent_path() / (fullPath:stem():string():gsub('%.', '/') .. ".lua") + fs.create_directories(newPath:parent_path()) + fullPath = newPath + end - utility.saveFile(tostring(filePath) .. '.d.lua', table.concat(texts, '\n')) + utility.saveFile(tostring(fullPath), table.concat(texts, '\n')) return true end -- cgit v1.2.3