initial commit
This commit is contained in:
82
Libraries/oUF/utils/changelog
Normal file
82
Libraries/oUF/utils/changelog
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
local tags = {}
|
||||
do
|
||||
for tag in io.popen('git tag'):lines() do
|
||||
local split = tag:gmatch('[^.]+')
|
||||
local release, api, bugfix = split(), split(), split() or 0
|
||||
table.insert(
|
||||
tags,
|
||||
{
|
||||
string = tag,
|
||||
release = release,
|
||||
api = api,
|
||||
bugfix = bugfix,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
table.sort(tags, function(a,b)
|
||||
a = a.release * 1e4 + a.api * 100 + a.bugfix
|
||||
b = b.release * 1e4 + b.api * 100 + b.bugfix
|
||||
|
||||
return a > b
|
||||
end)
|
||||
end
|
||||
|
||||
local generateLog = function(prevTag, currentTag)
|
||||
local ti = table.insert
|
||||
local sf = string.format
|
||||
|
||||
local out = {}
|
||||
local i = 0
|
||||
|
||||
ti(out, sf('**Changes in %s:**\n', currentTag))
|
||||
|
||||
for line in io.popen(sf('git shortlog --no-merges --reverse %s..%s', prevTag, currentTag)):lines() do
|
||||
if(line:sub(1, 6) == ' ') then
|
||||
local offset = line:match('() ', 7)
|
||||
if(offset) then
|
||||
line = line:sub(7, offset - 1)
|
||||
else
|
||||
line = line:sub(7)
|
||||
end
|
||||
line = line:gsub('#(%d+)', '[#%1](https://github.com/oUF-wow/oUF/issues/%1)')
|
||||
|
||||
i = i + 1
|
||||
ti(out, sf(' %s. %s', i, line))
|
||||
elseif(#line ~= 0) then
|
||||
i = 0
|
||||
ti(out, sf('- _%s_', line))
|
||||
end
|
||||
end
|
||||
|
||||
local p = assert(io.popen(sf('git diff --shortstat %s..%s', prevTag, currentTag)))
|
||||
local stat = p:read'*a'
|
||||
p:close()
|
||||
|
||||
ti(out, sf('- %s\n', stat:sub(2, -2)))
|
||||
|
||||
return table.concat(out, '\n')
|
||||
end
|
||||
|
||||
local stop
|
||||
local to = ...
|
||||
if(to) then
|
||||
for i=1, #tags do
|
||||
if(tags[i].string == to) then
|
||||
stop = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
if(not stop) then stop = #tags end
|
||||
else
|
||||
stop = #tags
|
||||
end
|
||||
|
||||
for i=2, stop do
|
||||
local current, prev = tags[i -1], tags[i]
|
||||
print(generateLog(prev.string, current.string))
|
||||
end
|
||||
|
||||
-- vim: set filetype=lua :
|
||||
254
Libraries/oUF/utils/docs
Normal file
254
Libraries/oUF/utils/docs
Normal file
@@ -0,0 +1,254 @@
|
||||
#!/usr/bin/env lua
|
||||
-- docs
|
||||
-- oUF documentation generator
|
||||
--
|
||||
-- This is really just a quick and dirty way of generating documentation for
|
||||
-- oUF[1]. The syntax is inspired by TomDoc[2], but a lot of the non-oUF and
|
||||
-- non-Lua things aren't implemented.
|
||||
--
|
||||
-- Why implement my own documentation generator?
|
||||
-- It was mainly done because oUF is kind-of special, but also because the
|
||||
-- available alternatives aren't good enough or have issues I can't workaround.
|
||||
--
|
||||
-- Things that need fixing:
|
||||
-- - No highlighting of Lua code.
|
||||
-- - Doesn't validate that comments are documentation strings.
|
||||
-- - Doesn't parse its own documentation header.
|
||||
-- - Close to zero error handling.
|
||||
--
|
||||
-- Usage
|
||||
--
|
||||
-- docs [docs path] [file...]
|
||||
--
|
||||
-- Links
|
||||
--
|
||||
-- [1] https://github.com/haste/oUF
|
||||
-- [2] http://tomdoc.org/
|
||||
|
||||
local out
|
||||
local lines
|
||||
|
||||
local tisf = function(fmt, ...)
|
||||
table.insert(out, fmt:format(...))
|
||||
end
|
||||
|
||||
local trim = function(str)
|
||||
return str:match('^()%s*$') and '' or str:match('^%s*(.*%S)')
|
||||
end
|
||||
|
||||
local findNextEmpty = function(start, stop)
|
||||
for i=start, stop or #lines do
|
||||
if(lines[i] == '') then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local findNextHeader = function(offest)
|
||||
for i=offest, #lines do
|
||||
local pre, header, post = unpack(lines, i, i + 2)
|
||||
-- Single lines without punctuation are headers.
|
||||
if(pre == '' and post == '' and not header:match'%.') then
|
||||
return i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local findNextArguent = function(start, stop, padding, pattern)
|
||||
for i=start, stop do
|
||||
local match, pad = lines[i]:match(pattern)
|
||||
if(match and pad == padding) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local replaceMarkup = function(str)
|
||||
return str
|
||||
-- `in-line code` to <code>in-line code</code>
|
||||
:gsub('`([^`]+)`', '<code>%1</code>')
|
||||
-- [Link](http://example.com) to <a href="http://example.com">Link</a>
|
||||
:gsub('%[([^%]]+)%]%(([^)]+)%)', '<a href="%2">%1</a>')
|
||||
end
|
||||
|
||||
local handleArguments = function(start, stop, pattern)
|
||||
tisf('<dl>')
|
||||
repeat
|
||||
-- Tear out the argument name and offset of where the description begins.
|
||||
local def, padding, offset = lines[start]:match(pattern)
|
||||
tisf('<dt>%s</dt>', def)
|
||||
|
||||
-- Insert the first line of the description.
|
||||
tisf('<dd>')
|
||||
tisf(lines[start]:sub(offset))
|
||||
|
||||
-- Find the next argument in the list or continue to the end of the
|
||||
-- current section.
|
||||
local nextarg = findNextArguent(start + 1, stop, padding, pattern)
|
||||
nextarg = (nextarg or stop + 1) - 1
|
||||
for i=start + 1, nextarg do
|
||||
tisf(trim(lines[i]))
|
||||
end
|
||||
tisf('</dd>')
|
||||
|
||||
start = nextarg + 1
|
||||
until start > stop
|
||||
tisf('</dl>')
|
||||
end
|
||||
|
||||
local handleExamples = function(start, stop)
|
||||
-- An extra line gets added if we don't do this.
|
||||
tisf('<pre><code>%s', lines[start]:sub(3))
|
||||
for i=start + 1, stop do
|
||||
tisf(lines[i]:sub(3))
|
||||
end
|
||||
tisf('</code></pre>')
|
||||
end
|
||||
|
||||
local handleParagraph = function(start, stop)
|
||||
tisf('<p>')
|
||||
for i=start, stop do
|
||||
tisf(trim(lines[i]))
|
||||
end
|
||||
tisf('</p>')
|
||||
end
|
||||
|
||||
local handleSection = function(start, stop)
|
||||
while(start) do
|
||||
-- Find the next empty line or continue until the end of the section.
|
||||
-- findNextEmpty() returns the position of the empty line, so we need to
|
||||
-- subtract one from it.
|
||||
local nextEmpty = findNextEmpty(start + 1, stop)
|
||||
if(nextEmpty) then
|
||||
nextEmpty = nextEmpty - 1
|
||||
else
|
||||
nextEmpty = stop
|
||||
end
|
||||
|
||||
local line = lines[start]
|
||||
if(not line) then
|
||||
return
|
||||
elseif(line:match('^%S+%s*%- ')) then
|
||||
handleArguments(start, nextEmpty, '(%S+)%s*()%- ()')
|
||||
elseif(line:sub(1, 2) == ' ') then
|
||||
handleExamples(start, nextEmpty)
|
||||
else
|
||||
handleParagraph(start, nextEmpty)
|
||||
end
|
||||
|
||||
start = findNextEmpty(nextEmpty, stop)
|
||||
if(start) then start = start + 1 end
|
||||
end
|
||||
end
|
||||
|
||||
local generateDocs = function(str, level)
|
||||
lines = {}
|
||||
out = {}
|
||||
|
||||
for line in str:gmatch('([^\n]*)\n') do
|
||||
table.insert(lines, line:gsub('\t*', ''):sub(2))
|
||||
end
|
||||
|
||||
-- The first line is always the main header.
|
||||
tisf('<h%d>%s</h%d>', level, lines[1], level)
|
||||
|
||||
-- Then comes the main description.
|
||||
local offset = findNextHeader(1)
|
||||
|
||||
-- Continue until two lines before the header or to the end of the comment.
|
||||
if(offset) then
|
||||
offset = offset - 2
|
||||
else
|
||||
offset = #lines
|
||||
end
|
||||
|
||||
local init = findNextEmpty(1) + 1
|
||||
if(init > offset) then
|
||||
init = 2
|
||||
end
|
||||
|
||||
handleSection(init, offset)
|
||||
|
||||
while(true) do
|
||||
offset = findNextHeader(offset)
|
||||
if(not offset) then break end
|
||||
|
||||
-- Every section has a header.
|
||||
tisf('<h%d>%s</h%d>', level + 1, lines[offset], level + 1)
|
||||
|
||||
-- Find out the size of the section.
|
||||
local start = findNextEmpty(offset) + 1
|
||||
if(not lines[start]) then
|
||||
-- There's no section here, only a headline.
|
||||
break
|
||||
end
|
||||
|
||||
local stop
|
||||
local nextHeader = findNextHeader(start)
|
||||
if(nextHeader) then
|
||||
stop = nextHeader - 2
|
||||
else
|
||||
local nextEmpty = findNextEmpty(start)
|
||||
if(nextEmpty) then
|
||||
stop = nextEmpty - 1
|
||||
else
|
||||
stop = #lines
|
||||
end
|
||||
end
|
||||
|
||||
handleSection(start, stop)
|
||||
offset = stop + 1
|
||||
end
|
||||
|
||||
return table.concat(out, '\n')
|
||||
end
|
||||
|
||||
local handleFile = function(path)
|
||||
local file = io.open(path, 'r')
|
||||
local content = file:read'*a'
|
||||
file:close()
|
||||
|
||||
local out = {}
|
||||
local init = 1
|
||||
repeat
|
||||
local _, comStart, depth = content:find('%-%-%[(=*)%[ ', init)
|
||||
if(comStart) then
|
||||
local comEnd = content:find('%]' .. depth .. '%]', comStart)
|
||||
local comment = content:sub(comStart, comEnd - 1)
|
||||
|
||||
-- Convert markup to html.
|
||||
comment = replaceMarkup(comment)
|
||||
|
||||
-- The first comment uses h1 and h2, while the subsequent ones uses h3
|
||||
-- and h4.
|
||||
local level = init == 1 and 1 or 3
|
||||
table.insert(out, generateDocs(comment, init == 1 and 1 or 3))
|
||||
|
||||
init = comEnd
|
||||
end
|
||||
until not comStart
|
||||
|
||||
return table.concat(out, '\n')
|
||||
end
|
||||
|
||||
local destination = (...)
|
||||
for i=2, select('#', ...) do
|
||||
local file = select(i, ...)
|
||||
local path, filename = file:match('(.+)/(.+)$')
|
||||
|
||||
if(path:sub(1,3) == '../') then
|
||||
path = path:sub(4)
|
||||
end
|
||||
|
||||
if(#path == 0) then path = nil end
|
||||
filename = filename:gsub('lua', 'html')
|
||||
|
||||
local doc = handleFile(file)
|
||||
if(doc) then
|
||||
local dfPath = string.format('%s/%s', destination, path or '')
|
||||
os.execute(string.format('mkdir -p %s', dfPath))
|
||||
local docFile = io.open(string.format('%s/%s', dfPath, filename), 'w+')
|
||||
docFile:write(doc)
|
||||
docFile:close()
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user