diff options
| author | Gly <[email protected]> | 2022-12-24 15:09:17 +0100 |
|---|---|---|
| committer | Gly <[email protected]> | 2022-12-24 15:09:17 +0100 |
| commit | 216c126bd8378e1b96159955fa00d647e50ec73b (patch) | |
| tree | 5f5f5eb1be9ad8072e67c7261527c9062235c277 /xmake/modules/private/utils/complete.lua | |
| parent | 2e5134b08e41ba3afb7975473601f4407a7334d5 (diff) | |
make completer into "class"
Diffstat (limited to 'xmake/modules/private/utils/complete.lua')
| -rw-r--r-- | xmake/modules/private/utils/complete.lua | 295 |
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 |
