В "простом" Lua / JIT вы можете сказать _1 _ ( func )
и получит таблицу, содержащую (среди прочего) поля 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
И просто для удовольствия, вот еще одна версия, которая возвращает код, если он может где-то его найти. (Это также будет работать для функций, которые были сгенерированы во время выполнения, например, путем вызова 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
s исчезают между определениями, потому что каждая строка (или минимальная полная группа строк) является отдельным фрагментом. Обычное исправление (которое вы, вероятно, знаете) - это обернуть все в блок как do
* paste * end
, но альтернативой является load[[
* paste * ]]()
(возможно, с большим количеством =
, таких как [===[
и ]===]
.) Если вы вставите таким образом, указанная выше dumpsource
(или любая другая функция, использующая debug.getinfo
) сможет получить источник функции (ей). Это также означает, что если вы определили красивую функцию, но она исчезла из истории и буфера прокрутки, вы можете восстановить ее таким способом (если вы определили ее с помощью load
ing, а не напрямую загрузили интерпретатор). Сохранение исходного кода в файле также будет возможно без копирования-вставки и не потребует редактирования >>
подсказок.
person
nobody
schedule
26.04.2015
Easy help with: ? funcname
(см. ссылку) - person Egor Skriptunoff   schedule 26.04.2015