[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: a script to simulate lua man pages
- From: Norman Ramsey <nr@...>
- Date: Sat, 07 May 2005 22:22:15 -0400
Dear Lua Lovers,
I use Lua only episodically, and I hate having to look up API
functions every time I want to do something. If only there
were man pages, I could just type
man lua_gettable
and everything would be good. But there are no man pages :-(
Do not fear! An hour of hacking solves the problem.
Attached is a script that goes through the HTML version
of the Lua manual and extracts documentation relevant
to functions by name (and more besides). Some examples
you can try include
luahelp gettable
luahelp expressions
luahelp metatable
and much more besides. For guidance, run the script with no arguments.
Be warned that you will need to edit two variables!
The script needs to know where the manual is, and it
needs a pager that can display HTML read from standard
input. The defaults should work on Debian linux,
provided you have lynx installed.
Under 200 lines of goodness! Enjoy!
Norman
#!/usr/bin/env lua50
--[[--------------------------------------------------------------
This script reads the HTML version of the lua manual and pulls out
a short section containing the documentation you hoped for :-)
It is meant to work around the lack of man pages for lua.
For examples, run the script with no arguments.
It requires you two edit two variables:
manual Location of the manual
pager A script that can take HTML on standard input and
display it to the user
--]]----------------------------------------------------------------
local manual = '/usr/share/doc/lua50/manual/manual.html'
local pager = 'lynx -nolist -dump -stdin | less'
-- user editing stops here
----------------------------------------------------------------
-- fast synonyms for library functions
local find = string.find
local gfind = string.gfind
local gsub = string.gsub
local insert = table.insert
-- sections is a list of all sections in the manual
-- each section is referred to by number
local sections = { }
local s = 1 -- number of the current section
-- accumulate the argument as the next section
local function next_section(lines)
sections[s] = lines
s = s + 1
return { }
end
local keytab = { }
-- For each named thing, stores the number of the section
-- documenting that thing. The level of indirection allows
-- us to refer to a section not yet completed, and it makes
-- it easy to have multiple references to a single section.
local function add_definition(luaval, optional)
-- add a definition to the current section
if luaval then
if keytab[luaval] and keytab[luaval] ~= s then
if not optional then
io.stderr:write ("duplicate definitions of " .. luaval .. " in sections " .. s .. " and " .. keytab[luaval] .. '\n')
end
else
keytab[luaval] = s
end
end
end
---------- righteous pattern matching for spotting definitions of C things
local rettypes = -- things that can be return types
{ 'void', 'int', 'char', 'const char', 'void', 'size_t',
'lua_Number', 'lua_CFunction' }
local isret = { } -- quick set of return types as mapping to bool
for _, t in pairs(rettypes) do
isret[t] = true
end
-- add declaration of a C function
local function add_c_def(line)
local i, j, rettype, fname =
find(line, "^%s+(%a[%a ]*%a)%s+%**(lua_[%a_]+)%s*%(lua_State.*%);")
if not rettype then
i, j, rettype, fname =
find(line, "^%s+([%a_]+)%s+%**(lua_[%a_]+)%s*%(lua_State.*%);")
end
if rettype and fname and isret[rettype] then
add_definition(fname)
end
end
-- add definition of a C macro
local function add_c_macro(line)
local i, j, mname = find(line, "^%s+#define%s+(lua_[%a_]+)%(")
add_definition(mname)
end
-- remember definitions by name tags in the HTML
local secnames = { } --- every section
local chapnames = { } --- just h1 and h2 sections
local function add_html_anchor_names(line)
for n in gfind(line, '<a name="([^"]+)">') do
n = string.lower(n)
add_definition(n, 'optional')
if not find(n, '^[%d%.]+$') then
table.insert(secnames, n .. '<br>')
if find(line, "<h[12]>") then
table.insert(chapnames, n .. '<br>')
end
end
end
end
-- add all known definitions
local function add_definitions(line)
-- idiom for library functions
local i, j, luaval, luatab = find(line, "<h3><code>(([%a%._]+)%.[%a%._]+) ")
add_definition(luaval) -- remember the full name
add_definition(luatab, 'optional') -- remember the library's name
add_c_def(line)
add_c_macro(line)
add_html_anchor_names(line)
end
-- now read in, split, and index all the lines
local lines = { }
for line in io.lines(manual) do
-- section boundaries are on HTML <h1> and <h2> tags
line = gsub(line, "´", "'") -- too hard to read
if find(line, "<h[12]>") then
lines = next_section(lines)
end
insert(lines, line)
add_definitions(line)
end
lines = next_section(lines)
-- now add special sections containing HTML anchor names
keytab['sections'] = s
keytab['contents'] = s
next_section(secnames)
keytab['chapters'] = s
next_section(chapnames)
-- here's how we display a section
local function showsection(s)
local f = assert(io.popen(pager, "w"))
for i = 1, table.getn(s) do
f:write(s[i], "\n")
end
f:close()
end
-- finally, do something based on the user's input
local h = arg[1]
if not h then
io.write [[
try
lhelp chapters
lhelp contents
lhelp <name> -- name from chapters or contents list
lhelp <cfunction-name> -- e.g., lhelp isnumber
lhelp <libname> -- e.g., lhelp os
lhelp <libname>.<funname> -- e.g., lhelp os.time
]]
else
-- if it helps, put in the lua_ prefix
if not keytab[h] and keytab['lua_' .. h] then
h = 'lua_' .. h
end
if keytab[h] then -- show a section
showsection(sections[keytab[h]])
elseif string.find(h, '^-%d+$') then -- for debugging only (section by number)
local _, _, n = string.find(h, '^-(%d+)$')
showsection(sections[tonumber(n)])
else
io.write('no help for ', h, '\n')
end
end