|
|
@ -69,7 +69,7 @@ local function update_entry(entry, iterator, opts)
|
|
|
|
for line in iterator do
|
|
|
|
for line in iterator do
|
|
|
|
if not short_help_found and opts.first_line_is_short_help then
|
|
|
|
if not short_help_found and opts.first_line_is_short_help then
|
|
|
|
local _,_,text = line:trim():find('^%-%-%s*(.*)')
|
|
|
|
local _,_,text = line:trim():find('^%-%-%s*(.*)')
|
|
|
|
if text[#text] ~= '.' then
|
|
|
|
if not text:endswith('.') then
|
|
|
|
text = text .. '.'
|
|
|
|
text = text .. '.'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
entry.short_help = text
|
|
|
|
entry.short_help = text
|
|
|
@ -92,10 +92,11 @@ local function update_entry(entry, iterator, opts)
|
|
|
|
if not header_found and line:find('%w') then
|
|
|
|
if not header_found and line:find('%w') then
|
|
|
|
header_found = true
|
|
|
|
header_found = true
|
|
|
|
elseif not tags_found and line:find('^Tags: [%w, ]+$') then
|
|
|
|
elseif not tags_found and line:find('^Tags: [%w, ]+$') then
|
|
|
|
-- tags must appear before the help text begins
|
|
|
|
|
|
|
|
local _,_,tags = line:trim():find('Tags: (.*)')
|
|
|
|
local _,_,tags = line:trim():find('Tags: (.*)')
|
|
|
|
entry.tags = tags:split('[ ,]+')
|
|
|
|
entry.tags = {}
|
|
|
|
table.sort(entry.tags)
|
|
|
|
for _,tag in ipairs(tags:split('[ ,]+')) do
|
|
|
|
|
|
|
|
entry.tags[tag] = true
|
|
|
|
|
|
|
|
end
|
|
|
|
tags_found = true
|
|
|
|
tags_found = true
|
|
|
|
elseif not short_help_found and not line:find('^Keybinding:') and
|
|
|
|
elseif not short_help_found and not line:find('^Keybinding:') and
|
|
|
|
line:find('%w') then
|
|
|
|
line:find('%w') then
|
|
|
@ -260,11 +261,11 @@ local function initialize_tags()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- ensures the db is up to date by scanning all help sources. does not do
|
|
|
|
-- ensures the db is up to date by scanning all help sources. does not do
|
|
|
|
-- anything if it has already been run within the last second.
|
|
|
|
-- anything if it has already been run within the last 10 seconds.
|
|
|
|
last_refresh_ms = last_refresh_ms or 0
|
|
|
|
last_refresh_ms = last_refresh_ms or 0
|
|
|
|
local function ensure_db()
|
|
|
|
local function ensure_db()
|
|
|
|
local now_ms = dfhack.getTickCount()
|
|
|
|
local now_ms = dfhack.getTickCount()
|
|
|
|
if now_ms - last_refresh_ms < 1000 then return end
|
|
|
|
if now_ms - last_refresh_ms < 60000 then return end
|
|
|
|
last_refresh_ms = now_ms
|
|
|
|
last_refresh_ms = now_ms
|
|
|
|
|
|
|
|
|
|
|
|
local old_db = db
|
|
|
|
local old_db = db
|
|
|
@ -293,9 +294,18 @@ function get_entry_long_help(entry)
|
|
|
|
return get_db_property(entry, 'long_help')
|
|
|
|
return get_db_property(entry, 'long_help')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- returns the list of tags associated with the entry
|
|
|
|
local function set_to_sorted_list(set)
|
|
|
|
|
|
|
|
local list = {}
|
|
|
|
|
|
|
|
for item in pairs(set) do
|
|
|
|
|
|
|
|
table.insert(list, item)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
table.sort(list)
|
|
|
|
|
|
|
|
return list
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- returns the list of tags associated with the entry, in alphabetical order
|
|
|
|
function get_entry_tags(entry)
|
|
|
|
function get_entry_tags(entry)
|
|
|
|
return get_db_property(entry, 'tags')
|
|
|
|
return set_to_sorted_list(get_db_property(entry, 'tags'))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local function chunk_for_sorting(str)
|
|
|
|
local function chunk_for_sorting(str)
|
|
|
@ -326,76 +336,109 @@ local function sort_by_basename(a, b)
|
|
|
|
return false
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local function add_if_matched(commands, command, strs, runnable)
|
|
|
|
local function matches(command, filter)
|
|
|
|
if runnable and db[command].unrunnable then
|
|
|
|
local db_entry = db[command]
|
|
|
|
return
|
|
|
|
if filter.runnable and db_entry.unrunnable then
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
if filter.tag then
|
|
|
|
|
|
|
|
local matched = false
|
|
|
|
|
|
|
|
for _,tag in ipairs(filter.tag) do
|
|
|
|
|
|
|
|
if db_entry.tags[tag] then
|
|
|
|
|
|
|
|
matched = true
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
if not matched then
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if strs then
|
|
|
|
if filter.str then
|
|
|
|
local matched = false
|
|
|
|
local matched = false
|
|
|
|
for _,str in ipairs(strs) do
|
|
|
|
for _,str in ipairs(filter.str) do
|
|
|
|
if command:find(str, 1, true) then
|
|
|
|
if command:find(str, 1, true) then
|
|
|
|
matched = true
|
|
|
|
matched = true
|
|
|
|
break
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if not matched then
|
|
|
|
if not matched then
|
|
|
|
return
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
table.insert(commands, command)
|
|
|
|
return true
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local function normalize_string_list(l)
|
|
|
|
|
|
|
|
if not l then return nil end
|
|
|
|
|
|
|
|
if type(l) == 'string' then
|
|
|
|
|
|
|
|
return {l}
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
return l
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local function normalize_filter(f)
|
|
|
|
|
|
|
|
if not f then return nil end
|
|
|
|
|
|
|
|
local filter = {}
|
|
|
|
|
|
|
|
filter.str = normalize_string_list(f.str)
|
|
|
|
|
|
|
|
filter.tag = normalize_string_list(f.tag)
|
|
|
|
|
|
|
|
filter.runnable = f.runnable
|
|
|
|
|
|
|
|
if not filter.str and not filter.tag and not filter.runnable then
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
return filter
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- returns a list of identifiers, alphabetized by their last path component
|
|
|
|
-- returns a list of identifiers, alphabetized by their last path component
|
|
|
|
-- (e.g. gui/autobutcher will immediately follow autobutcher).
|
|
|
|
-- (e.g. gui/autobutcher will immediately follow autobutcher).
|
|
|
|
-- the optional filter element is a map with the following elements:
|
|
|
|
-- the optional include and exclude filter params are maps with the following
|
|
|
|
|
|
|
|
-- elements:
|
|
|
|
-- str - if a string, filters by the given substring. if a table of strings,
|
|
|
|
-- str - if a string, filters by the given substring. if a table of strings,
|
|
|
|
-- includes commands that match any of the given substrings.
|
|
|
|
-- includes commands that match any of the given substrings.
|
|
|
|
-- tag - if a string, filters by the given tag name. if a table of strings,
|
|
|
|
-- tag - if a string, filters by the given tag name. if a table of strings,
|
|
|
|
-- includes commands that match any of the given tags.
|
|
|
|
-- includes commands that match any of the given tags.
|
|
|
|
-- runnable - if true, filters out plugin names that do no correspond to
|
|
|
|
-- runnable - if true, matches only runnable commands, not plugin names.
|
|
|
|
-- runnable commands.
|
|
|
|
function get_entries(include, exclude)
|
|
|
|
function list_entries(filter)
|
|
|
|
|
|
|
|
ensure_db()
|
|
|
|
ensure_db()
|
|
|
|
filter = filter or {}
|
|
|
|
include = normalize_filter(include)
|
|
|
|
|
|
|
|
exclude = normalize_filter(exclude)
|
|
|
|
local commands = {}
|
|
|
|
local commands = {}
|
|
|
|
local strs = filter.str
|
|
|
|
for command in pairs(db) do
|
|
|
|
if filter.str then
|
|
|
|
if (not include or matches(command, include)) and
|
|
|
|
if type(strs) == 'string' then strs = {strs} end
|
|
|
|
(not exclude or not matches(command, exclude)) then
|
|
|
|
end
|
|
|
|
table.insert(commands, command)
|
|
|
|
local runnable = filter.runnable
|
|
|
|
|
|
|
|
if not filter.tag then
|
|
|
|
|
|
|
|
for command in pairs(db) do
|
|
|
|
|
|
|
|
add_if_matched(commands, command, strs, runnable)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
local command_set = {}
|
|
|
|
|
|
|
|
local tags = filter.tag
|
|
|
|
|
|
|
|
if type(tags) == 'string' then tags = {tags} end
|
|
|
|
|
|
|
|
for _,tag in ipairs(tags) do
|
|
|
|
|
|
|
|
if not tag_index[tag] then
|
|
|
|
|
|
|
|
error('invalid tag: ' .. tag)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
for _,command in ipairs(tag_index[tag]) do
|
|
|
|
|
|
|
|
command_set[command] = true
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
for command in pairs(command_set) do
|
|
|
|
|
|
|
|
add_if_matched(commands, command, strs, runnable)
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
table.sort(commands, sort_by_basename)
|
|
|
|
table.sort(commands, sort_by_basename)
|
|
|
|
return commands
|
|
|
|
return commands
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local function get_max_width(list, min_width)
|
|
|
|
|
|
|
|
local width = min_width or 0
|
|
|
|
|
|
|
|
for _,item in ipairs(list) do
|
|
|
|
|
|
|
|
width = math.max(width, #item)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
return width
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- prints the requested entries to the console. include and exclude filters are
|
|
|
|
|
|
|
|
-- as in get_entries above.
|
|
|
|
|
|
|
|
function list_entries(include_tags, include, exclude)
|
|
|
|
|
|
|
|
local entries = get_entries(include, exclude)
|
|
|
|
|
|
|
|
local width = get_max_width(entries, 10)
|
|
|
|
|
|
|
|
for _,entry in ipairs(entries) do
|
|
|
|
|
|
|
|
print((' %-'..width..'s %s'):format(
|
|
|
|
|
|
|
|
entry, get_entry_short_help(entry)))
|
|
|
|
|
|
|
|
if include_tags then
|
|
|
|
|
|
|
|
print((' '..(' '):rep(width)..' tags(%s)'):format(
|
|
|
|
|
|
|
|
table.concat(get_entry_tags(entry), ',')))
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- returns the defined tags in alphabetical order
|
|
|
|
-- returns the defined tags in alphabetical order
|
|
|
|
function list_tags()
|
|
|
|
function get_tags()
|
|
|
|
ensure_db()
|
|
|
|
ensure_db()
|
|
|
|
local tags = {}
|
|
|
|
return set_to_sorted_list(tag_index)
|
|
|
|
for tag in pairs(tag_index) do
|
|
|
|
|
|
|
|
table.insert(tags, tag)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
table.sort(tags)
|
|
|
|
|
|
|
|
return tags
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- returns the description associated with the given tag
|
|
|
|
-- returns the description associated with the given tag
|
|
|
@ -407,4 +450,13 @@ function get_tag_description(tag)
|
|
|
|
return tag_index[tag].description
|
|
|
|
return tag_index[tag].description
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- prints the defined tags and their descriptions to the console
|
|
|
|
|
|
|
|
function list_tags()
|
|
|
|
|
|
|
|
local tags = get_tags()
|
|
|
|
|
|
|
|
local width = get_max_width(tags, 10)
|
|
|
|
|
|
|
|
for _,tag in ipairs(tags) do
|
|
|
|
|
|
|
|
print((' %-'..width..'s %s'):format(tag, get_tag_description(tag)))
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
return _ENV
|
|
|
|
return _ENV
|
|
|
|