diff options
Diffstat (limited to 'scripts/lua2dox.lua')
-rw-r--r-- | scripts/lua2dox.lua | 798 |
1 files changed, 359 insertions, 439 deletions
diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua index 19f8f8141d..1c8bc5a3cb 100644 --- a/scripts/lua2dox.lua +++ b/scripts/lua2dox.lua @@ -1,6 +1,6 @@ ---[[-------------------------------------------------------------------------- --- Copyright (C) 2012 by Simon Dales -- --- simon@purrsoft.co.uk -- +----------------------------------------------------------------------------- +-- Copyright (C) 2012 by Simon Dales -- +-- simon@purrsoft.co.uk -- -- -- -- This program is free software; you can redistribute it and/or modify -- -- it under the terms of the GNU General Public License as published by -- @@ -16,7 +16,7 @@ -- along with this program; if not, write to the -- -- Free Software Foundation, Inc., -- -- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- -----------------------------------------------------------------------------]] +----------------------------------------------------------------------------- --[[! Lua-to-Doxygen converter @@ -24,11 +24,18 @@ Lua-to-Doxygen converter Partially from lua2dox http://search.cpan.org/~alec/Doxygen-Lua-0.02/lib/Doxygen/Lua.pm -Running +RUNNING ------- This script "lua2dox.lua" gets called by "gen_vimdoc.py". +DEBUGGING/DEVELOPING +--------------------- + +1. To debug, run gen_vimdoc.py with --keep-tmpfiles: + python3 scripts/gen_vimdoc.py -t treesitter --keep-tmpfiles +2. The filtered result will be written to ./tmp-lua2dox-doc/….lua.c + Doxygen must be on your system. You can experiment like so: - Run "doxygen -g" to create a default Doxyfile. @@ -41,498 +48,395 @@ It only has to be good enough for doxygen to see it as legal. One limitation is that each line is treated separately (except for long comments). The implication is that class and function declarations must be on the same line. -Some functions can have their parameter lists extended over multiple lines to make it look neat. -Managing this where there are also some comments is a bit more coding than I want to do at this stage, -so it will probably not document accurately if we do do this. -However I have put in a hack that will insert the "missing" close paren. +There is hack that will insert the "missing" close paren. The effect is that you will get the function documented, but not with the parameter list you might expect. ]] -local function class() - local newClass = {} -- a new class newClass - -- the class will be the metatable for all its newInstanceects, - -- and they will look up their methods in it. - newClass.__index = newClass - - -- expose a constructor which can be called by <classname>(<args>) - setmetatable(newClass, { - __call = function(class_tbl, ...) - local newInstance = {} - setmetatable(newInstance, newClass) - --if init then - -- init(newInstance,...) - if class_tbl.init then - class_tbl.init(newInstance, ...) - end - return newInstance - end - }) - return newClass -end +local TYPES = { 'integer', 'number', 'string', 'table', 'list', 'boolean', 'function' } + +local TAGGED_TYPES = { 'TSNode', 'LanguageTree' } ---! \brief write to stdout -local function TCore_IO_write(Str) - if Str then - io.write(Str) +-- Document these as 'table' +local ALIAS_TYPES = { + 'Range', 'Range4', 'Range6', 'TSMetadata', + 'vim.filetype.add.filetypes', + 'vim.filetype.match.args' +} + +local debug_outfile = nil --- @type string? +local debug_output = {} + +--- write to stdout +--- @param str? string +local function write(str) + if not str then + return end -end ---! \brief write to stdout -local function TCore_IO_writeln(Str) - if Str then - io.write(Str) + io.write(str) + if debug_outfile then + table.insert(debug_output, str) end - io.write('\n') end ---! \brief trims a string -local function string_trim(Str) - return Str:match('^%s*(.-)%s*$') +--- write to stdout +--- @param str? string +local function writeln(str) + write(str) + write('\n') end ---! \brief split a string ---! ---! \param Str ---! \param Pattern ---! \returns table of string fragments ----@return string[] -local function string_split(Str, Pattern) - local splitStr = {} - local fpat = '(.-)' .. Pattern - local last_end = 1 - local str, e, cap = string.find(Str, fpat, 1) - while str do - if str ~= 1 or cap ~= '' then - table.insert(splitStr, cap) - end - last_end = e + 1 - str, e, cap = string.find(Str, fpat, last_end) - end - if last_end <= #Str then - cap = string.sub(Str, last_end) - table.insert(splitStr, cap) +--- an input file buffer +--- @class StreamRead +--- @field currentLine string? +--- @field contentsLen integer +--- @field currentLineNo integer +--- @field filecontents string[] +local StreamRead = {} + +--- @return StreamRead +--- @param filename string +function StreamRead.new(filename) + assert(filename, ('invalid file: %s'):format(filename)) + -- get lines from file + -- syphon lines to our table + local filecontents = {} --- @type string[] + for line in io.lines(filename) do + filecontents[#filecontents+1] = line end - return splitStr + + return setmetatable({ + filecontents = filecontents, + contentsLen = #filecontents, + currentLineNo = 1, + }, { __index = StreamRead }) end -------------------------------- ---! \brief file buffer ---! ---! an input file buffer -local TStream_Read = class() - ---! \brief get contents of file ---! ---! \param Filename name of file to read (or nil == stdin) -function TStream_Read.getContents(this, Filename) - assert(Filename, ('invalid file: %s'):format(Filename)) - -- get lines from file - -- syphon lines to our table - local filecontents = {} - for line in io.lines(Filename) do - table.insert(filecontents, line) +-- get a line +function StreamRead:getLine() + if self.currentLine then + self.currentLine = nil + return self.currentLine end - if filecontents then - this.filecontents = filecontents - this.contentsLen = #filecontents - this.currentLineNo = 1 + -- get line + if self.currentLineNo <= self.contentsLen then + local line = self.filecontents[self.currentLineNo] + self.currentLineNo = self.currentLineNo + 1 + return line end - return filecontents + return '' end ---! \brief get lineno -function TStream_Read.getLineNo(this) - return this.currentLineNo +-- save line fragment +--- @param line_fragment string +function StreamRead:ungetLine(line_fragment) + self.currentLine = line_fragment end ---! \brief get a line -function TStream_Read.getLine(this) - local line - if this.currentLine then - line = this.currentLine - this.currentLine = nil - else - -- get line - if this.currentLineNo <= this.contentsLen then - line = this.filecontents[this.currentLineNo] - this.currentLineNo = this.currentLineNo + 1 - else - line = '' - end - end - return line +-- is it eof? +function StreamRead:eof() + return not self.currentLine and self.currentLineNo > self.contentsLen end ---! \brief save line fragment -function TStream_Read.ungetLine(this, LineFrag) - this.currentLine = LineFrag +-- input filter +--- @class Lua2DoxFilter +local Lua2DoxFilter = {} +setmetatable(Lua2DoxFilter, { __index = Lua2DoxFilter }) + +--- trim comment off end of string +--- +--- @param line string +--- @return string, string? +local function removeCommentFromLine(line) + local pos_comment = line:find('%-%-') + if not pos_comment then + return line + end + return line:sub(1, pos_comment - 1), line:sub(pos_comment) end ---! \brief is it eof? -function TStream_Read.eof(this) - if this.currentLine or this.currentLineNo <= this.contentsLen then - return false +--- Processes "@…" directives in a docstring line. +--- +--- @param line string +--- @param generics table<string,string> +--- @return string? +local function process_magic(line, generics) + line = line:gsub('^%s+@', '@') + line = line:gsub('@package', '@private') + line = line:gsub('@nodoc', '@private') + + if not vim.startswith(line, '@') then -- it's a magic comment + return '/// ' .. line end - return true -end ---! \brief output stream -local TStream_Write = class() + local magic = line:sub(2) + local magic_split = vim.split(magic, ' ', { plain = true }) + local directive = magic_split[1] ---! \brief constructor -function TStream_Write.init(this) - this.tailLine = {} -end + if vim.list_contains({ + 'cast', 'diagnostic', 'overload', 'meta', 'type' + }, directive) then + -- Ignore LSP directives + return '// gg:"' .. line .. '"' + end ---! \brief write immediately -function TStream_Write.write(_, Str) - TCore_IO_write(Str) -end + if directive == 'defgroup' or directive == 'addtogroup' then + -- Can't use '.' in defgroup, so convert to '--' + return '/// @' .. magic:gsub('%.', '-dot-') + end ---! \brief write immediately -function TStream_Write.writeln(_, Str) - TCore_IO_writeln(Str) -end + if directive == 'generic' then + local generic_name, generic_type = line:match('@generic%s*(%w+)%s*:?%s*(.*)') + if generic_type == '' then + generic_type = 'any' + end + generics[generic_name] = generic_type + return + end ---! \brief write immediately -function TStream_Write.writelnComment(_, Str) - TCore_IO_write('// ZZ: ') - TCore_IO_writeln(Str) -end + local type_index = 2 ---! \brief write to tail -function TStream_Write.writelnTail(this, Line) - if not Line then - Line = '' + if directive == 'param' then + for _, type in ipairs(TYPES) do + magic = magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. ')%)', 'param %1 %2') + magic = + magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '|nil)%)', 'param %1 %2') + end + magic_split = vim.split(magic, ' ', { plain = true }) + type_index = 3 + elseif directive == 'return' then + for _, type in ipairs(TYPES) do + magic = magic:gsub('^return%s+.*%((' .. type .. ')%)', 'return %1') + magic = magic:gsub('^return%s+.*%((' .. type .. '|nil)%)', 'return %1') + end + -- Remove first "#" comment char, if any. https://github.com/LuaLS/lua-language-server/wiki/Annotations#return + magic = magic:gsub('# ', '', 1) + -- handle the return of vim.spell.check + magic = magic:gsub('({.*}%[%])', '`%1`') + magic_split = vim.split(magic, ' ', { plain = true }) end - table.insert(this.tailLine, Line) -end ---! \brief output tail lines -function TStream_Write.write_tailLines(this) - for _, line in ipairs(this.tailLine) do - TCore_IO_writeln(line) - end - TCore_IO_write('// Lua2DoX new eof') -end + local ty = magic_split[type_index] + + if ty then + -- fix optional parameters + if magic_split[2]:find('%?$') then + if not ty:find('nil') then + ty = ty .. '|nil' + end + magic_split[2] = magic_split[2]:sub(1, -2) + end ---! \brief input filter -local TLua2DoX_filter = class() + -- replace generic types + for k, v in pairs(generics) do + ty = ty:gsub(k, v) --- @type string + end ---! \brief allow us to do errormessages -function TLua2DoX_filter.warning(this, Line, LineNo, Legend) - this.outStream:writelnTail( - '//! \todo warning! ' .. Legend .. ' (@' .. LineNo .. ')"' .. Line .. '"' - ) -end + for _, type in ipairs(TAGGED_TYPES) do + ty = ty:gsub(type, '|%1|') + end + + for _, type in ipairs(ALIAS_TYPES) do + ty = ty:gsub('^'..type..'$', 'table') --- @type string + end + + -- surround some types by () + for _, type in ipairs(TYPES) do + ty = ty + :gsub('^(' .. type .. '|nil):?$', '(%1)') + :gsub('^(' .. type .. '):?$', '(%1)') + end + + magic_split[type_index] = ty ---! \brief trim comment off end of string ---! ---! If the string has a comment on the end, this trims it off. ---! -local function TString_removeCommentFromLine(Line) - local pos_comment = string.find(Line, '%-%-') - local tailComment - if pos_comment then - Line = string.sub(Line, 1, pos_comment - 1) - tailComment = string.sub(Line, pos_comment) end - return Line, tailComment + + magic = table.concat(magic_split, ' ') + + return '/// @' .. magic end ---! \brief get directive from magic -local function getMagicDirective(Line) - local macro, tail - local macroStr = '[\\@]' - local pos_macro = string.find(Line, macroStr) - if pos_macro then - --! ....\\ macro...stuff - --! ....\@ macro...stuff - local line = string.sub(Line, pos_macro + 1) - local space = string.find(line, '%s+') - if space then - macro = string.sub(line, 1, space - 1) - tail = string_trim(string.sub(line, space + 1)) +--- @param line string +--- @param in_stream StreamRead +--- @return string +local function process_block_comment(line, in_stream) + local comment_parts = {} --- @type string[] + local done --- @type boolean? + + while not done and not in_stream:eof() do + local thisComment --- @type string? + local closeSquare = line:find(']]') + if not closeSquare then -- need to look on another line + thisComment = line .. '\n' + line = in_stream:getLine() else - macro = line - tail = '' + thisComment = line:sub(1, closeSquare - 1) + done = true + + -- unget the tail of the line + -- in most cases it's empty. This may make us less efficient but + -- easier to program + in_stream:ungetLine(vim.trim(line:sub(closeSquare + 2))) end + comment_parts[#comment_parts+1] = thisComment end - return macro, tail + + local comment = table.concat(comment_parts) + + if comment:sub(1, 1) == '@' then -- it's a long magic comment + return '/*' .. comment .. '*/ ' + end + + -- discard + return '/* zz:' .. comment .. '*/ ' end ---! \brief check comment for fn -local function checkComment4fn(Fn_magic, MagicLines) - local fn_magic = Fn_magic - -- TCore_IO_writeln('// checkComment4fn "' .. MagicLines .. '"') +--- @param line string +--- @return string +local function process_function_header(line) + local pos_fn = assert(line:find('function')) + -- we've got a function + local fn = removeCommentFromLine(vim.trim(line:sub(pos_fn + 8))) + + if fn:sub(1, 1) == '(' then + -- it's an anonymous function + return '// ZZ: '..line + end + -- fn has a name, so is interesting + + -- want to fix for iffy declarations + if fn:find('[%({]') then + -- we might have a missing close paren + if not fn:find('%)') then + fn = fn .. ' ___MissingCloseParenHere___)' + end + end - local magicLines = string_split(MagicLines, '\n') + -- Big hax + if fn:find(':') then + fn = fn:gsub(':', '.', 1) - local macro, tail + local paren_start = fn:find('(', 1, true) + local paren_finish = fn:find(')', 1, true) - for _, line in ipairs(magicLines) do - macro, tail = getMagicDirective(line) - if macro == 'fn' then - fn_magic = tail - -- TCore_IO_writeln('// found fn "' .. fn_magic .. '"') - --else - --TCore_IO_writeln('// not found fn "' .. line .. '"') + -- Nothing in between the parens + local comma --- @type string + if paren_finish == paren_start + 1 then + comma = '' + else + comma = ', ' end + + fn = fn:sub(1, paren_start) + .. 'self' + .. comma + .. fn:sub(paren_start + 1) + end + + if line:match('local') then + -- Special: tell gen_vimdoc.py this is a local function. + return 'local_function ' .. fn .. '{}' end - return fn_magic + -- add vanilla function + return 'function ' .. fn .. '{}' end -local types = { 'number', 'string', 'table', 'list', 'boolean', 'function' } - ---! \brief run the filter -function TLua2DoX_filter.readfile(this, AppStamp, Filename) - local inStream = TStream_Read() - local outStream = TStream_Write() - this.outStream = outStream -- save to this obj - - if inStream:getContents(Filename) then - -- output the file - local line - local fn_magic -- function name/def from magic comment - - outStream:writelnTail('// #######################') - outStream:writelnTail('// app run:' .. AppStamp) - outStream:writelnTail('// #######################') - outStream:writelnTail() - - local state = '' -- luacheck: ignore 231 variable is set but never accessed. - local offset = 0 - local generic = {} - local l = 0 - while not (inStream:eof()) do - line = string_trim(inStream:getLine()) - l = l + 1 - if string.sub(line, 1, 2) == '--' then -- it's a comment - -- Allow people to write style similar to EmmyLua (since they are basically the same) - -- instead of silently skipping things that start with --- - if string.sub(line, 3, 3) == '@' then -- it's a magic comment - offset = 0 - elseif string.sub(line, 1, 4) == '---@' then -- it's a magic comment - offset = 1 - end - - if string.sub(line, 3, 3) == '@' or string.sub(line, 1, 4) == '---@' then -- it's a magic comment - state = 'in_magic_comment' - local magic = string.sub(line, 4 + offset) - - local magic_split = string_split(magic, ' ') - if magic_split[1] == 'param' then - for _, type in ipairs(types) do - magic = magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. ')%)', 'param %1 %2') - magic = - magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '|nil)%)', 'param %1 %2') - end - magic_split = string_split(magic, ' ') - elseif magic_split[1] == 'return' then - for _, type in ipairs(types) do - magic = magic:gsub('^return%s+.*%((' .. type .. ')%)', 'return %1') - magic = magic:gsub('^return%s+.*%((' .. type .. '|nil)%)', 'return %1') - end - magic_split = string_split(magic, ' ') - end - - if magic_split[1] == 'generic' then - local generic_name, generic_type = line:match('@generic%s*(%w+)%s*:?%s*(.*)') - if generic_type == '' then - generic_type = 'any' - end - generic[generic_name] = generic_type - else - local type_index = 2 - if magic_split[1] == 'param' then - type_index = type_index + 1 - end - - if magic_split[type_index] then - -- fix optional parameters - if magic_split[type_index] and magic_split[2]:find('%?$') then - if not magic_split[type_index]:find('nil') then - magic_split[type_index] = magic_split[type_index] .. '|nil' - end - magic_split[2] = magic_split[2]:sub(1, -2) - end - -- replace generic types - if magic_split[type_index] then - for k, v in pairs(generic) do - magic_split[type_index] = magic_split[type_index]:gsub(k, v) - end - end - -- surround some types by () - for _, type in ipairs(types) do - magic_split[type_index] = - magic_split[type_index]:gsub('^(' .. type .. '|nil):?$', '(%1)') - magic_split[type_index] = - magic_split[type_index]:gsub('^(' .. type .. '):?$', '(%1)') - end - end - - magic = table.concat(magic_split, ' ') - - outStream:writeln('/// @' .. magic) - fn_magic = checkComment4fn(fn_magic, magic) - end - elseif string.sub(line, 3, 3) == '-' then -- it's a nonmagic doc comment - local comment = string.sub(line, 4) - outStream:writeln('/// ' .. comment) - elseif string.sub(line, 3, 4) == '[[' then -- it's a long comment - line = string.sub(line, 5) -- nibble head - local comment = '' - local closeSquare, hitend, thisComment - while not hitend and (not inStream:eof()) do - closeSquare = string.find(line, ']]') - if not closeSquare then -- need to look on another line - thisComment = line .. '\n' - line = inStream:getLine() - else - thisComment = string.sub(line, 1, closeSquare - 1) - hitend = true - - -- unget the tail of the line - -- in most cases it's empty. This may make us less efficient but - -- easier to program - inStream:ungetLine(string_trim(string.sub(line, closeSquare + 2))) - end - comment = comment .. thisComment - end - if string.sub(comment, 1, 1) == '@' then -- it's a long magic comment - outStream:write('/*' .. comment .. '*/ ') - fn_magic = checkComment4fn(fn_magic, comment) - else -- discard - outStream:write('/* zz:' .. comment .. '*/ ') - fn_magic = nil - end - -- TODO(justinmk): Uncomment this if we want "--" lines to continue the - -- preceding magic ("---", "--@", …) lines. - -- elseif state == 'in_magic_comment' then -- next line of magic comment - -- outStream:writeln('/// '.. line:sub(3)) - else -- discard - outStream:writeln('// zz:"' .. line .. '"') - fn_magic = nil - end - elseif string.find(line, '^function') or string.find(line, '^local%s+function') then - generic = {} - state = 'in_function' -- it's a function - local pos_fn = string.find(line, 'function') - -- function - -- ....v... - if pos_fn then - -- we've got a function - local fn = TString_removeCommentFromLine(string_trim(string.sub(line, pos_fn + 8))) - if fn_magic then - fn = fn_magic - end - - if string.sub(fn, 1, 1) == '(' then - -- it's an anonymous function - outStream:writelnComment(line) - else - -- fn has a name, so is interesting - - -- want to fix for iffy declarations - local open_paren = string.find(fn, '[%({]') - if open_paren then - -- we might have a missing close paren - if not string.find(fn, '%)') then - fn = fn .. ' ___MissingCloseParenHere___)' - end - end - - -- Big hax - if string.find(fn, ':') then - -- TODO: We need to add a first parameter of "SELF" here - -- local colon_place = string.find(fn, ":") - -- local name = string.sub(fn, 1, colon_place) - fn = fn:gsub(':', '.', 1) - outStream:writeln('/// @param self') - - local paren_start = string.find(fn, '(', 1, true) - local paren_finish = string.find(fn, ')', 1, true) - - -- Nothing in between the parens - local comma - if paren_finish == paren_start + 1 then - comma = '' - else - comma = ', ' - end - fn = string.sub(fn, 1, paren_start) - .. 'self' - .. comma - .. string.sub(fn, paren_start + 1) - end - - -- add vanilla function - outStream:writeln('function ' .. fn .. '{}') - end - else - this:warning(inStream:getLineNo(), 'something weird here') - end - fn_magic = nil -- mustn't inadvertently use it again - - -- TODO: If we can make this learn how to generate these, that would be helpful. - -- elseif string.find(line, "^M%['.*'%] = function") then - -- state = 'in_function' -- it's a function - -- outStream:writeln("function textDocument/publishDiagnostics(...){}") - - -- fn_magic = nil -- mustn't inadvertently use it again - else - state = '' -- unknown - if #line > 0 then -- we don't know what this line means, so just comment it out - outStream:writeln('// zz: ' .. line) - else - outStream:writeln() -- keep this line blank - end - end +--- @param line string +--- @param in_stream StreamRead +--- @param generics table<string,string>> +--- @return string? +local function process_line(line, in_stream, generics) + local line_raw = line + line = vim.trim(line) + + if vim.startswith(line, '---') then + return process_magic(line:sub(4), generics) + end + + if vim.startswith(line, '--'..'[[') then -- it's a long comment + return process_block_comment(line:sub(5), in_stream) + end + + -- Hax... I'm sorry + -- M.fun = vim.memoize(function(...) + -- -> + -- function M.fun(...) + line = line:gsub('^(.+) = .*_memoize%([^,]+, function%((.*)%)$', 'function %1(%2)') + + if line:find('^function') or line:find('^local%s+function') then + return process_function_header(line) + end + + if not line:match('^local') then + local v = line_raw:match('^([A-Za-z][.a-zA-Z_]*)%s+%=') + if v and v:match('%.') then + -- Special: this lets gen_vimdoc.py handle tables. + return 'table '..v..'() {}' end + end - -- output the tail - outStream:write_tailLines() - else - outStream:writeln('!empty file') + if #line > 0 then -- we don't know what this line means, so just comment it out + return '// zz: ' .. line end + + return '' end ---! \brief this application -local TApp = class() +-- Processes the file and writes filtered output to stdout. +---@param filename string +function Lua2DoxFilter:filter(filename) + local in_stream = StreamRead.new(filename) ---! \brief constructor -function TApp.init(this) - this.timestamp = os.date('%c %Z', os.time()) - this.name = 'Lua2DoX' - this.version = '0.2 20130128' - this.copyright = 'Copyright (c) Simon Dales 2012-13' -end + local generics = {} --- @type table<string,string> -function TApp.getRunStamp(this) - return this.name .. ' (' .. this.version .. ') ' .. this.timestamp -end + while not in_stream:eof() do + local line = in_stream:getLine() + + local out_line = process_line(line, in_stream, generics) + + if not vim.startswith(vim.trim(line), '---') then + generics = {} + end -function TApp.getVersion(this) - return this.name .. ' (' .. this.version .. ') ' + if out_line then + writeln(out_line) + end + end end -function TApp.getCopyright(this) - return this.copyright +--- @class TApp +--- @field timestamp string|osdate +--- @field name string +--- @field version string +--- @field copyright string +--- this application +local TApp = { + timestamp = os.date('%c %Z', os.time()), + name = 'Lua2DoX', + version = '0.2 20130128', + copyright = 'Copyright (c) Simon Dales 2012-13' +} + +setmetatable(TApp, { __index = TApp }) + +function TApp:getRunStamp() + return self.name .. ' (' .. self.version .. ') ' .. self.timestamp end -local This_app = TApp() +function TApp:getVersion() + return self.name .. ' (' .. self.version .. ') ' +end --main -local argv1 = arg[1] -if argv1 == '--help' then - TCore_IO_writeln(This_app:getVersion()) - TCore_IO_writeln(This_app:getCopyright()) - TCore_IO_writeln([[ +if arg[1] == '--help' then + writeln(TApp:getVersion()) + writeln(TApp.copyright) + writeln([[ run as: nvim -l scripts/lua2dox.lua <param> -------------- @@ -540,16 +444,32 @@ if argv1 == '--help' then <filename> : interprets filename --version : show version/copyright info --help : this help text]]) -elseif argv1 == '--version' then - TCore_IO_writeln(This_app:getVersion()) - TCore_IO_writeln(This_app:getCopyright()) -else - -- it's a filter - local appStamp = This_app:getRunStamp() - local filename = argv1 - - local filter = TLua2DoX_filter() - filter:readfile(appStamp, filename) -end +elseif arg[1] == '--version' then + writeln(TApp:getVersion()) + writeln(TApp.copyright) +else -- It's a filter. + local filename = arg[1] + + if arg[2] == '--outdir' then + local outdir = arg[3] + if type(outdir) ~= 'string' or (0 ~= vim.fn.filereadable(outdir) and 0 == vim.fn.isdirectory(outdir)) then + error(('invalid --outdir: "%s"'):format(tostring(outdir))) + end + vim.fn.mkdir(outdir, 'p') + debug_outfile = string.format('%s/%s.c', outdir, vim.fs.basename(filename)) + end + + Lua2DoxFilter:filter(filename) + + -- output the tail + writeln('// #######################') + writeln('// app run:' .. TApp:getRunStamp()) + writeln('// #######################') + writeln() ---eof + if debug_outfile then + local f = assert(io.open(debug_outfile, 'w')) + f:write(table.concat(debug_output)) + f:close() + end +end |