diff --git a/clink/lua/scripts/arguments.lua b/clink/lua/scripts/arguments.lua index 14c14fe3e..5584f8b25 100644 --- a/clink/lua/scripts/arguments.lua +++ b/clink/lua/scripts/arguments.lua @@ -390,11 +390,12 @@ function _argmatcher:_generate(line_state, match_builder) -- could be well out of range. local matcher = reader._matcher local arg_index = reader._arg_index + local match_type = ((not matcher._deprecated) and "arg") or nil -- Are we left with a valid argument that can provide matches? - local add_matches = function(arg) + local add_matches = function(arg, match_type) for key, _ in pairs(arg._links) do - match_builder:addmatch(key, "arg") + match_builder:addmatch(key, match_type) end for _, i in ipairs(arg) do @@ -404,9 +405,9 @@ function _argmatcher:_generate(line_state, match_builder) return j or false end - match_builder:addmatches(j, "arg") + match_builder:addmatches(j, match_type) else - match_builder:addmatch(i, "arg") + match_builder:addmatch(i, match_type) end end @@ -416,12 +417,12 @@ function _argmatcher:_generate(line_state, match_builder) -- Select between adding flags or matches themselves. Works in conjunction -- with getwordbreakinfo()'s return. if matcher._flags and matcher:_is_flag(line_state:getendword()) then - add_matches(matcher._flags._args[1]) + add_matches(matcher._flags._args[1], match_type) return true else local arg = matcher._args[arg_index] if arg then - return add_matches(arg) and true or false + return add_matches(arg, match_type) and true or false end end @@ -556,6 +557,69 @@ function clink.argmatcher(...) return matcher end +-------------------------------------------------------------------------------- +--- -name: clink.dirmatches +--- -arg: word:string +--- -ret: table +--- -show: -- Make "cd" generate directory matches (no files). +--- -show: clink.argmatcher("cd") +--- -show: :addflags("/d") +--- -show: :argarg(({ clink.dirmatches }) +--- You can use this function in an argmatcher to supply directory matches. +--- This automatically handles Readline tilde completion. +function clink.dirmatches(match_word) + local word = rl.expandtilde(match_word) + + local root = path.getdirectory(word) or "" + if expanded then + root = rl.collapsetilde(root) + end + + local matches = {} + for _, i in ipairs(os.globdirs(word.."*", true)) do + local m = path.join(root, i.name) + table.insert(matches, { match = m, type = i.type }) + end + return matches +end + +-------------------------------------------------------------------------------- +--- -name: clink.filematches +--- -arg: word:string +--- -ret: table +--- -show: -- Make "foo --file" generate file matches, but other flags and args don't. +--- -show: -- And the third argument can be a file or $stdin or $stdout. +--- -show: clink.argmatcher("foo") +--- -show: :addflags( +--- -show:   "--help", +--- -show:   "--file"..clink.argmatcher():addarg({ clink.filematches }) +--- -show: ) +--- -show: :addarg({ "one", "won" }) +--- -show: :addarg({ "two", "too" }) +--- -show: :addarg({ clink.filematches, "$stdin", "$stdout" }) +--- You can use this function in an argmatcher to supply file matches. This +--- automatically handles Readline tilde completion.
+---
+--- Argmatchers default to matching files, so it's unusual to need this +--- function. However, some exceptions are when a flag needs to accept file +--- matches but other flags and arguments don't, or when matches need to include +--- more than files. +function clink.filematches(match_word) + local word = rl.expandtilde(match_word) + + local root = path.getdirectory(word) or "" + if expanded then + root = rl.collapsetilde(root) + end + + local matches = {} + for _, i in ipairs(os.globfiles(word.."*", true)) do + local m = path.join(root, i.name) + table.insert(matches, { match = m, type = i.type }) + end + return matches +end + --------------------------------------------------------------------------------