Skip to content

Commit

Permalink
Fix foo -x: argmatcher syntax.
Browse files Browse the repository at this point in the history
Clink 0.4.9 accidentally interpreted the next part as the next arg
position.  But that's because Clink and Readline got out of sync about
which word was being completed.

Clink 1.x didn't do any completion.  Although that was actually the
intended behavior, I want to strike a balance between compatibility and
reasonable behavior.

So now Clink recognizes the `-x:` flag syntax and does file completion,
and also colors the whole argument as a flag, regardless what follows
the `:` or `=` character.  To generate other matches, a lua script can
register a generator and provide code to handle the case.

This fixes issues #61 and #62.
  • Loading branch information
chrisant996 committed Jan 28, 2021
1 parent 0c94f28 commit 05d4daa
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 12 deletions.
2 changes: 0 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ _This todo list describes ChrisAnt996's current intended roadmap for Clink's fut
# RELEASE

## Issues
- Argmatcher should have a new mechanism for generating matches for `-foo:right_here` so that it doesn't treat it like an argument position. Maybe `"-foo:"+function_name`, and by default it uses `file_match_generator()`.
- Argmatcher should color `-foo:` as a Flag and `right_here` as Other.
- Provide a way for a custom classifier to apply a classification anywhere (not just to a pre-parsed word), and to apply any arbitrary CSI SGR code to a word or to anywhere.
- An unbound multi-char key sequence is fully ignored if it's the first key sequence in a chord. But if a chord is already being resolved, then an unbound multi-char key sequence (such as Right Arrow or Escape or etc) inserts whatever part of the key sequence failed to resolve. It should discard the full key sequence, just like when there's no chord being resolved yet.

Expand Down
2 changes: 1 addition & 1 deletion clink/lib/src/line_editor_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ unsigned int line_editor_impl::collect_words(words& words, matches_impl& matches
{
for (const char* walk = word_start; *walk && !isspace((unsigned char)*walk); walk++)
{
if (*walk == ':' || *walk == '=')
if (strchr(":=", *walk))
{
if (walk[1] &&
(rl_completer_quote_characters && strchr(rl_completer_quote_characters, walk[1])) ||
Expand Down
60 changes: 51 additions & 9 deletions clink/lua/scripts/arguments.lua
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,36 @@ function _argreader:update(word, word_index)
if arg._links and arg._links[word] then
t = arg_match_type
else
for _, i in ipairs(arg) do
if type(i) == "function" then
-- For performance reasons, don't run argmatcher functions
-- during classify. If that's needed, a script can provide
-- a :classify function to complement a :generate function.
t = 'o' --other (placeholder; superseded by :classifyword).
elseif i == word then
t = arg_match_type
break
-- For performance reasons, don't run argmatcher functions
-- during classify. If that's needed, a script can provide a
-- :classify function to complement a :generate function.
--
-- Also, when the word is a flag and contains : or = then check
-- if the portion up to and including the : or = is a known
-- flag. When so, color the whole thing as a flag.
--
local matched = false
if arg_match_type == "f" then
local attached_pos = word:find("[:=]")
if attached_pos then
local prefix = word:sub(1, attached_pos)
for _, i in ipairs(arg) do
if type(i) ~= "function" and i == prefix then
t = arg_match_type
matched = true
break
end
end
end
end
if not matched then
for _, i in ipairs(arg) do
if type(i) == "function" then
t = 'o' --other (placeholder; superseded by :classifyword).
elseif i == word then
t = arg_match_type
break
end
end
end
end
Expand Down Expand Up @@ -462,6 +483,21 @@ function _argmatcher:_generate(line_state, match_builder)
add_matches(matcher._flags._args[1], match_type)
return true
else
-- When endword is adjacent the previous word and the previous word ends
-- with : or = then this is a flag-attached arg, not an arg position.
if line_state:getwordcount() > 1 then
local prevwordinfo = line_state:getwordinfo(line_state:getwordcount() - 1)
local endwordinfo = line_state:getwordinfo(line_state:getwordcount())
if prevwordinfo.offset + prevwordinfo.length == endwordinfo.offset and
matcher:_is_flag(line_state:getword(line_state:getwordcount() - 1)) and
line_state:getline():sub(endwordinfo.offset - 1, endwordinfo.offset - 1):find("[:=]") then
-- FUTURE: Could have a new argmatcher syntax to generate
-- matches for "-x:" flags, but it's such a niche scenario that
-- it seems reasonable to require a custom :generate() function.
match_builder:addmatches(clink.filematches(line_state:getendword()))
return true
end
end
local arg = matcher._args[arg_index]
if arg then
return add_matches(arg, match_type) and true or false
Expand Down Expand Up @@ -769,6 +805,12 @@ function argmatcher_generator:getwordbreakinfo(line_state)
if argmatcher and argmatcher._flags then
local word = line_state:getendword()
if argmatcher:_is_flag(word) then
-- Accommodate `-flag:text` and `-flag=text` (with or without
-- quotes) so that matching can happen for the `text` portion.
local attached_arg,attach_pos = word:find("^[^:=][^:=]+[:=]")
if attached_arg then
return attach_pos, 0
end
return 0, 1
end
end
Expand Down

0 comments on commit 05d4daa

Please sign in to comment.