lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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, "&acute;", "'") -- 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