1
0

Function formatting will now automatically pull documentation from a lua file, if it knows where to look.

This commit is contained in:
Jon Michael Aanes 2017-06-24 20:06:36 +02:00
parent 3bb599e976
commit 9a6a5b4b51
4 changed files with 119 additions and 33 deletions

View File

@ -123,12 +123,23 @@ local function get_function_paramlist_and_body (str, start_line, end_line)
local start_line_index = get_line_index(str, start_line)
local end_line_index = get_line_index(str, end_line + 1)
local function_params, function_body = str:sub(start_line_index, end_line_index):match('.*function%s*[a-zA-Z0-9_.]*%s*(%([a-zA-Z0-9_,. \t]*%))[ \t]*(.+)[ \t]*end')
local function_params, function_body = str:sub(start_line_index, end_line_index):match('.*%f[%a_]function%f[^%a_]%s*[a-zA-Z0-9_.]*%s*(%([a-zA-Z0-9_,. \t]*%))[ \t]*(.+)[ \t]*end')
function_body = function_body:match('^%s*(.-)%s*$')
assert(type(function_params) == 'string' and type(function_body) == 'string')
return function_params, function_body
end
local function get_function_body_from_file (filename, start_line, end_line)
assert(type(filename) == 'string')
assert(type(start_line) == 'number')
assert(type(end_line) == 'number')
local file = io.open(filename, 'r')
local str = file:read('*all')
file:close()
return select(2, get_function_paramlist_and_body(str, start_line, end_line))
end
local function get_full_function_str (...)
local function_params, function_body = get_function_paramlist_and_body(...)
return 'function '..function_params..' '..function_body..' end'
@ -159,14 +170,20 @@ local function add_indent_to_string (str, indent)
assert(type(str) == 'string')
assert(type(indent) == 'string')
local l = {}
for line in str:gmatch('[^\n]+', true) do
l[#l+1] = indent
l[#l+1] = line
l[#l+1] = '\n'
return indent .. str:gsub('\n', '\n'..indent)
end
local function get_docs_from_function_body (func_body)
assert(type(func_body) == 'string')
local doc_lines = {}
for line in func_body:gmatch('[^\n]+', true) do
if not line:match('^%s*$') then
local line_text = line:match('^%s*%-%-%s*(.*)%s*$')
if not line_text then break end
doc_lines[#doc_lines+1] = line_text
end
end
if l[#l] == '\n' then l[#l] = nil end
return table.concat(l, '')
return table.concat(doc_lines, '\n')
end
--------------------------------------------------------------------------------
@ -215,6 +232,10 @@ return function (value, depth, l, format_value)
if info.defined_how == 'string' and l.options.embed_loaded_funcs then
-- Function was defined as a string.
function_params, function_body = get_function_paramlist_and_body(info.source, info.linedefined, info.lastlinedefined)
--elseif info.defined_how == 'file' then
--function_body = get_function_body_from_file(info.short_src, info.linedefined, info.lastlinedefined)
----print(function_body)
--function_body = function_body or '...'
end
if info.builtin and l.options.short_builtins then
@ -259,17 +280,21 @@ return function (value, depth, l, format_value)
end
-- Doc
if info.doc then
for doc_line in info.doc:gmatch('[^\n]+') do
l[#l+1] = indent
l[#l+1] = '-- '
if not info.doc then
local function_body = get_function_body_from_file(info.short_src, info.linedefined, info.lastlinedefined)
if function_body then
local documentation = get_docs_from_function_body(function_body)
info.doc = documentation ~= '' and documentation
end
end
l[#l+1] = doc_line
end
if info.doc then
l[#l+1] = '\n'
l[#l+1] = add_indent_to_string(info.doc, l.options.indent .. '-- ')
end
-- source
if not info.builtin then
if not info.builtin and not info.doc then
l[#l+1] = indent
l[#l+1] = ('-- source_file: \'%s\' '):format(info.short_src)
if info.linedefined == info.lastlinedefined then
@ -280,7 +305,7 @@ return function (value, depth, l, format_value)
end
-- upvalues
if info.nups > 0 and not info.builtin then
if info.nups > 0 and (not info.builtin and not info.doc) then
l[#l+1] = indent
l[#l+1] = '-- up_values: '
format_value(info.ups, depth + 1, l)

View File

@ -474,8 +474,8 @@ local KNOWN_OPTIONS = {
indent = { type = 'string', default = ' ' },
max_depth = { type = 'number', default = math.huge },
embed_loaded_funcs = { type = 'boolean', default = false }, -- TODO: Outphase this, in favor of automatically embedding "small enough" functions.
recursion = { type = 'string', default = 'ignore', accepted = {['ignore'] = true, ['marked'] = true} },
short_builtins = { type = 'boolean', default = false }, -- TODO: Outphase this. Rather automatically use the short versions in places where it would be strange to find the function, like keys, etc.
recursion = { type = 'string', default = 'ignore', accepted = {['ignore'] = true, ['marked'] = true} },
}
local function ensure_that_all_options_are_known (options)

View File

@ -166,7 +166,7 @@ SUITE:addTest('Recursive Numeration, Simple', function ()
input[1] = input
local info = analyze_structure(input)
assert(info[input].marker == 1)
assert_equal(1, info[input].marker)
end)
SUITE:addTest('Recursive Numeration, Multiple-appear', function ()
@ -174,7 +174,7 @@ SUITE:addTest('Recursive Numeration, Multiple-appear', function ()
input[1][1] = input[2][1]
local info = analyze_structure(input)
assert(info[input[1][1]].marker == 1)
assert_equal(1, info[input[1][1]].marker)
end)
SUITE:addTest('Recursive Numeration, Multiple at once', function ()
@ -183,8 +183,8 @@ SUITE:addTest('Recursive Numeration, Multiple at once', function ()
input[1][2] = input
local info = analyze_structure(input)
assert(type(info[input[1][1]].marker) == 'number')
assert(type(info[input].marker) == 'number')
assert_equal('number', type(info[input[1][1]].marker))
assert_equal('number', type(info[input].marker))
end)
SUITE:addTest('Recursive Numeration, Through Keys', function ()
@ -192,7 +192,7 @@ SUITE:addTest('Recursive Numeration, Through Keys', function ()
input[input] = input
local info = analyze_structure(input)
assert(info[input].marker == 1)
assert_equal(1, info[input].marker)
end)
--------------------------------------------------------------------------------
@ -209,7 +209,7 @@ SUITE:addTest('Can count elements, even though metatable.__index throws errors',
local input = setmetatable({ 'hi', 'hello' }, {__index = function (_, k) error('Undefined access on key: '..k) end})
local info = analyze_structure(input)
assert_equal(info[input].seq_elems, 2)
assert_equal(2, info[input].seq_elems)
end)
--------------------------------------------------------------------------------
@ -219,21 +219,21 @@ SUITE:addTest('Can detect uniform structure', function ()
local input = { a = 'b', b = 'a' }
local info = analyze_structure(input)
assert_equal(info[input].is_uniform, true)
assert_equal(true, info[input].is_uniform)
end)
SUITE:addTest('Can detect uniform structure with different key value types', function ()
local input = { a = 1, b = 4 }
local info = analyze_structure(input)
assert_equal(info[input].is_uniform, true)
assert_equal(true, info[input].is_uniform)
end)
SUITE:addTest('Can detect basic non-uniform structure', function ()
local input = { a = 'b', b = 5 }
local info = analyze_structure(input)
assert_equal(info[input].is_uniform, false)
assert_equal(false, info[input].is_uniform)
end)
SUITE:addTest('Can detect pseudo-uniform structure with nested tables', function ()
@ -242,14 +242,14 @@ SUITE:addTest('Can detect pseudo-uniform structure with nested tables', function
local input = { a = { d = 7 }, b = { p = 3 } }
local info = analyze_structure(input)
assert_equal(info[input].is_uniform, true)
assert_equal(true, info[input].is_uniform)
end)
SUITE:addTest('Can detect non-uniform structure with nested tables', function ()
local input = { a = { 'a', 'b', 'c' }, b = { p = 3, 'hi' } }
local info = analyze_structure(input)
assert_equal(info[input].is_uniform, false)
assert_equal(false, info[input].is_uniform)
end)
-- TODO: Add predicate to check for pseudo-uniformness.

View File

@ -119,15 +119,67 @@ format_test {
expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n -- up_values: { TEST_UPVALUE = 42 }\n\n ...\nend'
}
local func_line = curline(3)
--------------------------------------------------------------------------------
-- Elaborate functions with documentation
format_test {
name = 'Elaborate function with documentation',
name = 'Basic Func with docs',
input = function ()
-- Hello World
if true then return false end
-- This is docs
return true
end,
expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Lines: '..func_line..' - '..(func_line+1)..']\n -- Hello World\n\n ...\nend',
expect = 'function ()\n -- This is docs\n\n ...\nend',
}
format_test {
name = 'Comments after other code won\'t be included as docs',
input = function ()
-- This is also docs
if true then return false end
-- Some other comment, that won't appear as docs.
return true
end,
expect = 'function ()\n -- This is also docs\n\n ...\nend',
}
format_test {
name = 'We can leave a space between doc lines',
input = function ()
-- This is docs
-- This is also docs
return true
end,
expect = 'function ()\n -- This is docs\n -- This is also docs\n\n ...\nend',
}
format_test {
name = 'We can also leave a line with an empty comment',
input = function ()
-- This is docs
--
-- This is also docs
return true
end,
expect = 'function ()\n -- This is docs\n -- \n -- This is also docs\n\n ...\nend',
}
format_test {
name = 'No opvalues when docs are there',
input = function ()
-- This is docs
return TEST_UPVALUE
end,
expect = 'function ()\n -- This is docs\n\n ...\nend',
}
format_test {
name = 'Can find docs when body contains the word "function"',
input = function ()
-- Hi
_function()
end,
expect = 'function ()\n -- Hi\n\n ...\nend',
}
--------------------------------------------------------------------------------
@ -229,6 +281,15 @@ format_test {
expect = 'function () ... end',
}
format_test {
name = 'Can still find body when body contains the word "function"',
single = true,
adv_getlocal = true,
options = { embed_loaded_funcs = true },
input = loadstring('return function () function_body() end')(),
expect = 'function () function_body() end',
}
--------------------------------------------------------------------------------
-- Indent functions nicely