diff options
| author | Alexander Pickering <alex@cogarr.net> | 2020-07-05 17:18:56 -0400 |
|---|---|---|
| committer | Alexander Pickering <alex@cogarr.net> | 2020-07-05 17:18:56 -0400 |
| commit | e87b06ee0fe2a588b72a356bbb8378899365d626 (patch) | |
| tree | 0d0acd945a70644835e8958425e6d5e6c10196a6 /init.lua | |
| parent | d2ba262c5307aa14c325ef53d8e4e56a5ece0376 (diff) | |
| download | mdoc-e87b06ee0fe2a588b72a356bbb8378899365d626.tar.gz mdoc-e87b06ee0fe2a588b72a356bbb8378899365d626.tar.bz2 mdoc-e87b06ee0fe2a588b72a356bbb8378899365d626.zip | |
Add rockspec
Add a rockspec and move the files around so that luarocks can
install it correctly
Diffstat (limited to 'init.lua')
| -rw-r--r-- | init.lua | 572 |
1 files changed, 0 insertions, 572 deletions
diff --git a/init.lua b/init.lua deleted file mode 100644 index a3515ed..0000000 --- a/init.lua +++ /dev/null @@ -1,572 +0,0 @@ ---[[
-Mdoc creats documentation from comments in source files.
-Mdoc works in several steps:
- 1. Create "chunks" from input source files
- 2. Create a dependnecy graph, so we only update the things that
- need updating
- 3. Output html documentation
-]]
-local lpeg = require("lpeg")
-local lfs = require("lfs")
-local et = require("etlua")
-require("ext")
-local opt = require("opt_parser")
-
-local args = {...}
-local options = opt.parse_options(args)
-if options.help then
- print(opt.help())
- return
-end
-print("options:",options)
-
-local state = {
- title = "",
- sections = {},
- files = {},
- documents = {},
- known_names = {},
- index = {},
-}
-
-local function log(...)
- if options.verbose then
- print(...)
- end
-end
-local function logf(...)
- if options.verbose then
- printf(...)
- end
-end
-
-local toskip = {["."] = true,[".."] = true}
-local function scan(path,callback)
- assert(path,"Cannot scan without a path to scan (was nil)")
- assert(callback,"Cannot scan without a callback to call (was nil)")
- for item in lfs.dir(path) do
- log("looking at:",item)
- if toskip[item] then
- goto nextitem
- end
- local fullpath = path .. "/" .. item
- local attributes = lfs.attributes(fullpath)
- if attributes.mode == "directory" or attributes.mode == "link" then
- log("found directory:",directory)
- scan(fullpath,callback)
- elseif attributes.mode == "file" then
- log("found item:",item)
- callback(fullpath)
- end
- ::nextitem::
- end
-end
-for _,path in pairs(options.paths) do
- scan(path,function(p)
- local attributes = lfs.attributes(p)
- table.insert(state.files,{
- path = p,
- relpath = p:match(string.format("%s/(.*)",path)),
- lastmod = attributes.modification,
- })
- end)
-end
-logf("Found %d files.",#state.files)
-
-for _,path in pairs(options.document_paths) do
- scan(path,function(p)
- local attributes = lfs.attributes(p)
- table.insert(state.documents,{
- path = p,
- lastmod = attributes.modification,
- })
- end)
-end
-logf("Found %d documents.",#state.documents)
-
-
-local function parse(text,filename)
- assert(options.parser,"Failed to find a parser option")
- assert(text,"Failed to get text")
- text = text:gsub("@{(.+)}",function(data)
- return string.format("[%s](%s.html)",data,data)
- end)
- log("Using parser:",options.parser)
- local tmp = options.output .. "/" .. os.tmpname()
- log("using temp name:",tmp)
- local pd = io.popen(options.parser .. " > " .. tmp,"w")
- pd:write(text)
- pd:close()
- local id = assert(io.open(tmp,"r"))
- local ret = id:read("*a")
- id:close()
- assert(os.remove(tmp))
- return ret
-end
-
-local function table_to_string(tbl)
- --Collect all of our tables first,
- --so that we don't break when we have recursive tables.
- local tables = {}
- local table_order = {}
- local function tables_helper(t)
- tables[t] = #table_order + 1
- table_order[#table_order + 1] = t
- for k,v in pairs(t) do
- if type(k) == "table" and not tables[k] then
- tables_helper(k)
- end
- if type(v) == "table" and not tables[v] then
- tables_helper(v)
- end
- end
- end
- tables_helper(tbl)
-
- --Get the string representation of an element
- local errfun = function(e) error("Cannot format a " .. type(e)) end
- local rep_map = {
- --things we can format
- number = function(e)
- if e % 1 == 0 then return string.format("%d",e)
- else return string.format("%f",e) end
- end,
- string = function(e) return string.format("%q",e) end,
- boolean = function(e) return e and "true" or "false" end,
- table = function(e)
- assertf(tables[e] ~= nil,"Could not find dependency table %s",tostring(e))
- return string.format("table_%d",tables[e])
- end,
- --things we can't format
- ["function"] = errfun,
- coroutine = errfun,
- file = errfun,
- userdata = errfun,
- --nil can never happen
- }
- local sb = {}
- --Create all the variables first, so that recursive tables will work
- for n,_ in pairs(table_order) do
- sb[#sb + 1] = string.format("local table_%d = {}",n)
- end
- --Go backwards through tables, since that should be the
- --"dependency" order
- for i = #table_order, 1, -1 do -- -1 is needed in case #table_order == 0
- local tstr = {}
- local this_table = table_order[i]
- for k,v in pairs(this_table) do
- tstr[#tstr + 1] = string.format("table_%d[%s] = %s",i,rep_map[type(k)](k), rep_map[type(v)](v))
- end
- sb[#sb + 1] = table.concat(tstr,"\n")
- end
- sb[#sb + 1] = "return table_1"
- return table.concat(sb,"\n\n");
-end
-
---io.open automatically creates parent directories
-local oldopen = io.open
-function io.open(path,mode)
- if mode == "w" or mode == "w+" then
- local path_so_far = ""
- for folder in path:gmatch("([^/]+)/") do
- path_so_far = path_so_far .. folder .. "/"
- if lfs.attributes(path_so_far) == nil then
- lfs.mkdir(path_so_far)
- end
- end
- end
- return oldopen(path,mode)
-end
-
---Create a cache directory
-if not lfs.attributes(options.output .. "/cache") then
- assert(lfs.mkdir(options.output .. "/cache"))
- assert(lfs.mkdir(options.output .. "/cache/documents"))
- assert(lfs.mkdir(options.output .. "/cache/files"))
- assert(lfs.mkdir(options.output .. "/cache/chunks"))
-end
-
---Get the data for the reference documents
-for dn, data in pairs(state.documents) do
- local file_name = data.path:match(".*/([^.]+)%.[^.]+$")
- local cachefile = string.format("%s/cache/documents/%s",options.output,file_name)
- local out_attrs = lfs.attributes(cachefile)
- if not out_attrs or out_attrs.modification < data.lastmod then
- --we're out of date, update
- local fd = assert(io.open(data.path,"r"))
- local file_text = fd:read("*a")
- fd:close()
- local parsed_text = parse(file_text, data.path)
- local od = assert(io.open(cachefile,"w"))
- od:write(parsed_text)
- od:close()
- state.sections[file_name] = {
- type = "reference",
- data_file = cachefile
- }
- end
-end
-
---Openers and closers
-local parse_between = {
- ["/***"] = "*/",
- ["--[[**"] = "]]"
-}
-for _,file in pairs(state.files) do
- local cachefilename = string.format("%s/cache/files/%s",options.output,file.relpath)
- local cacheattrs = lfs.attributes(cachefilename)
- if (not cacheattrs) or cacheattrs.modification < file.lastmod then
- local chunks = {}
- local in_chunk = false
- local line_num = 0
- local closer
- local fd = assert(io.open(file.path,"r"))
- for line in fd:lines() do
- line_num = line_num + 1
- if parse_between[line] then
- closer = parse_between[line]
- table.insert(chunks,{})
- in_chunk = true
- end
- if in_chunk then
- table.insert(chunks[#chunks],line)
- end
- if in_chunk and line == closer then
- log("found end, chunks:",chunks)
- chunks[#chunks] = {
- text = chunks[#chunks],
- file = file.path,
- line = line_num,
- relpath = file.relpath,
- }
- in_chunk = false
- end
- end
- file.chunks = chunks
- local cachefile = assert(io.open(cachefilename,"w"))
- cachefile:write(table_to_string(chunks))
- cachefile:close()
- else
- file.chunks = loadfile(cachefilename)()
- end
-end
-
-for _,file in pairs(state.files) do
- local function process_chunk(chunk)
- assert(chunk.file and chunk.line, "Chunk without file or line num:")
- local section = nil
- local partname = nil
- local sectiontype = nil
- local short_desc
- local desc = {}
- --Parameters are {
- -- name = "string",
- -- type = "string",
- -- optional = bool
- -- optchain = bool
- -- default = nil | "string"
- --}
- local ret = {}
- for num,line in pairs(chunk.text) do
- if num == 2 then
- if line:match("^@.*") then
- short_desc = "no short description provided"
- else
- short_desc = line
- end
- end
- if num > 2 and type(desc) == "table" and not line:match("^@.*") then
- table.insert(desc,line)
- end
- if line:match("^@") then
- local command, rest = line:match("^@([^ ]+) (.*)")
- if command == "function" then
- sectiontype = "function"
- if rest:find(":") then
- local classname, functionname = rest:match("^([^:]+):([^%(]+)")
- ret = {
- --state.sections[classname] = state.sections[classname] or {type = "class"}
- --state.sections[classname][functionname] = state.sections[classname][functionname] or {
- type="method",
- name = functionname,
- path = {classname,functionname},
- short_desc = parse(short_desc),
- line = chunk.line,
- desc = parse(table.concat(desc,"\n")),
- params = {},
- returns = {},
- file = chunk.relpath
- }
- section = classname
- partname = functionname
- else
- local namespace, functionname
- local c = rest:match("^([^.%(]+)%(")
- if c then
- namespace = "_G"
- functionname = c
- else
- namespace, functionname = rest:match("([^.]+)%.([^%(]+)")
- end
- log("namespace:",namespace,"functionname:",functionname)
- ret = {
- --state.sections[namespace] = state.sections[namespace] or {type = "namespace"}
- --state.sections[namespace][functionname] = state.sections[namespace][functionname] or {
- type="function",
- name = functionname,
- short_desc = parse(short_desc),
- path = {namespace,functionname},
- line = chunk.line,
- desc = parse(table.concat(desc,"\n")),
- params = {},
- returns = {},
- references = {},
- file = chunk.relpath
- }
- section = namespace
- partname = functionname
- end
- elseif command == "tparam" or command == "tparam?" then
- local parts = {}
- local vartype, name, description
- for word in rest:gmatch("([^ ]+)") do table.insert(parts,word) end
- assertf(#parts >= 2,"@tparam at %s:%d requires at least a type and a variable name",chunk.file,chunk.line_num)
- if parts[1] then
- vartype = parts[1]
- table.remove(parts,1)
- end
- if parts[1] then
- name = parts[1]
- table.remove(parts,1)
- end
- description = table.concat(parts,"\n")
-
- assertf(section and partname and sectiontype == "function","Tried to specify a tparam for something that wasn't a function at %s:%d",chunk.file,chunk.line)
- local param = {
- type = vartype,
- name = name,
- description = parse(description),
- optional = command == "tparam?"
- }
- table.insert(ret.params,param)
- --table.insert(state.sections[section][partname].params,param)
- elseif command == "treturn" then
- local vartype, description = rest:match("([^ ]+) (.*)")
- assertf(section and partname and sectiontype == "function","Tried to specify a treturn for something that wasn't a function at %s:%d",chunk.file,chunk.line)
- local tret = {
- type = vartype,
- description = description and parse(description)
- }
- table.insert(ret.returns,tret)
- --table.insert(state.sections[section][partname].returns,{
- --type = vartype,
- --description = description and parse(description)
- --})
- elseif command == "field" then
- local namespace, field, value
- local c,v = rest:match("^([^ ]+) ([^ ]+)$")
- if c then
- namespace = "_G"
- field = c
- value = v
- else
- namespace, field, value = rest:match("([^.]+).([^ ]+) ?(.*)")
- end
- assertf(namespace and field and value, "Improperly defined @field at %s:%d, should be '@field module.field Description here'",chunk.file,chunk.line)
- section = namespace
- partname = field
- state.sections[namespace] = state.sections[namespace] or {type="namespace"}
- assertf(not state.sections[namespace][field],"2 or more definitions for %s.%s",namespace,field)
- ret = {
- --state.sections[namespace][field] = {
- type = "field",
- name = field,
- path = {namespace,field},
- short_desc = parse(short_desc),
- desc = desc and parse(table.concat(desc,"\n")),
- line = chunk.line,
- file = chunk.relpath
- }
- elseif command == "class" then
- local classname = rest
- section = classname
- ret = {
- --state.sections[classname] = state.sections[classname] or {
- type = "class",
- name = classname,
- short_desc = parse(short_desc),
- desc = parse(table.concat(desc,"\n")),
- path = {classname}
- }
- partname = nil
- elseif command == "inherits" then
- assertf(ret and ret.type == "class","Don't know what is using @inherits at %s:%d, add a @class definition above it",chunk.file,chunk.line)
- ret.inherits = ret.inherits or {}
- table.insert(ret.inherits,rest)
- --state.sections[section].inherits = state.sections[section].inherits or {}
- --table.insert(state.sections[section].inherits,rest)
- else
- assertf(ret and ret.path[1] ,"Don't know where to put @%s, add a @function, @field or @table marker before it.",command)
- if partname then
- assertf(ret.path[2] ,"Don't know where to put @%s, add a @function, @field, or @table marker before it")
- ret[command] = rest
- --state.sections[section][partname][command] = rest
- else
- ret[command] = rest
- --state.sections[section][command] = rest
- end
- end
- end
- end
- return ret
- end
- local cachefilename = string.format("%s/cache/chunks/%s",options.output,file.relpath)
- local cachefileattrs = lfs.attributes(cachefilename)
- if (not cachefileattrs) or cachefileattrs.modification < file.lastmod then
- for k,v in pairs(file.chunks) do
- file.chunks[k] = process_chunk(v)
- end
- local cachefile = assert(io.open(cachefilename,"w"))
- cachefile:write(table_to_string(file.chunks))
- cachefile:close()
- else
- file.chunks = loadfile(cachefilename)()
- end
-end
-
-for _,file in pairs(state.files) do
- for _, chunk in pairs(file.chunks) do
- assertf(chunk.path, "Chunk at %s:%d didn't have a path.", file.name, chunk.line)
- local cursor = state.sections
- for _, path_part in pairs(chunk.path) do
- if not cursor[path_part] then
- cursor[path_part] = {}
- end
- cursor = cursor[path_part]
- end
- for k,v in pairs(chunk) do
- cursor[k] = v
- end
- end
-end
-
---Get the data for the reference documents
-if options.index ~= nil then
- local file_mod = lfs.attributes(options.index).modification
- local file_name = options.index:match(".*/([^.]+)%.[^.]+$")
- local cachefile = string.format("%s/cache/documents/%s",options.output,file_name)
- local out_attrs = lfs.attributes(cachefile)
- if not out_attrs or out_attrs.modification < file_mod then
- --we're out of date, update
- local fd = assert(io.open(options.index,"r"))
- local file_text = fd:read("*a")
- fd:close()
- local parsed_text = parse(file_text, options.index)
- local od = assert(io.open(cachefile,"w"))
- od:write(parsed_text)
- od:close()
- end
- state.sections[file_name] = {
- type = "reference",
- data_file = cachefile
- }
- state.index = state.sections[file_name]
-end
-
-log("After copying everything in, state.sections is:")
-log(state.sections)
-
-local headers = {}
-for name,section in pairs(state.sections) do
- log("section:",name,"type:",section.type,"data:")
- local ust = "namespace"
- for _,v in pairs(section) do
- if v.type == "method" then
- ust = "class"
- end
- end
- section.type = section.type or ust
- headers[section.type] = headers[section.type] or {}
- section.name = name
- table.insert(headers[section.type],section)
-end
-for _,group in pairs(headers) do
- table.sort(group,function(a,b)
- --print("sorting:",a.type,"against",b.type)
- return a.type < b.type
- end)
-end
---print("headers:",headers)
-
-local nvfd = assert(io.open("navbar.etlua","r"))
-local navbar = assert(et.compile(nvfd:read("*a")))
-nvfd:close()
-local navbarhtml = navbar{headers = headers}
-local pagefd = assert(io.open("page.etlua","r"))
-local page = assert(et.compile(pagefd:read("*a")))
-pagefd:close()
-local funcsignaturefd = assert(io.open("funcsignature.etlua","r"))
-local funcsignature = assert(et.compile(funcsignaturefd:read("*a")))
-funcsignaturefd:close()
-local sorted_headers = {}
-for name,_ in pairs(headers) do
- table.insert(sorted_headers,name)
-end
-table.sort(sorted_headers)
-for _,name in pairs(sorted_headers) do
- local header = headers[name]
- for _,section in pairs(header) do
- log("About to render section:",section.name)
- log(section)
- local pagehtml = assert(page{
- header = section,
- navbar = navbarhtml,
- options = options,
- et = et,
- funcsig = funcsignature,
- })
- log("Done rendering pagehtml")
- log("section name:",section.name)
- log("section:",section)
- local ofd = assert(io.open(options.output .. "/" .. section.name .. ".html","w"))
- ofd:write(pagehtml)
- ofd:close()
- end
-end
-
-if options.index ~= nil then
- local indexfd = assert(io.open("index.etlua","r"))
- local index = assert(et.compile(indexfd:read("*a")))
- indexfd:close()
- log("state.index:",state.index)
- local indextextfd = assert(io.open(state.index.data_file,"r"))
- local indextext = indextextfd:read("*a")
- indextextfd:close()
- local indexhtml = index{
- navbar = navbarhtml,
- options = options,
- et = et,
- text = indextext,
- }
- local ofd = assert(io.open(options.output .. "/index.html", "w"))
- ofd:write(indexhtml)
- ofd:close()
-end
-
---Copy style css
-local css = assert(io.open("style.css","r"))
-local css_out = assert(io.open(options.output .. "/style.css","w"))
-for line in css:lines() do
- css_out:write(line)
-end
-css:close()
-css_out:close()
-
---Generate html
---for header, sections in pairs(headers) do
-
- ----local ofd = assert(io.open(options.output .. "/" .. name,"w"))
- --print("want to output section:",name,section.type)
---end
-
---print(state)
|
