From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.3 required=5.0 tests=DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,DKIM_VALID,FREEMAIL_FROM,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 16721 invoked from network); 23 Mar 2021 08:57:26 -0000 Received: from zero.zsh.org (2a02:898:31:0:48:4558:7a:7368) by inbox.vuxu.org with ESMTPUTF8; 23 Mar 2021 08:57:26 -0000 ARC-Seal: i=1; cv=none; a=rsa-sha256; d=zsh.org; s=rsa-20200801; t=1616489846; b=ll9Om7vTc7WN9/ydcPXg+aJI+6oBW/4gGam/cCwTVmln6nOkVkO/oeci7ZG5i0x58mxBa5BqUF 1yShr8sJ6edZiDyYMEF9AottXLHQq4/MwdJD6Hu2KRK7P5hM+xBZKbJGpMKCmk5bc8PGfxwOsa iTMCek0PnfH0kpHBqJ+aZ1TWp3iLu1AmidLRVdNYKKLoysscv0pdyLtYPKi2lxOo/iZdfXOLQk JeUEnDO1uW2dkGSJKWnbFbRoLNrMu0Bw8kdwGmARTe+SrIiTil939psA31idRW8DDJWLbpnixo v1CHGVxf/8zCd7SzCvgCbeWpsxvU8LHxtVrkFlbhjYqI2w==; ARC-Authentication-Results: i=1; zsh.org; iprev=pass (mail-wr1-f43.google.com) smtp.remote-ip=209.85.221.43; dkim=pass header.d=gmail.com header.s=20161025 header.a=rsa-sha256; dmarc=pass header.from=gmail.com; arc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed; d=zsh.org; s=rsa-20200801; t=1616489846; bh=UM0d/E1bMaegPNc4/7RGd70VwcrmDtvqvcqULXgFmlE=; h=List-Archive:List-Owner:List-Post:List-Unsubscribe:List-Subscribe:List-Help: List-Id:Sender:Content-Transfer-Encoding:Content-Type:MIME-Version: Message-ID:Date:Subject:Cc:To:From:DKIM-Signature:DKIM-Signature; b=P3vHgSRfQMCXZyWCt9PZAHeWBpZdOzu6QyBDvzeEdmn7VVUnKUwWT2h3ESoN51shxREZ5yoDDZ t1FkHVyHpumEzg5Unqvh8W1uPwWMPuTr8elZD+Rnx86qlH6POzfWD7+dQPHPZiq1E1XAVXHRkx ujTOpmoF1Xqb4sCmjhiPaV8R+lHlM6rFFqnM5QQqHyRi/TutRtbX+qNeVh1gC7EajNrtbklx5o NQppSr8ggSpvbeWUbSQ50DUUDAKQJYy+/kVpXxpGq0uYWZNsl8Bv6lIeKgGvmJ/G1XJ6lfE7ha jY+To1S5H+eBC9OQsXx86HuqSdv1UCGF9F3guAZLV2jWww==; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zsh.org; s=rsa-20200801; h=List-Archive:List-Owner:List-Post:List-Unsubscribe: List-Subscribe:List-Help:List-Id:Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:Message-Id:Date:Subject:Cc:To:From:Reply-To: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References; bh=RgqtbWMIaxlDopyvDibWcvPj3IaOB017kIkxwAgJDS0=; b=hsBpS4CL2YOhf3X96lT/TxdExm Xg+KBLnRVxMcDu8WFcTO5z8LNFf0Bs7CpPMu4V6MCkXKsYTwE5BX/6U1+XMyXMAup9oebx3HpibHt AkDwkXj8pqPzMGH2C33NGL99ir4ylhfD3mdMO2h7Vbn1y9HFTjWpG5sVNcsyWFxXKX/nBLbBqGrYq JNbakhBobONTkIjlwcjZyUU0625zpEq7UFivVUSDlg6TM5S9sbmAZwquSjlwi3IV02yrKxbEbEraX VZ+Lu84A6JXbULfISebd/pw2Z35SYGrKc+copjkbOd+6V+b/jP6tk2WP6vXjs39ElGKUlEU28nyU3 KJZgG7WA==; Received: from authenticated user by zero.zsh.org with local id 1lOcqp-000OhR-Hg; Tue, 23 Mar 2021 08:57:23 +0000 Authentication-Results: zsh.org; iprev=pass (mail-wr1-f43.google.com) smtp.remote-ip=209.85.221.43; dkim=pass header.d=gmail.com header.s=20161025 header.a=rsa-sha256; dmarc=pass header.from=gmail.com; arc=none Received: from mail-wr1-f43.google.com ([209.85.221.43]:47099) by zero.zsh.org with esmtps (TLS1.3:TLS_AES_128_GCM_SHA256:128) id 1lOcqW-000OXu-Li; Tue, 23 Mar 2021 08:57:05 +0000 Received: by mail-wr1-f43.google.com with SMTP id v4so19895933wrp.13 for ; Tue, 23 Mar 2021 01:57:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=RgqtbWMIaxlDopyvDibWcvPj3IaOB017kIkxwAgJDS0=; b=RXY/gCbUxVSF9tbzTpZUrblsYk7yKlKOjJgL0b+ByvH0sFNGWPXS3YPrvrS2RYtjVu rqCe6nWiEe09sPObKCyQN1WZK50U67rs18bxa/W7Fl8cOveugKMDvdZL8nxRJXaG+Ao1 y8wlq9T0YC6MjwB7sza91gBzKZG+hMCW3TLu5Pniev2TCSEzeWbaVZw15AyDr+TkgPBq 5bM/WPpEJyqAJEcfDSsrN55Uc+SJDZeSh/03lj82ABkyhzCyel8JRKWRoTGz2eWOKIv/ PzpCVO1CJsRi8bJ7P2NQPr8yvQrIWNIEX9b5jIVDFcSLBbFkv+MKVHlmAJQfVM4q8IuT BnJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :mime-version:content-transfer-encoding; bh=RgqtbWMIaxlDopyvDibWcvPj3IaOB017kIkxwAgJDS0=; b=IFciCX4ZVl95ciU8CJsvkIPZVipziuoLHKbDgEnWqIb9hkNacUO1HloB6Mez/FJ/iz k2yUhYrB9jnpkAs6gDWUg2FtTEigJJ7IpFZ9vt0B0R0A7z9wW9tM6iHSTxQVLAaGYASI YCaxL+Lp445qihltHRKXMBreI2ShdkNpoCUNnhQd+1Z+o8zmzfelJ1hVBHFBWZloJna7 Atjt3hyAV8dqp8KM3Sqxc+E0zccDNOmF3fAIwKEHFti5g7EyS9nga+Y3+oe4+wMevksu CgjHSAaxkhYX6+NpIBuOoPYZ3CEgs6i9AtRPBsmJPmdJsmfu+eZ/WcdsocWZOfwkLy/R pNtA== X-Gm-Message-State: AOAM531vVu+u9fGiWzdKMDmdnuHKe71/f03XpqViayK+mngbXnojO7xW S9LFuoqiudtuK733a6Jmef22Ahprlgc= X-Google-Smtp-Source: ABdhPJy0g0T2jsbV4rWEz7UGxu31sBnPoPQg4f4uEHBV8j7K/iviM00nMpDX434Z6xPc5PrBH8U2dg== X-Received: by 2002:adf:e791:: with SMTP id n17mr2767288wrm.322.1616489823486; Tue, 23 Mar 2021 01:57:03 -0700 (PDT) Received: from biscuitbox.h.opandeq.com (p200300eef7160c0200000000000005f1.dip0.t-ipconnect.de. [2003:ee:f716:c02::5f1]) by smtp.gmail.com with ESMTPSA id j30sm24332767wrj.62.2021.03.23.01.57.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Mar 2021 01:57:03 -0700 (PDT) From: Syphdias To: zsh-workers@zsh.org Cc: Syphdias Subject: [PATCH] Fix _openstack completion for new style clients Date: Tue, 23 Mar 2021 09:56:39 +0100 Message-Id: <20210323085639.29974-1-syphdias+git@gmail.com> X-Mailer: git-send-email 2.30.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Seq: 48228 Archived-At: X-Loop: zsh-workers@zsh.org Errors-To: zsh-workers-owner@zsh.org Precedence: list Precedence: bulk Sender: zsh-workers-request@zsh.org X-no-archive: yes List-Id: List-Help: List-Subscribe: List-Unsubscribe: List-Post: List-Owner: List-Archive: Archived-At: 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 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