在 trepl 或 luajit 中,如何找到我正在使用的库的源代码?
In trepl or luajit, how can I find the source code of a library I'm using?
假设我正在使用使用 luarocks 安装的 lua 库,我想查看该库中函数的定义。在 ipython 中可以使用
??function_name
要在终端中查看定义,在 matlab 中我可以使用
which function_name
然后用我的编辑器看看which返回的路径。我怎样才能做类似的事情来找到 lua 库的函数定义?
在 'plain' Lua/JIT 中,您可以说 debug.getinfo
( func )
并会得到一个 table 包含(除其他外)字段 short_src
, source
和 linedefined
.
对于 Lua 函数,short_src
将是文件名或 stdin
如果它已在 REPL 中定义。 (source
的格式略有不同,文件名以 @
为前缀,=
前缀用于 C 函数或交互式定义的内容,以及 load
ed 函数,它将是实际加载的字符串。)
你可以把它打包成一个函数,比如
function sourceof( f )
local info = debug.getinfo( f, "S" )
return info.short_src, info.linedefined
end
或者甚至可以启动一个编辑器并将其指向那里,例如(对于 vim)
function viewsource( f )
-- get info & check it's actually from a file
local info = debug.getinfo( f, "S" )
local src, line = info.source, info.linedefined
if src == "=[C]" then return nil, "Is a C function." end
local path = src:match "^@(.*)$"
if path then
-- start vim (or an other editor if you adapt the format string)
return os.execute( ("vim -fR %q +%d"):format( path, line ) )
end
return nil, "Was defined at run time."
end
只是为了好玩,这里还有另一个版本 returns 如果可以在某处找到代码,则可以使用该代码。 (这也适用于在 运行 时间生成的函数,例如通过调用 load
,并且不存在源文件。您也可以通过转储 load
ed 代码片段到一个临时文件中并打开它……)
-- helper to extract the source block defining the function
local function funclines( str, line1, lineN, filename )
-- if linedefined / lastlinedefined are 0, this is the main chunk's function
if line1 == 0 and lineN == 0 then
filename = filename and filename.." (main chunk)"
or "(chunk defined at runtime)"
return "-- "..filename.."\n"..str
end
-- add line info to file name or use placeholder
filename = filename and filename..":"..line1 or "(defined at runtime)"
-- get the source block
local phase, skip, grab = 1, line1-1, lineN-(line1-1)
local ostart, oend -- these will be the start/end offsets
if skip == 0 then phase, ostart = 2, 0 end -- starts at first line
for pos in str:gmatch "\n()" do
if phase == 1 then -- find offset of linedefined
skip = skip - 1 ; if skip == 0 then ostart, phase = pos, 2 end
else -- phase == 2, find offset of lastlinedefined+1
grab = grab - 1 ; if grab == 0 then oend = pos-2 ; break end
end
end
return "-- "..filename.."\n"..str:sub( ostart, oend )
end
function dumpsource( f )
-- get info & line numbers
local info = debug.getinfo( f, "S" )
local src, line, lastline = info.source, info.linedefined, info.lastlinedefined
-- can't do anything for a C function
if src == "=[C]" then return nil, "Is a C function." end
if src == "=stdin" then return nil, "Was defined interactively." end
-- for files, fetch the definition
local path = src:match "^@(.*)$"
if path then
local f = io.open( path )
local code = f:read '*a'
f:close( )
return funclines( code, line, lastline, path )
end
-- otherwise `load`ed, so `source`/`src` _is_ the source
return funclines( src, line, lastline )
end
结束语:如果将代码粘贴到 Lua/JIT REPL 中,local
会在定义之间消失,因为每一行(或最小的完整行组)都是它自己的块。常见的修复方法(您可能知道)是将所有内容包装到一个块中,如 do
*paste*end
,但另一种方法是 load[[
*paste*]]()
(可能有更多的 =
,如 [===[
和 ]===]
。)如果你这样粘贴,上面的 dumpsource
(或任何其他使用 debug.getinfo
的函数)将会能够获得功能的来源。这也意味着,如果您定义了一个不错的函数,但它已从历史记录和滚动缓冲区中消失,您可以通过这种方式恢复它(if 您通过 load
ing 定义了它而不是直接喂口译员)。无需复制粘贴也可以将源代码保存在文件中,也不需要编辑掉 >>
提示。
假设我正在使用使用 luarocks 安装的 lua 库,我想查看该库中函数的定义。在 ipython 中可以使用
??function_name
要在终端中查看定义,在 matlab 中我可以使用
which function_name
然后用我的编辑器看看which返回的路径。我怎样才能做类似的事情来找到 lua 库的函数定义?
在 'plain' Lua/JIT 中,您可以说 debug.getinfo
( func )
并会得到一个 table 包含(除其他外)字段 short_src
, source
和 linedefined
.
对于 Lua 函数,short_src
将是文件名或 stdin
如果它已在 REPL 中定义。 (source
的格式略有不同,文件名以 @
为前缀,=
前缀用于 C 函数或交互式定义的内容,以及 load
ed 函数,它将是实际加载的字符串。)
你可以把它打包成一个函数,比如
function sourceof( f )
local info = debug.getinfo( f, "S" )
return info.short_src, info.linedefined
end
或者甚至可以启动一个编辑器并将其指向那里,例如(对于 vim)
function viewsource( f )
-- get info & check it's actually from a file
local info = debug.getinfo( f, "S" )
local src, line = info.source, info.linedefined
if src == "=[C]" then return nil, "Is a C function." end
local path = src:match "^@(.*)$"
if path then
-- start vim (or an other editor if you adapt the format string)
return os.execute( ("vim -fR %q +%d"):format( path, line ) )
end
return nil, "Was defined at run time."
end
只是为了好玩,这里还有另一个版本 returns 如果可以在某处找到代码,则可以使用该代码。 (这也适用于在 运行 时间生成的函数,例如通过调用 load
,并且不存在源文件。您也可以通过转储 load
ed 代码片段到一个临时文件中并打开它……)
-- helper to extract the source block defining the function
local function funclines( str, line1, lineN, filename )
-- if linedefined / lastlinedefined are 0, this is the main chunk's function
if line1 == 0 and lineN == 0 then
filename = filename and filename.." (main chunk)"
or "(chunk defined at runtime)"
return "-- "..filename.."\n"..str
end
-- add line info to file name or use placeholder
filename = filename and filename..":"..line1 or "(defined at runtime)"
-- get the source block
local phase, skip, grab = 1, line1-1, lineN-(line1-1)
local ostart, oend -- these will be the start/end offsets
if skip == 0 then phase, ostart = 2, 0 end -- starts at first line
for pos in str:gmatch "\n()" do
if phase == 1 then -- find offset of linedefined
skip = skip - 1 ; if skip == 0 then ostart, phase = pos, 2 end
else -- phase == 2, find offset of lastlinedefined+1
grab = grab - 1 ; if grab == 0 then oend = pos-2 ; break end
end
end
return "-- "..filename.."\n"..str:sub( ostart, oend )
end
function dumpsource( f )
-- get info & line numbers
local info = debug.getinfo( f, "S" )
local src, line, lastline = info.source, info.linedefined, info.lastlinedefined
-- can't do anything for a C function
if src == "=[C]" then return nil, "Is a C function." end
if src == "=stdin" then return nil, "Was defined interactively." end
-- for files, fetch the definition
local path = src:match "^@(.*)$"
if path then
local f = io.open( path )
local code = f:read '*a'
f:close( )
return funclines( code, line, lastline, path )
end
-- otherwise `load`ed, so `source`/`src` _is_ the source
return funclines( src, line, lastline )
end
结束语:如果将代码粘贴到 Lua/JIT REPL 中,local
会在定义之间消失,因为每一行(或最小的完整行组)都是它自己的块。常见的修复方法(您可能知道)是将所有内容包装到一个块中,如 do
*paste*end
,但另一种方法是 load[[
*paste*]]()
(可能有更多的 =
,如 [===[
和 ]===]
。)如果你这样粘贴,上面的 dumpsource
(或任何其他使用 debug.getinfo
的函数)将会能够获得功能的来源。这也意味着,如果您定义了一个不错的函数,但它已从历史记录和滚动缓冲区中消失,您可以通过这种方式恢复它(if 您通过 load
ing 定义了它而不是直接喂口译员)。无需复制粘贴也可以将源代码保存在文件中,也不需要编辑掉 >>
提示。