zsh-workers
 help / color / mirror / code / Atom feed
* OpenStack CLI completion
@ 2021-03-07 18:11 Christian K
  2021-03-08 15:58 ` Marko Myllynen
  0 siblings, 1 reply; 6+ messages in thread
From: Christian K @ 2021-03-07 18:11 UTC (permalink / raw)
  To: zsh-workers; +Cc: myllynen

Hi,

I stumbled upon a bug in the completion for openstack command
introduced in https://www.zsh.org/mla/workers/2016/msg01936.html

I noticed that the suggestions stop for further subcommands at a certain point.
An example:
`openstack vpn <tab>` offers "endpoint", "ike", "ipsec" and "service"
– perfect, selecting "ipsec"!
`openstack vpn ipsec <tab>` offers nothing – It should offer "policy",
"site" as can be seen here:

# I removed flag suggestions -* for readability reasons
❯ echo $_cache_openstack_clnt_outputs |grep cmds_vpn_ipsec |sed
"s/='-.*/='...'/"
  cmds_vpn_ipsec='policy site'
  cmds_vpn_ipsec_policy='create delete list set show'
  cmds_vpn_ipsec_policy_create='...'
  cmds_vpn_ipsec_policy_delete='...'
  cmds_vpn_ipsec_policy_list='...'
  cmds_vpn_ipsec_policy_set='...'
  cmds_vpn_ipsec_policy_show='...'
  cmds_vpn_ipsec_site='connection'
  cmds_vpn_ipsec_site_connection='create delete list set show'
  cmds_vpn_ipsec_site_connection_create='...'
  cmds_vpn_ipsec_site_connection_delete='...'
  cmds_vpn_ipsec_site_connection_list='...'
  cmds_vpn_ipsec_site_connection_set='...'
  cmds_vpn_ipsec_site_connection_show='...'

This issue continues after selecting "site"
`openstack vpn ipsec site <tab>` , no offers – should be "connection"
(only one, see above)
`openstack vpn ipsec site connection <tab>` no offers – should be
"create", "delete", "list", "set" and "show"

In the thread it was introduced in, there were some discussions
whether it should be included in zsh or in the openstack project. Is
there interest in a patch to fix this?

I have some idea how to fix this by making some assumptions but I am
not certain it's the right way. I would probably get rid of $subcmd
and just take the longest string of words connected by underscores as
$cmd to find the right suggestions.
Some barriers I currently have:
* There is also some substitution going on for colon which I just don't get
* Why is there a check for not prefix-needed?

Some comments from the original author would be quite helpful if he
still remembers why it was done a certain way :)

Best,
Christian


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: OpenStack CLI completion
  2021-03-07 18:11 OpenStack CLI completion Christian K
@ 2021-03-08 15:58 ` Marko Myllynen
  2021-03-18 22:45   ` Christian K
  0 siblings, 1 reply; 6+ messages in thread
From: Marko Myllynen @ 2021-03-08 15:58 UTC (permalink / raw)
  To: Christian K, zsh-workers

Hi Christian,

On 07/03/2021 20.11, Christian K wrote:
> 
> I stumbled upon a bug in the completion for openstack command
> introduced in https://www.zsh.org/mla/workers/2016/msg01936.html
> 
> I noticed that the suggestions stop for further subcommands at a certain point.
> An example:
> `openstack vpn <tab>` offers "endpoint", "ike", "ipsec" and "service"
> – perfect, selecting "ipsec"!
> `openstack vpn ipsec <tab>` offers nothing – It should offer "policy",
> "site" as can be seen here:
> 
> [...]
> 
> I have some idea how to fix this by making some assumptions but I am
> not certain it's the right way. I would probably get rid of $subcmd
> and just take the longest string of words connected by underscores as
> $cmd to find the right suggestions.
> Some barriers I currently have:
> * There is also some substitution going on for colon which I just don't get

I have a vague recollection that some (sub)command(s) had a slightly
inconsistent output with colons somewhere which had to be removed for
completions. Could have been just one or two such commands but
unfortunately I don't remember exactly anymore.

> * Why is there a check for not prefix-needed?
> 
> Some comments from the original author would be quite helpful if he
> still remembers why it was done a certain way :)

Hmm, this one I don't remember, I guess this might be a common
convention or something like that, probably not specific to _openstack.

I haven't dealt with OpenStack recently so I can't actually test
anything around it anymore but if you could fix the issue that would be
great.

Thanks,

-- 
Marko Myllynen



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: OpenStack CLI completion
  2021-03-08 15:58 ` Marko Myllynen
