1local gio = require("lgi").Gio 2local gobject = require("lgi").GObject 3local glib = require("lgi").GLib 4 5local name_attr = gio.FILE_ATTRIBUTE_STANDARD_NAME 6local type_attr = gio.FILE_ATTRIBUTE_STANDARD_TYPE 7 8local module = {} 9 10-- Like pairs(), but iterate over keys in a sorted manner. Does not support 11-- modifying the table while iterating. 12local function sorted_pairs(t) 13 -- Collect all keys 14 local keys = {} 15 for k in pairs(t) do 16 table.insert(keys, k) 17 end 18 19 table.sort(keys) 20 21 -- return iterator function 22 local i = 0 23 return function() 24 i = i + 1 25 if keys[i] then 26 return keys[i], t[keys[i]] 27 end 28 end 29end 30 31-- Recursive file scanner 32local function get_all_files(path, ext, ret) 33 ret = ret or {} 34 local enumerator = gio.File.new_for_path(path):enumerate_children( 35 table.concat({name_attr, type_attr}, ",") , 0, nil, nil 36 ) 37 38 for file in function() return enumerator:next_file() end do 39 local file_name = file:get_attribute_as_string(name_attr) 40 local file_type = file:get_file_type() 41 local match_ext = file_name:match("[.]"..ext.."$" or "") 42 local fpath = enumerator:get_child(file):get_path() 43 local is_test = fpath:match("/tests/") 44 if file_type == "REGULAR" and match_ext and not is_test then 45 table.insert(ret, fpath) 46 elseif file_type == "DIRECTORY" then 47 get_all_files(enumerator:get_child(file):get_path(), ext, ret) 48 end 49 end 50 51 return ret 52end 53 54local function path_to_module(path) 55 if path:match("[.]c$") then 56 return path:gmatch("/([^./]+)[.]c$")() 57 end 58 59 for _, module in ipairs { 60 "awful", "wibox", "gears", "naughty", "menubar", "beautiful" 61 } do 62 local match = path:match("/"..module.."/([^.]+).lua") 63 if match then 64 return module.."."..match:gsub("/",".") 65 end 66 end 67 68 error("Cannot figure out module for " .. tostring(path)) 69end 70 71function module.path_to_html(path) 72 local mod = path_to_module(path):gsub(".init", "") 73 local f = assert(io.open(path)) 74 while true do 75 local line = f:read() 76 if not line then break end 77 if line:match("@classmod") then 78 f:close() 79 return "../classes/".. mod ..".html#" 80 end 81 if line:match("@module") or line:match("@submodule") then 82 f:close() 83 return "../libraries/".. mod ..".html#" 84 end 85 end 86 f:close() 87 88 error("Cannot figure out if module or class: " .. tostring(path)) 89end 90 91local function get_link(file, element, element_name) 92 return table.concat { 93 "<a href='", 94 module.path_to_html(file), 95 element, 96 "'>", 97 element_name, 98 "</a>" 99 } 100end 101 102local function parse_files(paths, property_name, matcher, name_matcher) 103 local exp1 = "[-*]*[ ]*@".. property_name .." ([^ \n]*)" 104 local exp2 = matcher or "[-*]*[ ]*".. property_name ..".(.+)" 105 local exp3 = name_matcher or "[. ](.+)" 106 107 local ret = {} 108 109 table.sort(paths) 110 111 -- Find all @beautiful doc entries 112 for _,file in ipairs(paths) do 113 local f = io.open(file) 114 115 local buffer = "" 116 117 for line in f:lines() do 118 119 local var = line:gmatch(exp1)() 120 121 -- There is no backward/forward pattern in lua 122 if #line <= 1 then 123 buffer = "" 124 elseif #buffer and not var then 125 buffer = buffer.."\n"..line 126 elseif line:sub(1,3) == "---" or line:sub(1,3) == "/**" then 127 buffer = line 128 end 129 130 if var then 131 -- Get the @param, @see and @usage 132 local params = "" 133 for line in f:lines() do 134 if line:sub(1,2) ~= "--" and line:sub(1,2) ~= " *" then 135 break 136 else 137 params = params.."\n"..line 138 end 139 end 140 141 local name = var:gmatch(exp2)() 142 if not name then 143 print("WARNING:", var, 144 "seems to be misformatted. Use `beautiful.namespace_name`" 145 ) 146 else 147 table.insert(ret, { 148 file = file, 149 name = name:gsub("_", "\\_"), 150 link = get_link(file, var, var:match(exp3):gsub("_", "\\_")), 151 desc = buffer:gmatch("[-*/ \n]+([^\n.]*)")() or "", 152 mod = path_to_module(file), 153 }) 154 end 155 156 buffer = "" 157 end 158 end 159 end 160 161 return ret 162end 163 164local function create_table(entries, columns, prefix) 165 prefix = prefix or "" 166 local lines = {} 167 168 for _, entry in ipairs(entries) do 169 local line = " <tr>" 170 171 for _, column in ipairs(columns) do 172 line = line.."<td>"..entry[column].."</td>" 173 end 174 175 table.insert(lines, prefix..line.."</tr>\n") 176 end 177 178 return [[--<table class='widget_list' border=1> 179]]..prefix..[[<tr> 180]]..prefix..[[ <th align='center'>Name</th> 181]]..prefix..[[ <th align='center'>Description</th> 182]]..prefix..[[</tr> 183]] .. table.concat(lines) .. prefix .."</table>\n" 184end 185 186module.create_table = create_table 187module.parse_files = parse_files 188module.sorted_pairs = sorted_pairs 189module.get_all_files = get_all_files 190 191return module 192