mirror of
https://github.com/neovim/neovim.git
synced 2024-12-29 14:41:06 -07:00
refactor(lua2dox): overhaul (#24386)
This commit is contained in:
parent
e4da418ba8
commit
9fcb0a64ee
@ -674,7 +674,7 @@ vim.regex:match_str({str}) *regex:match_str()*
|
||||
match is returned. When there is no match, `nil` is returned. As any integer is truth-y, `regex:match()` can be directly used as a condition in an if-statement.
|
||||
|
||||
Parameters: ~
|
||||
• {str} (string)
|
||||
• {str} (string)
|
||||
|
||||
|
||||
==============================================================================
|
||||
@ -1988,13 +1988,13 @@ vim.Ringbuf:peek() *Ringbuf:peek()*
|
||||
Returns the first unread item without removing it
|
||||
|
||||
Return: ~
|
||||
any?|ni
|
||||
any?|nil
|
||||
|
||||
vim.Ringbuf:pop() *Ringbuf:pop()*
|
||||
Removes and returns the first unread item
|
||||
|
||||
Return: ~
|
||||
any?|ni
|
||||
any?|nil
|
||||
|
||||
vim.Ringbuf:push({item}) *Ringbuf:push()*
|
||||
Adds an item, overriding the oldest item if the buffer is full.
|
||||
@ -3044,7 +3044,7 @@ vim.version.last({versions}) *vim.version.last()*
|
||||
• {versions} Version []
|
||||
|
||||
Return: ~
|
||||
Version ?|ni
|
||||
Version ?|nil
|
||||
|
||||
vim.version.lt({v1}, {v2}) *vim.version.lt()*
|
||||
Returns `true` if `v1 < v2` . See |vim.version.cmp()| for usage.
|
||||
|
@ -1035,7 +1035,7 @@ set({lang}, {query_name}, {text}) *vim.treesitter.query.set()*
|
||||
Lua module: vim.treesitter.highlighter *lua-treesitter-highlighter*
|
||||
|
||||
TSHighlighter:destroy() *TSHighlighter:destroy()*
|
||||
Removes all internal references to the highlighter
|
||||
Removes all internal references to the highlighter.
|
||||
|
||||
|
||||
==============================================================================
|
||||
@ -1100,7 +1100,8 @@ LanguageTree:destroy() *LanguageTree:destroy()*
|
||||
|
||||
Any cleanup logic should be performed here.
|
||||
|
||||
Note: This DOES NOT remove this tree from a parent. Instead, `remove_child` must be called on the parent to remove it.
|
||||
Note: This DOES NOT remove this tree from a parent. Instead,
|
||||
`remove_child` must be called on the parent to remove it.
|
||||
|
||||
*LanguageTree:for_each_child()*
|
||||
LanguageTree:for_each_child({fn}, {include_self})
|
||||
@ -1117,7 +1118,7 @@ LanguageTree:for_each_tree({fn}) *LanguageTree:for_each_tree()*
|
||||
Note: This includes the invoking tree's child trees as well.
|
||||
|
||||
Parameters: ~
|
||||
• {fn} fun(tree: TSTree, ltree: LanguageTree)
|
||||
• {fn} fun(tree: TSTree, ltree: LanguageTree)
|
||||
|
||||
LanguageTree:included_regions() *LanguageTree:included_regions()*
|
||||
Gets the set of included regions
|
||||
|
@ -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
|
||||
@ -48,536 +48,364 @@ 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 _debug_outfile = nil
|
||||
local _debug_output = {}
|
||||
local TYPES = { 'integer', 'number', 'string', 'table', 'list', 'boolean', 'function' }
|
||||
|
||||
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
|
||||
local TAGGED_TYPES = { 'TSNode', 'LanguageTree' }
|
||||
|
||||
-- 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
|
||||
-- Document these as 'table'
|
||||
local ALIAS_TYPES = { 'Range', 'Range4', 'Range6', 'TSMetadata' }
|
||||
|
||||
-- write to stdout
|
||||
local function TCore_IO_write(Str)
|
||||
if Str then
|
||||
io.write(Str)
|
||||
if _debug_outfile then
|
||||
table.insert(_debug_output, Str)
|
||||
end
|
||||
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
|
||||
|
||||
io.write(str)
|
||||
if debug_outfile then
|
||||
table.insert(debug_output, str)
|
||||
end
|
||||
end
|
||||
|
||||
-- write to stdout
|
||||
local function TCore_IO_writeln(Str)
|
||||
TCore_IO_write(Str)
|
||||
TCore_IO_write('\n')
|
||||
--- write to stdout
|
||||
--- @param str? string
|
||||
local function writeln(str)
|
||||
write(str)
|
||||
write('\n')
|
||||
end
|
||||
|
||||
-- trims a string
|
||||
local function string_trim(Str)
|
||||
return Str:match('^%s*(.-)%s*$')
|
||||
end
|
||||
--- an input file buffer
|
||||
--- @class StreamRead
|
||||
--- @field currentLine string?
|
||||
--- @field contentsLen integer
|
||||
--- @field currentLineNo integer
|
||||
--- @field filecontents string[]
|
||||
local StreamRead = {}
|
||||
|
||||
-- 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)
|
||||
end
|
||||
return splitStr
|
||||
end
|
||||
|
||||
-------------------------------
|
||||
-- file buffer
|
||||
--!
|
||||
--! an input file buffer
|
||||
local TStream_Read = class()
|
||||
|
||||
-- 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))
|
||||
--- @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 = {}
|
||||
for line in io.lines(Filename) do
|
||||
table.insert(filecontents, line)
|
||||
local filecontents = {} --- @type string[]
|
||||
for line in io.lines(filename) do
|
||||
filecontents[#filecontents+1] = line
|
||||
end
|
||||
|
||||
if filecontents then
|
||||
this.filecontents = filecontents
|
||||
this.contentsLen = #filecontents
|
||||
this.currentLineNo = 1
|
||||
end
|
||||
|
||||
return filecontents
|
||||
end
|
||||
|
||||
-- get lineno
|
||||
function TStream_Read.getLineNo(this)
|
||||
return this.currentLineNo
|
||||
return setmetatable({
|
||||
filecontents = filecontents,
|
||||
contentsLen = #filecontents,
|
||||
currentLineNo = 1,
|
||||
}, { __index = StreamRead })
|
||||
end
|
||||
|
||||
-- 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
|
||||
function StreamRead:getLine()
|
||||
if self.currentLine then
|
||||
self.currentLine = nil
|
||||
return self.currentLine
|
||||
end
|
||||
return line
|
||||
|
||||
-- get line
|
||||
if self.currentLineNo <= self.contentsLen then
|
||||
local line = self.filecontents[self.currentLineNo]
|
||||
self.currentLineNo = self.currentLineNo + 1
|
||||
return line
|
||||
end
|
||||
|
||||
return ''
|
||||
end
|
||||
|
||||
-- save line fragment
|
||||
function TStream_Read.ungetLine(this, LineFrag)
|
||||
this.currentLine = LineFrag
|
||||
--- @param line_fragment string
|
||||
function StreamRead:ungetLine(line_fragment)
|
||||
self.currentLine = line_fragment
|
||||
end
|
||||
|
||||
-- is it eof?
|
||||
function TStream_Read.eof(this)
|
||||
if this.currentLine or this.currentLineNo <= this.contentsLen then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- output stream
|
||||
local TStream_Write = class()
|
||||
|
||||
-- constructor
|
||||
function TStream_Write.init(this)
|
||||
this.tailLine = {}
|
||||
end
|
||||
|
||||
-- write immediately
|
||||
function TStream_Write.write(_, Str)
|
||||
TCore_IO_write(Str)
|
||||
end
|
||||
|
||||
-- write immediately
|
||||
function TStream_Write.writeln(_, Str)
|
||||
TCore_IO_writeln(Str)
|
||||
end
|
||||
|
||||
-- write immediately
|
||||
function TStream_Write.writelnComment(_, Str)
|
||||
TCore_IO_write('// ZZ: ')
|
||||
TCore_IO_writeln(Str)
|
||||
end
|
||||
|
||||
-- write to tail
|
||||
function TStream_Write.writelnTail(this, Line)
|
||||
if not Line then
|
||||
Line = ''
|
||||
end
|
||||
table.insert(this.tailLine, Line)
|
||||
end
|
||||
|
||||
-- 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')
|
||||
function StreamRead:eof()
|
||||
return not self.currentLine and self.currentLineNo > self.contentsLen
|
||||
end
|
||||
|
||||
-- input filter
|
||||
local TLua2DoX_filter = class()
|
||||
--- @class Lua2DoxFilter
|
||||
local Lua2DoxFilter = {}
|
||||
setmetatable(Lua2DoxFilter, { __index = Lua2DoxFilter })
|
||||
|
||||
-- allow us to do errormessages
|
||||
function TLua2DoX_filter.warning(this, Line, LineNo, Legend)
|
||||
this.outStream:writelnTail(
|
||||
'//! \todo warning! ' .. Legend .. ' (@' .. LineNo .. ')"' .. Line .. '"'
|
||||
)
|
||||
end
|
||||
|
||||
-- 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)
|
||||
--- 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, tailComment
|
||||
return line:sub(1, pos_comment - 1), line:sub(pos_comment)
|
||||
end
|
||||
|
||||
-- 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 generics table<string,string>
|
||||
--- @return string?
|
||||
local function process_magic(line, generics)
|
||||
line = line:gsub('^%s+@', '@')
|
||||
line = line:gsub('@package', '@private')
|
||||
|
||||
if not vim.startswith(line, '@') then -- it's a magic comment
|
||||
return '/// ' .. line
|
||||
end
|
||||
|
||||
local magic = line:sub(2)
|
||||
local magic_split = vim.split(magic, ' ', { plain = true })
|
||||
local directive = magic_split[1]
|
||||
|
||||
if vim.list_contains({
|
||||
'cast', 'diagnostic', 'overload', 'meta', 'type'
|
||||
}, directive) then
|
||||
-- Ignore LSP directives
|
||||
return '// gg:"' .. line .. '"'
|
||||
end
|
||||
|
||||
if directive == 'defgroup' or directive == 'addtogroup' then
|
||||
-- Can't use '.' in defgroup, so convert to '--'
|
||||
return '/// @' .. magic:gsub('%.', '-dot-')
|
||||
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
|
||||
|
||||
local type_index = 2
|
||||
|
||||
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
|
||||
-- handle the return of vim.spell.check
|
||||
magic = magic:gsub('({.*}%[%])', '`%1`')
|
||||
magic_split = vim.split(magic, ' ', { plain = true })
|
||||
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
|
||||
|
||||
-- replace generic types
|
||||
for k, v in pairs(generics) do
|
||||
ty = ty:gsub(k, v) --- @type string
|
||||
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
|
||||
|
||||
end
|
||||
|
||||
magic = table.concat(magic_split, ' ')
|
||||
|
||||
return '/// @' .. magic
|
||||
end
|
||||
|
||||
--- @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
|
||||
|
||||
-- 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)))
|
||||
|
||||
local magicLines = string_split(MagicLines, '\n')
|
||||
if fn:sub(1, 1) == '(' then
|
||||
-- it's an anonymous function
|
||||
return '// ZZ: '..line
|
||||
end
|
||||
-- fn has a name, so is interesting
|
||||
|
||||
local macro, tail
|
||||
|
||||
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 .. '"')
|
||||
-- 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
|
||||
|
||||
return fn_magic
|
||||
-- Big hax
|
||||
if fn:find(':') then
|
||||
fn = fn:gsub(':', '.', 1)
|
||||
|
||||
local paren_start = fn:find('(', 1, true)
|
||||
local paren_finish = fn:find(')', 1, true)
|
||||
|
||||
-- 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
|
||||
|
||||
-- add vanilla function
|
||||
return 'function ' .. fn .. '{}'
|
||||
end
|
||||
|
||||
local types = { 'integer', 'number', 'string', 'table', 'list', 'boolean', 'function' }
|
||||
--- @param line string
|
||||
--- @param in_stream StreamRead
|
||||
--- @param generics table<string,string>>
|
||||
--- @return string?
|
||||
local function process_line(line, in_stream, generics)
|
||||
if vim.startswith(line, '---') then
|
||||
return process_magic(line:sub(4), generics)
|
||||
end
|
||||
|
||||
local tagged_types = { 'TSNode', 'LanguageTree' }
|
||||
if vim.startswith(line, '--'..'[[') then -- it's a long comment
|
||||
return process_block_comment(line:sub(5), in_stream)
|
||||
end
|
||||
|
||||
-- Document these as 'table'
|
||||
local alias_types = { 'Range', 'Range4', 'Range6', 'TSMetadata' }
|
||||
if line:find('^function') or line:find('^local%s+function') then
|
||||
return process_function_header(line)
|
||||
end
|
||||
|
||||
if #line > 0 then -- we don't know what this line means, so just comment it out
|
||||
return '// zz: ' .. line
|
||||
end
|
||||
|
||||
return ''
|
||||
end
|
||||
|
||||
-- Processes the file and writes filtered output to stdout.
|
||||
function TLua2DoX_filter.filter(this, AppStamp, Filename)
|
||||
local inStream = TStream_Read()
|
||||
local outStream = TStream_Write()
|
||||
this.outStream = outStream -- save to this obj
|
||||
---@param filename string
|
||||
function Lua2DoxFilter:filter(filename)
|
||||
local in_stream = StreamRead.new(filename)
|
||||
|
||||
if inStream:getContents(Filename) then
|
||||
-- output the file
|
||||
local line
|
||||
local fn_magic -- function name/def from magic comment
|
||||
local generics = {} --- @type table<string,string>
|
||||
|
||||
outStream:writelnTail('// #######################')
|
||||
outStream:writelnTail('// app run:' .. AppStamp)
|
||||
outStream:writelnTail('// #######################')
|
||||
outStream:writelnTail()
|
||||
while not in_stream:eof() do
|
||||
local line = vim.trim(in_stream:getLine())
|
||||
|
||||
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
|
||||
line = line:gsub('^---%s+@', '---@')
|
||||
-- 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
|
||||
local out_line = process_line(line, in_stream, generics)
|
||||
|
||||
line = line:gsub('@package', '@private')
|
||||
|
||||
if vim.startswith(line, '---@cast')
|
||||
or vim.startswith(line, '---@diagnostic')
|
||||
or vim.startswith(line, '---@overload')
|
||||
or vim.startswith(line, '---@meta')
|
||||
or vim.startswith(line, '---@type') then
|
||||
-- Ignore LSP directives
|
||||
outStream:writeln('// gg:"' .. line .. '"')
|
||||
elseif 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
|
||||
-- handle the return of vim.spell.check
|
||||
magic = magic:gsub('({.*}%[%])', '`%1`')
|
||||
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
|
||||
|
||||
for _, type in ipairs(tagged_types) do
|
||||
magic_split[type_index] =
|
||||
magic_split[type_index]:gsub(type, '|%1|')
|
||||
end
|
||||
|
||||
for _, type in ipairs(alias_types) do
|
||||
magic_split[type_index] =
|
||||
magic_split[type_index]:gsub('^'..type..'$', 'table')
|
||||
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, ' ')
|
||||
|
||||
if magic_split[1] == 'defgroup' or magic_split[1] == 'addtogroup' then
|
||||
-- Can't use '.' in defgroup, so convert to '--'
|
||||
magic = magic:gsub('%.', '-dot-')
|
||||
end
|
||||
|
||||
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
|
||||
if not vim.startswith(line, '---') then
|
||||
generics = {}
|
||||
end
|
||||
|
||||
-- output the tail
|
||||
outStream:write_tailLines()
|
||||
else
|
||||
outStream:writeln('!empty file')
|
||||
if out_line then
|
||||
writeln(out_line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- this application
|
||||
local TApp = class()
|
||||
--- @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'
|
||||
}
|
||||
|
||||
-- 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'
|
||||
setmetatable(TApp, { __index = TApp })
|
||||
|
||||
function TApp:getRunStamp()
|
||||
return self.name .. ' (' .. self.version .. ') ' .. self.timestamp
|
||||
end
|
||||
|
||||
function TApp.getRunStamp(this)
|
||||
return this.name .. ' (' .. this.version .. ') ' .. this.timestamp
|
||||
function TApp:getVersion()
|
||||
return self.name .. ' (' .. self.version .. ') '
|
||||
end
|
||||
|
||||
function TApp.getVersion(this)
|
||||
return this.name .. ' (' .. this.version .. ') '
|
||||
end
|
||||
|
||||
function TApp.getCopyright(this)
|
||||
return this.copyright
|
||||
end
|
||||
|
||||
local This_app = TApp()
|
||||
|
||||
--main
|
||||
|
||||
if arg[1] == '--help' then
|
||||
TCore_IO_writeln(This_app:getVersion())
|
||||
TCore_IO_writeln(This_app:getCopyright())
|
||||
TCore_IO_writeln([[
|
||||
writeln(TApp:getVersion())
|
||||
writeln(TApp.copyright)
|
||||
writeln([[
|
||||
run as:
|
||||
nvim -l scripts/lua2dox.lua <param>
|
||||
--------------
|
||||
@ -586,8 +414,8 @@ if arg[1] == '--help' then
|
||||
--version : show version/copyright info
|
||||
--help : this help text]])
|
||||
elseif arg[1] == '--version' then
|
||||
TCore_IO_writeln(This_app:getVersion())
|
||||
TCore_IO_writeln(This_app:getCopyright())
|
||||
writeln(TApp:getVersion())
|
||||
writeln(TApp.copyright)
|
||||
else -- It's a filter.
|
||||
local filename = arg[1]
|
||||
|
||||
@ -597,18 +425,20 @@ else -- It's a filter.
|
||||
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))
|
||||
debug_outfile = string.format('%s/%s.c', outdir, vim.fs.basename(filename))
|
||||
end
|
||||
|
||||
local appStamp = This_app:getRunStamp()
|
||||
local filter = TLua2DoX_filter()
|
||||
filter:filter(appStamp, filename)
|
||||
Lua2DoxFilter:filter(filename)
|
||||
|
||||
if _debug_outfile then
|
||||
local f = assert(io.open(_debug_outfile, 'w'))
|
||||
f:write(table.concat(_debug_output))
|
||||
-- output the tail
|
||||
writeln('// #######################')
|
||||
writeln('// app run:' .. TApp:getRunStamp())
|
||||
writeln('// #######################')
|
||||
writeln()
|
||||
|
||||
if debug_outfile then
|
||||
local f = assert(io.open(debug_outfile, 'w'))
|
||||
f:write(table.concat(debug_output))
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
--eof
|
||||
|
Loading…
Reference in New Issue
Block a user