@ 2021-03-18 22:45   ` Christian K
  2021-03-19  9:37     ` Marko Myllynen
  0 siblings, 1 reply; 6+ messages in thread
From: Christian K @ 2021-03-18 22:45 UTC (permalink / raw)
  To: zsh-workers; +Cc: Marko Myllynen

[-- Attachment #1: Type: text/plain, Size: 1281 bytes --]

Hey,

> I have a vague recollection that some (sub)command(s) had a slightly
> inconsistent output with colons somewhere which had to be removed for
> completions. Could have been just one or two such commands but
> unfortunately I don't remember exactly anymore.

@Marko, I tried all clients I could find easily and could not find any
suggestions including colons. I cannot handle an error I don't know how to
throw. Please let me know if you remember an example.

> > * Why is there a check for not prefix-needed?
> >
> > Some comments from the original author would be quite helpful if he
> > still remembers why it was done a certain way :)
>
> Hmm, this one I don't remember, I guess this might be a common
> convention or something like that, probably not specific to _openstack.

I read up on it and I think it has something to do with how people configure
their completion preferences with `zstyle`. If you are a nice completion writer
you honor the setting. I hope I did it justice.

> I haven't dealt with OpenStack recently so I can't actually test
> anything around it anymore but if you could fix the issue that would be
> great.

I gave it a try. I ignored any colon issues for now. Would be great if someone
could.

So @list what do I need to do to get this merged?

