在trepl或luajit中,如何找到我正在使用的库的源代码? [英] In trepl or luajit, how can I find the source code of a library I'm using?

查看:103
本文介绍了在trepl或luajit中,如何找到我正在使用的库的源代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我正在使用通过luarocks安装的lua库工作,我想查看该库中函数的定义.在ipython中可以使用

?? function_name

要查看终端中的定义,在matlab中我可以使用

哪个function_name

然后使用我的编辑器查看其中返回的路径.我该怎么做才能找到lua库的函数定义?

解决方案

在普通" Lua/JIT中,您可以说

,或者甚至启动编辑器并将其指向该位置,例如(对于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

只是为了好玩,这是另一个版本,如果可以在某个地方找到它,则返回该代码. (这也适用于在运行时生成的函数,例如,通过调用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定义的,而不是直接输入口译员).这样,无需复制粘贴就可以将源保存到文件中,并且不需要编辑>>提示.

Let's say I'm working with a lua library I installed using luarocks, and I want to see the definition of a function from that library. In ipython in could use

??function_name

to see the definition in the terminal, in matlab I could use

which function_name

then use my editor to look at the path returned by which. How could I do something similar to find the function definition for a lua library?

In 'plain' Lua/JIT, you can say debug.getinfo( func ) and will get a table containing (among others) the fields short_src, source and linedefined.

For Lua functions, short_src will be the filename or stdin if it was defined in the REPL. (source has a slightly different format, filenames are prefixed with an @, a = prefix is used for C functions or stuff defined interactively, and for loaded functions, it will be the actual string that was loaded.)

You can pack that up in a function like

function sourceof( f )
    local info = debug.getinfo( f, "S" )
    return info.short_src, info.linedefined
end

or maybe even start an editor and point it there, e.g. (for 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

And just for fun, here's yet another version that returns the code if it can find it somewhere. (This will also work for functions that have been generated at run time, e.g. by calling load, and where no source file exists. You could also work in the other direction by dumping the loaded snippet into a temp file and opening that…)

-- 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

A closing remark: If you paste code into a Lua/JIT REPL, locals disappear between definitions, because every line (or minimal complete group of lines) is its own chunk. The common fix (that you probably know) is to wrap everything into a block as do*paste*end, but an alternative is to load[[*paste*]]() (possibly with more =s like [===[ and ]===].) If you paste this way, the above dumpsource (or any other function using debug.getinfo) will then be able to get the source of the function(s). This also means that if you defined a nice function but it's gone from the history and the scroll buffer, you can recover it in this way (if you defined it by loading and not directly feeding the interpreter). Saving the source in a file will then also be possible without copy-pasting and not require editing out the >> prompts.

这篇关于在trepl或luajit中,如何找到我正在使用的库的源代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