summaryrefslogtreecommitdiff
path: root/xmake/modules/private/utils/complete.lua
diff options
context:
space:
mode:
authorGly <[email protected]>2022-12-24 15:09:17 +0100
committerGly <[email protected]>2022-12-24 15:09:17 +0100
commit216c126bd8378e1b96159955fa00d647e50ec73b (patch)
tree5f5f5eb1be9ad8072e67c7261527c9062235c277 /xmake/modules/private/utils/complete.lua
parent2e5134b08e41ba3afb7975473601f4407a7334d5 (diff)
make completer into "class"
Diffstat (limited to 'xmake/modules/private/utils/complete.lua')
-rw-r--r--xmake/modules/private/utils/complete.lua295
1 files changed, 11 insertions, 284 deletions
diff --git a/xmake/modules/private/utils/complete.lua b/xmake/modules/private/utils/complete.lua
index 072c69704..a93d24776 100644
--- a/xmake/modules/private/utils/complete.lua
+++ b/xmake/modules/private/utils/complete.lua
@@ -23,292 +23,13 @@ import("core.base.option")
import("core.base.task")
import("core.base.cli")
import("core.base.json")
-
-local raw_words = {}
-local raw_config
-local position = 0
-local no_json = false
-local use_spaces = true
-local no_key = false
-local reenter = false
-
-function _print_candidate(candidate)
- if candidate.value and #candidate.value ~= 0 then
- printf(candidate.value)
- if use_spaces and candidate.is_complete then
- print(" ")
- else
- print("")
- end
- end
-end
-
-function _print_candidates(candidates)
- if to_json then
- print(json.encode(candidates))
- else
- for _, v in ipairs(candidates) do
- _print_candidate(v)
- end
- end
-end
-
-function _find_candidates(candidates, find)
-
- if type(candidates) ~= 'table' then
- return {}
- end
-
- local has_candidate = false
- local results = table.new(#candidates, 0)
-
- -- find candidate starts with find str
- for _, v in ipairs(candidates) do
- if tostring(v):startswith(find) then
- table.insert(results, v)
- has_candidate = true
- end
- end
-
- -- stop searching if found any
- if has_candidate then
- return results
- end
-
- -- find candidate contains find str
- for _, v in ipairs(candidates) do
- if tostring(v):find(find, 1, true) then
- table.insert(results, v)
- end
- end
-
- return results
-end
-
-function _complete_task(tasks, name)
- local found_candidates = {}
- for i, v in ipairs(_find_candidates((table.keys(tasks)), name)) do
- table.insert(found_candidates, { value = v, is_complete = true, description = tasks[v].description })
- end
- _print_candidates(found_candidates)
- return #found_candidates > 0
-end
-
--- complete values of kv
-function _complete_option_kv_v(options, current, completing, name, value)
-
- -- find completion option
- local opt
- for _, v in ipairs(options) do
- if v[3] == "kv" and (v[1] == name or v[2] == name) then
- opt = v
- break
- end
- end
- if not opt then
- return false
- end
-
- -- show candidates of values
- local values = opt.values
- if type(values) == "function" then
- values = values(value, current)
- end
- if values == nil and type(opt[4]) == "boolean" then
- values = { "yes", "no" }
- -- ignore existing input
- value = ""
- end
-
- -- match values starts with value first
- local found_candidates = {}
- for _, v in ipairs(_find_candidates(values, value)) do
- if no_key then
- table.insert(found_candidates, { value = v, is_complete = true })
- else
- table.insert(found_candidates, { value = format("--%s=%s", name, v), is_complete = true })
- end
- end
- _print_candidates(found_candidates)
-
- -- whether any candidates has been found, finish complete since we don't have more info
- return true
-end
-
--- complete keys of kv
-function _complete_option_kv_k(options, current, completing, name)
-
- local opcandi = table.new(0, 10)
- for _, opt in ipairs(options) do
- if opt[2] and current[opt[2]] == nil and (opt[3] == "kv" or opt[3] == "k") then
- opcandi[opt[2]] = opt
- end
- end
- local found_candidates = {}
- for _, k in ipairs(_find_candidates((table.keys(opcandi)), name)) do
- local opt = opcandi[k]
- local name = format((opt[3] == "k") and "--%s" or "--%s=", opt[2])
- table.insert(found_candidates, { value = name, description = opt[5], is_complete = (opt[3] == "k") })
- end
- _print_candidates(found_candidates)
-
- return true
-end
-
-function _complete_option_kv(options, current, completing)
-
- local name, value
- if completing == "-" or completing == "--" then
- name = ""
- elseif completing:startswith("--") then
- local parg = cli.parsev({completing})[1]
- if parg.type == "option" then
- name, value = parg.key, parg.value
- elseif parg.type == "flag" then
- name = parg.key
- end
- elseif completing:startswith("-") then
- -- search full names only
- return true
- end
-
- if value then
- -- complete values
- return _complete_option_kv_v(options, current, completing, name, value)
- else
- -- complete keys
- return _complete_option_kv_k(options, current, completing, name)
- end
-end
-
--- complete options v and vs
-function _complete_option_v(options, current, completing)
- -- find completion option
- local opt
- local optvs
- for _, v in ipairs(options) do
- if v[3] == "v" and current[v[2] or v[1]] == nil then
- opt = v
- end
- if v[3] == "vs" and not optvs then
- optvs = v
- end
- end
- local found_candidates = {}
- if opt then
- -- show candidates of values
- local values = opt.values
- if type(values) == "function" then
- values = values(completing, current)
- end
- for _, v in ipairs(values) do
- if tostring(v):startswith(completing) then
- table.insert(found_candidates, { value = v, is_complete = true })
- end
- end
- end
-
- if optvs and #found_candidates == 0 then
- -- show candidates of values
- local values = optvs.values
- if type(values) == "function" then
- values = values(completing)
- end
- for _, v in ipairs(values) do
- if tostring(v):startswith(completing) then
- table.insert(found_candidates, { value = v, is_complete = true })
- end
- end
- end
- _print_candidates(found_candidates)
- return #found_candidates > 0
-end
-
-function _complete_option(options, segs, completing)
- local current_options = try
- {
- function()
- return option.raw_parse(segs, options, { populate_defaults = false, allow_unknown = true })
- end
- }
- -- current options is invalid
- if not current_options then return false end
-
- -- current context is wrong
- if not reenter and (current_options.file or current_options.project) then
- local args = {"lua", "private.utils.complete", tostring(position), raw_config .. "-reenter", table.unpack(raw_words) }
- if current_options.file then
- table.insert(args, 2, "--file=" .. current_options.file)
- end
- if current_options.project then
- table.insert(args, 2, "--project=" .. current_options.project)
- end
- os.execv("xmake", args)
- return true
- end
-
- if completing:startswith("-") then
- return _complete_option_kv(options, current_options, completing)
- else
- return _complete_option_v(options, current_options, completing)
- end
-end
-
-function _complete(argv, completing)
-
- local tasks = table.new(10, 0)
- local shortnames = table.new(0, 10)
- for _, v in ipairs(task.names()) do
- local menu = option.taskmenu(v)
- tasks[v] = menu
- if menu.shortname then
- shortnames[menu.shortname] = v
- end
- end
-
- if #argv == 0 then
- if _complete_task(tasks, completing) then return end
- end
-
- local task_name = "build"
- if argv[1] and not argv[1]:startswith("-") then
- task_name = table.remove(argv, 1)
- end
-
- if shortnames[task_name] then task_name = shortnames[task_name] end
-
- local options
- if tasks[task_name] then
- options = tasks[task_name].options
- else
- options = tasks["build"].options
- end
-
- _complete_option(options, argv, completing)
-end
+import("private.utils.completer")
function main(pos, config, ...)
- raw_words = {...}
-
- raw_config = (config or ""):trim()
- if raw_config:find("nospace", 1, true) then
- use_spaces = false
- end
- if raw_config:find("reenter", 1, true) then
- reenter = true
- end
- if raw_config:find("nokey", 1, true) then
- no_key = true
- end
- if raw_config:find("debug", 1, true) then
- debug = true
- end
- if raw_config:find("json", 1, true) then
- to_json = true
- end
+ local comp = completer.new(pos, config, {...})
- local word = table.concat(raw_words, " ") or ""
+ local word = table.concat(comp:words(), " ") or ""
position = tonumber(pos) or 0
local has_space = word:endswith(" ") or position > #word
@@ -327,11 +48,17 @@ function main(pos, config, ...)
end
end
+ local items = {}
+ local tasks = task.names()
+ for _, name in ipairs(tasks) do
+ items[name] = option.taskmenu(name)
+ end
+
if has_space then
- _complete(argv, "")
+ comp:complete(items, argv, "")
else
local completing = table.remove(argv)
- _complete(argv, completing or "")
+ comp:complete(items, argv, completing or "")
end
end