[-- Attachment #2: 0001-Fix-_openstack-completion-for-new-style-clients.patch --]
[-- Type: text/x-patch, Size: 8533 bytes --]

From ecb7cbe49bce946bb4d6e919794af72f3d43014d Mon Sep 17 00:00:00 2001
From: Syphdias <syphdias+git@gmail.com>
Date: Thu, 18 Mar 2021 23:23:16 +0100
Subject: [PATCH] Fix _openstack completion for new style clients
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

I have rewritten the completion function for new style clients. It no longer
differentiates between command and sub command since this lead to a limited
depth for completion lookups. This gets rid of the extra global caching variable
`_cache_openstack_clnt_cmds`.  I tried to stay true to the prefix-needed
setting.

First I process the words left of the cursor. `words` did not provide this
granularity I needed so I opted to parse `LBUFFER` also for saving a partial
input/match for later. I remove `help` since everything after it is normal (sub)
command, so matches are identical to proper commands. Also I filter out every
flag/option.

To find the proper completion options I try one level at a time.
* $service
* $service $some_command
* $service $some_command $some_command_for_some_command
* etc.
You could probably do this in reverse to save time but I don't think it is worth
the effort.

I add the global options if `-` is used as a prefix at the current position.

Caveats:
* I know there are options like `--file`. The new implementation does not handle
  this – neither did the old one. For this level, I'd suggest the OpenStack team
  to provide official zsh completions
* Ignores everything right of the cursor so you can end up with command
  suggestion that are already on the right
* `openstack complete` gets completed now, old implementation ignored it
---
 Completion/Unix/Command/_openstack | 119 +++++++++++++++--------------
 1 file changed, 63 insertions(+), 56 deletions(-)

diff --git a/Completion/Unix/Command/_openstack b/Completion/Unix/Command/_openstack
index fcb704ac8..c12f25985 100644
--- a/Completion/Unix/Command/_openstack
+++ b/Completion/Unix/Command/_openstack
@@ -34,8 +34,6 @@ if (( ! $+_cache_openstack_clnt_opts )); then
   typeset -gA _cache_openstack_clnt_opts
   typeset -gA _cache_openstack_clnt_cmds
   typeset -gA _cache_openstack_clnt_cmds_opts
-  typeset -gA _cache_openstack_clnt_cmds_subcmds
-  typeset -gA _cache_openstack_clnt_cmds_subcmd_opts
 fi
 
 local -a conn_opts
@@ -61,65 +59,74 @@ if [[ -n ${clnts_compl_new[(r)$service]} ]]; then
     # Populate caches - clnt_outputs is command raw output used later
     _cache_openstack_clnt_outputs[$service]=${:-"$($service ${(Q)conn_opts} complete 2>/dev/null)"}
     _cache_openstack_clnt_opts[$service]=${${${${(M)${${${${=${(f)"$($service help 2>/dev/null)"}}/\[}/\]}/\;}:#-[-0-9A-Za-z]*}/,}/\.}%--os-}
-    _cache_openstack_clnt_cmds[$service]=${${${${_cache_openstack_clnt_outputs[$service]}/* cmds=\'}/\'*}/complete}
   fi
-  local cmd subcmd
-  # Determine the command
-  for word in ${words:1}; do
-    local s=${_cache_openstack_clnt_cmds[$service]}
-    [[ $s[(wI)$word] -gt 0 ]] && cmd=$word && break
+
+  # get worlds left of the curser into an array
+  local -a left_words
+  left_words=(${=LBUFFER})
+
+  # if curser is directly at a word (no space at the end),
+  # exclude the last word to offer right matches
+  # the last word could be a partial match that is later checked (prefix-needed)
+  local partial=""
+  if [[ "${LBUFFER[-1]}" != " " ]]; then
+    partial=${(@)left_words[-1]}
+    left_words=(${(@)left_words[1,$#left_words-1]})
+  fi
+  # remove $service
+  left_words=(${left_words:1})
+
+  # filter out "help"
+  if [[ $left_words[1] == help ]]; then
+    left_words=(${(@)left_words[2,$#left_words]})
+  fi
+
+  # filter out options (-*)
+  left_words=(${left_words//-*})
+
+  local -a subcmd_array cmds_array cache_key_array cache_values
+  subcmd_array=()
+  cmds_array=(cmds)
+  cache_key_array=(${service})
+  cache_values=()
+  local cache_key cmds
+  cache_key=""
+  cmds=""
+
+  # Check for matches one level at a time
+  # example: "" server create
+  for word in "" ${(@)left_words}; do                   # first loop  second loop        third loop
+    subcmd_array=(${(@)subcmd_array} ${word})           # ()          (server)           (server create)
+    cmds_array=(${(@)cmds_array} ${word})               # (cmds)      (cmds server)      (cmds server create)
+    cmds=${${(j:_:)cmds_array}/-/_}                     #  cmds        cmds_openstack     cmds_server_create
+    cache_key_array=(${(@)cache_key_array} ${word})     # (openstack) (openstack server) (openstack server create)
+    cache_key=${${(j:_:)cache_key_array}/-/_}           #  openstack   openstack_server   openstack_server_create
+
+    # lookup if current word is in cache_values of last elements
+    if [[ ${cache_values[(wI)${word}]} -gt 0 || $word == "" ]]; then
+      _cache_openstack_clnt_cmds[${cache_key}]=${${${_cache_openstack_clnt_outputs[${service}]}/* ${cmds}=\'}/\'*}
+    fi
+    # set cache_values for next loop
+    cache_values=${_cache_openstack_clnt_cmds[${cache_key}]}
   done
-  # Populate the subcommand cache
-  if [[ -n $cmd && -z $_cache_openstack_clnt_cmds_subcmds[$service$cmd] ]]; then
-      local t=cmds_${cmd//-/_}
-      _cache_openstack_clnt_cmds_subcmds[$service$cmd]=${${${_cache_openstack_clnt_outputs[$service]}/* $t=\'}/\'*}
-  fi
-  # Determine the subcommand
-  if [[ -n $cmd ]]; then
-    for word in ${words:2}; do
-      local s=${_cache_openstack_clnt_cmds_subcmds[$service$cmd]}
-      [[ $s[(wI)$word] -gt 0 ]] && subcmd=$word && break
-    done
-    # Populate subcommand option cache
-    if [[ -n $subcmd && -z $_cache_openstack_clnt_cmds_subcmd_opts[$service${cmd}--$subcmd] ]]; then
-      local t=cmds_${cmd//-/_}_${subcmd//-/_}
-      _cache_openstack_clnt_cmds_subcmd_opts[$service${cmd}--$subcmd]=${${${_cache_openstack_clnt_outputs[$service]}/* $t=\'}/\'*}
-    fi
-  fi
-  # Special treatment for the help command
-  if [[ $cmd == help ]]; then
-      if [[ $words[CURRENT-1] == $cmd && $words[CURRENT] != -* ]]; then
-        # Offer commands
-        [[ -n $_cache_openstack_clnt_cmds[$service] ]] && _values -w option ${(u)=_cache_openstack_clnt_cmds[$service]} && ret=0
-      elif [[ $words[CURRENT-2] == $cmd && $words[CURRENT-1] != -* && $words[CURRENT] != -* ]]; then
-        # Offer subcommands
-        local cmd=$words[CURRENT-1]
-        local t=cmds_${cmd//-/_}
-        [[ -z $_cache_openstack_clnt_cmds_subcmds[$service$cmd] ]] && _cache_openstack_clnt_cmds_subcmds[$service$cmd]=${${${_cache_openstack_clnt_outputs[$service]}/* $t=\'}/\'*}
-        [[ -n $_cache_openstack_clnt_cmds_subcmds[$service$cmd] ]] && _values -w option ${(u)=_cache_openstack_clnt_cmds_subcmds[$service$cmd]} && ret=0
-      else
-        # Handle help<TAB> properly
-        _values -w option help && ret=0
-      fi
-  # Client options
-  elif [[ -z $cmd && $words[CURRENT] == -* ]]; then
-    _values -w option ${(u)=_cache_openstack_clnt_opts[$service]} && ret=0
-  # Commands
-  elif [[ -z $cmd ]]; then
-    if [[ -z $_cache_openstack_clnt_cmds[$service] ]]; then
-      _message "missing authentication options"
-    else
-      _values -w option ${(u)=_cache_openstack_clnt_cmds[$service]} && ret=0
-    fi
-  # Subcommands
-  elif [[ -z $subcmd ]]; then
-    [[ -n $_cache_openstack_clnt_cmds_subcmds[$service$cmd] ]] && _values -w option ${(u)=_cache_openstack_clnt_cmds_subcmds[$service$cmd]} && ret=0
-  # Subcommand options
+
+  # Populate the command cache
+  if [[ -z $_cache_openstack_clnt_cmds[${cache_key}] ]]; then
+    _message "missing authentication options"
   else
-    { ! zstyle -T ":completion:${curcontext}:options" prefix-needed || [[ -prefix - ]] } && \
-      [[ -n $_cache_openstack_clnt_cmds_subcmd_opts[$service${cmd}--$subcmd] ]] && _values -w option ${(u)=_cache_openstack_clnt_cmds_subcmd_opts[$service${cmd}--$subcmd]//\:/\\\:} && ret=0
+    # add global options to completion list if current word start with -*
+    local extra_opts
+    if [[ $words[CURRENT] == -* ]]; then;
+      extra_opts=${_cache_openstack_clnt_opts[$service]}
+    fi
+
+    { ! zstyle -T ":completion:${curcontext}:options" prefix-needed \
+          || [[ -n "${partial}" && ${${_cache_openstack_clnt_cmds[${cache_key}]}[(Iw)${partial}*]} -gt 0 || -prefix - ]] } \
+      && _values -w option ${(u)=_cache_openstack_clnt_cmds[${cache_key}]} ${(u)=extra_opts} \
+      && ret=0
   fi
 
+
 # Old style clients
 elif [[ -n ${clnts_compl_old[(r)$service]} ]]; then
   if [[ -z $_cache_openstack_clnt_cmds[$service] ]]; then
-- 
2.30.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: OpenStack CLI completion
  2021-03-18 22:45   ` Christian K
@ 2021-03-19  9:37     ` Marko Myllynen
  2021-03-19 22:05       ` Christian K
  0 siblings, 1 reply; 6+ messages in thread
From: Marko Myllynen @ 2021-03-19  9:37 UTC (permalink / raw)
  To: Christian K, zsh-workers

Hi,

On 19/03/2021 00.45, Christian K wrote:
> 
>> I have a vague recollection that some (sub)command(s) had a slightly
>> inconsistent output with colons somewhere which had to be removed for
>> completions. Could have been just one or two such commands but
>> unfortunately I don't remember exactly anymore.
> 
> @Marko, I tried all clients I could find easily and could not find any
> suggestions including colons. I cannot handle an error I don't know how to
> throw. Please let me know if you remember an example.
I think I remember swift and perhaps one or two being somewhat different
that the rest. But it might be also that it was a client which has since
then become obsolete. Or perhaps it was added needlessly in the first place.

Given that you've tested it with all recent client version I'd say it
should be safe to drop today.

Thanks,

-- 
Marko Myllynen



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: OpenStack CLI completion
  2021-03-19  9:37     ` Marko Myllynen
@ 2021-03-19 22:05       ` Christian K
  2021-03-27 16:31         ` Lawrence Velázquez
  0 siblings, 1 reply; 6+ messages in thread
From: Christian K @ 2021-03-19 22:05 UTC (permalink / raw)
  To: Marko Myllynen; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 706 bytes --]

> > @Marko, I tried all clients I could find easily and could not find any
> > suggestions including colons. I cannot handle an error I don't know how to
> > throw. Please let me know if you remember an example.
> I think I remember swift and perhaps one or two being somewhat different
> that the rest. But it might be also that it was a client which has since
> then become obsolete. Or perhaps it was added needlessly in the first place.

swift should not be affected since it is in the "swift like" category
and not new style.

> Given that you've tested it with all recent client version I'd say it
> should be safe to drop today.

I'd prefer more testers. :)

I found another small bug and fixed it.

[-- Attachment #2: 0001-Fix-_openstack-completion-for-new-style-clients.patch --]
[-- Type: text/x-patch, Size: 8675 bytes --]

From d408532eb84988d2e565f4b097571b832b8ed172 Mon Sep 17 00:00:00 2001
From: Syphdias <syphdias+git@gmail.com>
Date: Thu, 18 Mar 2021 23:23:16 +0100
Subject: [PATCH] Fix _openstack completion for new style clients
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

I have rewritten the completion function for new style clients. It no longer
differentiates between command and sub command since this lead to a limited
depth for completion lookups. This gets rid of the extra global caching variable
`_cache_openstack_clnt_cmds`.  I tried to stay true to the prefix-needed
setting.

First I process the words left of the cursor. `words` did not provide this
granularity I needed so I opted to parse `LBUFFER` also for saving a partial
input/match for later. I remove `help` since everything after it is normal (sub)
command, so matches are identical to proper commands. Also I filter out every
flag/option.

To find the proper completion options I try one level at a time.
* $service
* $service $some_command
* $service $some_command $some_command_for_some_command
* etc.
You could probably do this in reverse to save time but I don't think it is worth
the effort.

I add the global options if `-` is used as a prefix at the current position.

Caveats:
* I know there are options like `--file`. The new implementation does not handle
  this – neither did the old one. For this level, I'd suggest the OpenStack team
  to provide official zsh completions
* Ignores everything right of the cursor so you can end up with command
  suggestion that are already on the right
* `openstack complete` gets completed now, old implementation ignored it
---
 Completion/Unix/Command/_openstack | 117 ++++++++++++++++-------------
 1 file changed, 64 insertions(+), 53 deletions(-)

diff --git a/Completion/Unix/Command/_openstack b/Completion/Unix/Command/_openstack
index fcb704ac8..d55686b80 100644
--- a/Completion/Unix/Command/_openstack
+++ b/Completion/Unix/Command/_openstack
@@ -34,8 +34,6 @@ if (( ! $+_cache_openstack_clnt_opts )); then
   typeset -gA _cache_openstack_clnt_opts
   typeset -gA _cache_openstack_clnt_cmds
   typeset -gA _cache_openstack_clnt_cmds_opts
-  typeset -gA _cache_openstack_clnt_cmds_subcmds
-  typeset -gA _cache_openstack_clnt_cmds_subcmd_opts
 fi
 
 local -a conn_opts
@@ -61,65 +59,78 @@ if [[ -n ${clnts_compl_new[(r)$service]} ]]; then
     # Populate caches - clnt_outputs is command raw output used later
     _cache_openstack_clnt_outputs[$service]=${:-"$($service ${(Q)conn_opts} complete 2>/dev/null)"}
     _cache_openstack_clnt_opts[$service]=${${${${(M)${${${${=${(f)"$($service help 2>/dev/null)"}}/\[}/\]}/\;}:#-[-0-9A-Za-z]*}/,}/\.}%--os-}
-    _cache_openstack_clnt_cmds[$service]=${${${${_cache_openstack_clnt_outputs[$service]}/* cmds=\'}/\'*}/complete}
   fi
-  local cmd subcmd
-  # Determine the command
-  for word in ${words:1}; do
-    local s=${_cache_openstack_clnt_cmds[$service]}
-    [[ $s[(wI)$word] -gt 0 ]] && cmd=$word && break
-  done
-  # Populate the subcommand cache
-  if [[ -n $cmd && -z $_cache_openstack_clnt_cmds_subcmds[$service$cmd] ]]; then
-      local t=cmds_${cmd//-/_}
-      _cache_openstack_clnt_cmds_subcmds[$service$cmd]=${${${_cache_openstack_clnt_outputs[$service]}/* $t=\'}/\'*}
+
+  # get worlds left of the curser into an array
+  local -a left_words
+  left_words=(${=LBUFFER})
+
+  # if curser is directly at a word (no space at the end),
+  # exclude the last word to offer right matches
+  # the last word could be a partial match that is later checked (prefix-needed)
+  local partial=""
+  if [[ "${LBUFFER[-1]}" != " " ]]; then
+    partial=${(@)left_words[-1]}
+    left_words=(${(@)left_words[1,$#left_words-1]})
   fi
-  # Determine the subcommand
-  if [[ -n $cmd ]]; then
-    for word in ${words:2}; do
-      local s=${_cache_openstack_clnt_cmds_subcmds[$service$cmd]}
-      [[ $s[(wI)$word] -gt 0 ]] && subcmd=$word && break
-    done
-    # Populate subcommand option cache
-    if [[ -n $subcmd && -z $_cache_openstack_clnt_cmds_subcmd_opts[$service${cmd}--$subcmd] ]]; then
-      local t=cmds_${cmd//-/_}_${subcmd//-/_}
-      _cache_openstack_clnt_cmds_subcmd_opts[$service${cmd}--$subcmd]=${${${_cache_openstack_clnt_outputs[$service]}/* $t=\'}/\'*}
-    fi
+  # remove $service
+  left_words=(${left_words:1})
+
+  # filter out "help"
+  if [[ $left_words[1] == help ]]; then
+    left_words=(${(@)left_words[2,$#left_words]})
   fi
-  # Special treatment for the help command
-  if [[ $cmd == help ]]; then
-      if [[ $words[CURRENT-1] == $cmd && $words[CURRENT] != -* ]]; then
-        # Offer commands
-        [[ -n $_cache_openstack_clnt_cmds[$service] ]] && _values -w option ${(u)=_cache_openstack_clnt_cmds[$service]} && ret=0
-      elif [[ $words[CURRENT-2] == $cmd && $words[CURRENT-1] != -* && $words[CURRENT] != -* ]]; then
-        # Offer subcommands
-        local cmd=$words[CURRENT-1]
-        local t=cmds_${cmd//-/_}
-        [[ -z $_cache_openstack_clnt_cmds_subcmds[$service$cmd] ]] && _cache_openstack_clnt_cmds_subcmds[$service$cmd]=${${${_cache_openstack_clnt_outputs[$service]}/* $t=\'}/\'*}
-        [[ -n $_cache_openstack_clnt_cmds_subcmds[$service$cmd] ]] && _values -w option ${(u)=_cache_openstack_clnt_cmds_subcmds[$service$cmd]} && ret=0
-      else
-        # Handle help<TAB> properly
-        _values -w option help && ret=0
-      fi
-  # Client options
-  elif [[ -z $cmd && $words[CURRENT] == -* ]]; then
-    _values -w option ${(u)=_cache_openstack_clnt_opts[$service]} && ret=0
-  # Commands
-  elif [[ -z $cmd ]]; then
-    if [[ -z $_cache_openstack_clnt_cmds[$service] ]]; then
-      _message "missing authentication options"
+
+  # filter out options (-*)
+  left_words=(${left_words//-*})
+
+  local -a subcmd_array cmds_array cache_key_array cache_values
+  subcmd_array=()
+  cmds_array=(cmds)
+  cache_key_array=(${service})
+  cache_values=()
+  local cache_key cmds
+  cache_key=""
+  cmds=""
+
+  # Check for matches one level at a time
+  # example: "" server create
+  for word in "" ${(@)left_words}; do                   # first loop  second loop        third loop
+    subcmd_array=(${(@)subcmd_array} ${word})           # ()          (server)           (server create)
+    cmds_array=(${(@)cmds_array} ${word})               # (cmds)      (cmds server)      (cmds server create)
+    cmds=${${(j:_:)cmds_array}/-/_}                     #  cmds        cmds_openstack     cmds_server_create
+    cache_key_array=(${(@)cache_key_array} ${word})     # (openstack) (openstack server) (openstack server create)
+    cache_key=${${(j:_:)cache_key_array}/-/_}           #  openstack   openstack_server   openstack_server_create
+
+    # lookup if current word is in cache_values of last elements
+    if [[ ${cache_values[(wI)${word}]} -gt 0 || $word == "" ]]; then
+      _cache_openstack_clnt_cmds[${cache_key}]=${${${_cache_openstack_clnt_outputs[${service}]}/* ${cmds}=\'}/\'*}
     else
-      _values -w option ${(u)=_cache_openstack_clnt_cmds[$service]} && ret=0
+      # unknown word: set cache_key to last cache_key and break
+      cache_key=${${(j:_:)${cache_key_array:0:${#cache_key_array}-1}}/-/_}
+      break
     fi
-  # Subcommands
-  elif [[ -z $subcmd ]]; then
-    [[ -n $_cache_openstack_clnt_cmds_subcmds[$service$cmd] ]] && _values -w option ${(u)=_cache_openstack_clnt_cmds_subcmds[$service$cmd]} && ret=0
-  # Subcommand options
+    # set cache_values for next loop
+    cache_values=${_cache_openstack_clnt_cmds[${cache_key}]}
+  done
+
+  # Populate the command cache
+  if [[ -z $_cache_openstack_clnt_cmds[${cache_key}] ]]; then
+    _message "missing authentication options"
   else
-    { ! zstyle -T ":completion:${curcontext}:options" prefix-needed || [[ -prefix - ]] } && \
-      [[ -n $_cache_openstack_clnt_cmds_subcmd_opts[$service${cmd}--$subcmd] ]] && _values -w option ${(u)=_cache_openstack_clnt_cmds_subcmd_opts[$service${cmd}--$subcmd]//\:/\\\:} && ret=0
+    # add global options to completion list if current word start with -*
+    local extra_opts
+    if [[ $words[CURRENT] == -* ]]; then;
+      extra_opts=${_cache_openstack_clnt_opts[$service]}
+    fi
+
+    { ! zstyle -T ":completion:${curcontext}:options" prefix-needed \
+          || [[ -n "${partial}" && ${${_cache_openstack_clnt_cmds[${cache_key}]}[(Iw)${partial}*]} -gt 0 || -prefix - ]] } \
+      && _values -w option ${(u)=_cache_openstack_clnt_cmds[${cache_key}]} ${(u)=extra_opts} \
+      && ret=0
   fi
 
+
 # Old style clients
 elif [[ -n ${clnts_compl_old[(r)$service]} ]]; then
   if [[ -z $_cache_openstack_clnt_cmds[$service] ]]; then
-- 
2.30.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: OpenStack CLI completion
  2021-03-19 22:05       ` Christian K
@ 2021-03-27 16:31         ` Lawrence Velázquez
  0 siblings, 0 replies; 6+ messages in thread
From: Lawrence Velázquez @ 2021-03-27 16:31 UTC (permalink / raw)
  To: zsh-workers; +Cc: Christian K, Marko Myllynen

On Fri, Mar 19, 2021, at 6:05 PM, Christian K wrote:
> > > @Marko, I tried all clients I could find easily and could not find any
> > > suggestions including colons. I cannot handle an error I don't know how to
> > > throw. Please let me know if you remember an example.
> > I think I remember swift and perhaps one or two being somewhat different
> > that the rest. But it might be also that it was a client which has since
> > then become obsolete. Or perhaps it was added needlessly in the first place.
> 
> swift should not be affected since it is in the "swift like" category
> and not new style.
> 
> > Given that you've tested it with all recent client version I'd say it
> > should be safe to drop today.
> 
> I'd prefer more testers. :)
> 
> I found another small bug and fixed it.

ping for review

vq


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-03-27 16:32 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-07 18:11 OpenStack CLI completion Christian K
2021-03-08 15:58 ` Marko Myllynen
2021-03-18 22:45   ` Christian K
2021-03-19  9:37     ` Marko Myllynen
2021-03-19 22:05       ` Christian K
2021-03-27 16:31         ` Lawrence Velázquez

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).