ros2cli: Autocomplete fails while using zsh.

Bug report

Required Info:

  • Operating System:
    • Ubuntu 18.04
  • Installation type:
    • binaries
  • Version or commit hash:
    • Dashing / Eloquent
  • DDS implementation:
    • ALL
  • Client library (if applicable):
    • N/A

Steps to reproduce issue

I use zsh as my shell, but I find some problems while using <tab> to autocomplete.

  • While I type ros2 run <tab>, it works well.
  • However when I type ros2 run d<tab>, it can’t show the packages which starts with ‘d’.

Additional information

After some debugging, I find that the behavior is related to argcomplete library in Python 3. If I remove the library rm -rf ~/.local/lib/python3.6/site-packages/argcomplete*, zsh works well again. I’m not pretty sure what the root cause is. Maybe argcomplete library does not support zsh well.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 6
  • Comments: 28 (11 by maintainers)

Most upvoted comments

Having the same issue with Zsh and ROS2 Galactic too.

But I found a solution in https://kislyuk.github.io/argcomplete/#zsh-support

By adding these lines to .zshrc the argcompletion is succesfully enabled.

# argcomplete for ros2 & colcon
eval "$(register-python-argcomplete3 ros2)"
eval "$(register-python-argcomplete3 colcon)"

(Thanks to https://github.com/ros2/ros2cli/issues/534#issuecomment-957905035, I removed the unnessecary autoload -U bashcompinit \ bashcompinit)

image

Instead of running eval "$(register-python-argcomplete3 ros2)" every time after sourcing setup.zsh, I made a modification in /opt/ros/galactic/share/rosidl_cli/environment/rosidl-argcomplete.zsh. I removed/commented the line:

autoload -U +X compinit && compinit

Then ros2 tab completion works. This has to do with compinit being called too many times (see also https://stackoverflow.com/questions/67136714/how-to-properly-call-compinit-and-bashcompinit-in-zsh ).

I’m not sure what a final fix should be, especially since tab completion for colcon still doesn’t work with this change (the eval "$(register-python-argcomplete3 colcon)" is still needed for that).

Having the same issue with Zsh and ROS2 Galactic too.

But I found a solution in https://kislyuk.github.io/argcomplete/#zsh-support

By adding these lines to .zshrc the argcompletion is succesfully enabled.

# argcomplete for ros2 & colcon
autoload -U bashcompinit
bashcompinit
eval "$(register-python-argcomplete3 ros2)"
eval "$(register-python-argcomplete3 colcon)"

image

That worked for me, thanks for sharing!

Huh, interesting. So it turns out that we are already calling eval "$(register-python-argcomplete ros2)" when sourcing for the zsh shell: https://github.com/ros2/ros2cli/blob/master/ros2cli/completion/ros2-argcomplete.zsh . And I verified locally that those files do indeed get sourced when source /opt/ros/rolling/setup.zsh. However, completion doesn’t work anyway; you have to re-run the eval, as everyone above found out.

Actually, I found out that after sourcing /opt/ros/rolling/setup.zsh, it is enough to do:

complete -o nospace -o default -F _python_argcomplete "ros2"

That suggests to me that something else later in the sourcing process is unregistering what was already registered. Someone would need to look deeper into it to find out exactly why this isn’t working as expected.

Hi, I’m having the same problem as @ferrolho with zsh version 5.8, and with both Foxy and Galaxy I’m unable to tab complete anything with the ros2 command.

I will add that zsh can tab complete parameters with any command except ros2. For example apt se<tab> will produce apt search, but ros2 lau<tab> will not complete to ros2 launch

Hi! I have just installed ROS 2 (Galactic) for the first time on my machine (Ubuntu 20.04). I am also a user of ZSH, and for some reason the autocomplete isn’t working; but it works on the Bash. Some more info:

➜  ~ zsh --version
zsh 5.8 (x86_64-ubuntu-linux-gnu)

➜  ~ which _bash_complete
_bash_complete () {
	local ret=1 
	local -a suf matches
	local -x COMP_POINT COMP_CWORD
	local -a COMP_WORDS COMPREPLY BASH_VERSINFO
	local -x COMP_LINE="$words" 
	local -A savejobstates savejobtexts
	(( COMP_POINT = 1 + ${#${(j. .)words[1,CURRENT-1]}} + $#QIPREFIX + $#IPREFIX + $#PREFIX ))
	(( COMP_CWORD = CURRENT - 1))
	COMP_WORDS=($words) 
	BASH_VERSINFO=(2 05b 0 1 release) 
	savejobstates=(${(kv)jobstates}) 
	savejobtexts=(${(kv)jobtexts}) 
	[[ ${argv[${argv[(I)nospace]:-0}-1]} = -o ]] && suf=(-S '') 
	matches=(${(f)"$(compgen $@ -- ${words[CURRENT]})"}) 
	if [[ -n $matches ]]
	then
		if [[ ${argv[${argv[(I)filenames]:-0}-1]} = -o ]]
		then
			compset -P '*/' && matches=(${matches##*/}) 
			compset -S '/*' && matches=(${matches%%/*}) 
			compadd -Q -f "${suf[@]}" -a matches && ret=0 
		else
			compadd -Q "${suf[@]}" -a matches && ret=0 
		fi
	fi
	if (( ret ))
	then
		if [[ ${argv[${argv[(I)default]:-0}-1]} = -o ]]
		then
			_default "${suf[@]}" && ret=0 
		elif [[ ${argv[${argv[(I)dirnames]:-0}-1]} = -o ]]
		then
			_directories "${suf[@]}" && ret=0 
		fi
	fi
	return ret
}

Fixed by #750

I am using Ubuntu 20.04 and Foxy, I have ZSH and oh-my-zsh installed. I needed to do the following to fix this issue.

pip install argcomplete
eval "$(register-python-argcomplete ros2)"
eval "$(register-python-argcomplete colcon)"

Maybe rather than removing the compinit call it should be replaced with a check and call? As far as I’ve tested, compinit sets the variable _comps, so it could be something like:

if (( ! ${+_comps} )); then
    autoload -U +X compinit && compinit
fi

This way neither completion script ordering nor the possible compinit call in .zshrc doesn’t matter.

Edit: NVM had similar problem, but I’m not sure whether their solution works as intended - it calls compinit either way but with a flag (?), which doesn’t change the fact that it clears previous completions.

For testing I removed the line autoload -U +X compinit && compinit from the following files:

/usr/share/colcon_argcomplete/hook/colcon-argcomplete.zsh
/opt/ros/humble/share/ros2cli/environment/ros2-argcomplete.zsh
/opt/ros/humble/share/ament_index_python/environment/ament_index-argcomplete.zsh
/opt/ros/humble/share/rosidl_cli/environment/rosidl-argcomplete.zsh

In order to make it work properly I have to add above line in my .zshrc before sourcing ROS workspace (and colcon-argcomplete). Whithout it it does not work. So it seems to be mandatory.

@hardesh I think I was on to something with compinit being called too often. What I hadn’t tried to figure out is why compinit is being called in rosidl-argcomplete.zsh, where else it’s being called, and what would be the right (single) spot to do it.

@dirk-thomas Thank you for the suggestion. The patch works perfectly!!! It frustrated me a long time about the argcomplete. You can close the issue if you think it’s OK.

I can reproduce the problem with Eloquent (using 5.4.2-3ubuntu3.1). In Foxy it is working though (using 5.8-3ubuntu1).

I think this is a duplicate of kislyuk/argcomplete#258. Either you use a newer version of zsh or you have to patch the function _bash_complete manually (https://github.com/zsh-users/zsh/commit/e2f793e7df7214cc3d80e2fcfe961ed087c860ab):

  • type which _bash_complete

  • copy-n-past the whole function, but insert the -1 to the following line:

    • Before: (( COMP_POINT = 1 + ${#${(j. .)words[1,CURRENT]}} + $#QIPREFIX + $#IPREFIX + $#PREFIX ))
    • After: (( COMP_POINT = 1 + ${#${(j. .)words[1,CURRENT-1]}} + $#QIPREFIX + $#IPREFIX + $#PREFIX ))