Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to setup autocompletion? #288

Open
muellerbernd opened this issue Aug 9, 2023 · 14 comments
Open

how to setup autocompletion? #288

muellerbernd opened this issue Aug 9, 2023 · 14 comments

Comments

@muellerbernd
Copy link
Contributor

I am using this overlay for ros1 and ros2 development. For ros1 autocompletion was enable after sourcing devel/setup.zsh . For ros2 someting like eval "$(register-python-argcomplete colcon)" would be needed (see this issue).
What is the best way to setup autocompletion for ros1 and ros2? Can I setup autocompletion in the mkshell shell-hook?

@hacker1024
Copy link
Contributor

hacker1024 commented Aug 9, 2023

Yep, in the shell hook will work nicely. Be aware that argcomplete was only listed as a ROS 2 CLI dependency fairly recently, so anything older than Humble will need an override to add it.

# Add argcomplete as a propagated ros2cli dependency.
# https://github.com/ros2/ros2cli/pull/564
# https://github.com/ros2/ros2cli/blob/26715cbb0948258d6f04b94c909d035c5130456a/ros2cli/ros2cli/cli.py#L45
ros2cli = rosSuper.ros2cli.overrideAttrs ({ propagatedBuildInputs ? [ ], ... }: {
  propagatedBuildInputs = propagatedBuildInputs ++ [ rosSelf.pythonPackages.argcomplete ];
});

@muellerbernd
Copy link
Contributor Author

muellerbernd commented Aug 9, 2023

and how would I do that? For ros2 I tried to use the following in my setup

  shellHook = ''
    eval ${pkgs.python310Packages.argcomplete}/bin/register-python-argcomplete ros2
    eval ${pkgs.python310Packages.argcomplete}/bin/register-python-argcomplete colcon
    eval ${pkgs.python310Packages.argcomplete}/bin/register-python-argcomplete rosidl
  '';

@hacker1024
Copy link
Contributor

hacker1024 commented Aug 9, 2023

That looks good to me. I have a more developed setup here (see the shell hook and setup script): https://github.com/hacker1024/nix-ros-workspace/blob/master/packages/ros/build-ros-workspace/default.nix

@muellerbernd muellerbernd changed the title how to setup autocomplete? how to setup autocompletion? Aug 9, 2023
@muellerbernd
Copy link
Contributor Author

muellerbernd commented Aug 9, 2023

Yeah I saw your repo and took inspirations from there for my shell hook. But the autocompletion does not work.
When I build my flake, change into it and call the following by hand then autocompletion works.

eval "$(register-python-argcomplete ros2)"
eval "$(register-python-argcomplete colcon)"
eval "$(register-python-argcomplete rosidl)"

But it does not work when I put these commands into my shellHook.

@muellerbernd
Copy link
Contributor Author

muellerbernd commented Aug 15, 2023

@hacker1024 I got it working using the setup script from your setup. But it only works with bash when I use zsh it does not work. Do you have any tips on how to get it working with zsh?

It works when I call eval "$(mk-workspace-shell-setup)" after I got into zsh.

@hacker1024
Copy link
Contributor

It works when I call eval "$(mk-workspace-shell-setup)" after I got into zsh.

That is expected. The shellHook does not run directly in Zsh, but rather in Bash before launching Zsh. This allows environment variables to be set, but does not allow any shell-specific setup to be done. This means that completion cannot be set up automatically.

@liarokapisv
Copy link
Contributor

liarokapisv commented Dec 28, 2024

Leaving a few tips on how to automatically setup zsh autocompletion.

As hacker1024 said, this is a general issue with non-bash shells integration with shellHook.
shellHook is actually run in a bash environment and then the environment is exported and then sourced from the
active shell. This obviously breaks autocomplete functionality.

What you want to do is rely on native shell auto-complete script discovery.
This is supposed to be achieved through XDG_DATA_DIRS, but zsh instead looks into FPATH so that's a bit unfortunate.

stdenv's setup hook will take care to properly set the XDG_DATA_DIRS env variable from $out/share folders present in dependencies. This means that adding a simple derivation, like below in your shell's packages, will properly create the directories and set XDG_DATA_DIRS properly.

  (pkgs.runCommand "ros-autocompletions" { } ''
    for dir in {bash-completion/completions,zsh/site-functions}; do
        mkdir -p $out/share/$dir
        for program in {ros2,colcon,rosidl}; do
            ${pkgs.python3.pkgs.argcomplete}/bin/register-python-argcomplete $program > $out/share/$dir/_$program
        done
    done
  '')

(Ideally these should be part of the corresponding packages' derivations)

You can use the zsh-completion-sync plugin, which will take care of fetching the proper dirs from XDG_DATA_DIR, populating FPATH and then calling compinit dynamically.

@muellerbernd
Copy link
Contributor Author

@liarokapisv Thanks for your reply on this issue. Can you give a minimal working example?

@liarokapisv
Copy link
Contributor

Basically, just put the above derivation in your mkShell's packages. Below is an example flake:

{
  inputs = {
    ros-overlay.url = "github:lopsided98/nix-ros-overlay/master";
    nixpkgs.follows = "ros-overlay/nixpkgs";
  };

  outputs = { self, nixpkgs, ros-overlay, ... }:
    let
      forAllSystems = (f: nixpkgs.lib.genAttrs [ "x86_64-linux" ] (system:
        let
          pkgs = import nixpkgs {
            inherit system;
            overlays = [ self.overlays.default ];
          };
          ros-distro = pkgs.rosPackages.jazzy;
        in
        f {
          inherit system pkgs ros-distro;
        })
      );
    in
    {
      overlays.default = ros-overlay.overlays.default;

      devShells = forAllSystems
        ({ pkgs, ros-distro, ... }:
          {
            default =
              pkgs.mkShell
                {
                  name = "ros-shell";
                  packages = with pkgs; [
                    ros-distro.ros-core
                    colcon
                    (pkgs.runCommand "ros-autocompletions" { } ''
                      for dir in {bash-completion/completions,zsh/site-functions}; do
                          mkdir -p $out/share/$dir
                          for program in {ros2,colcon,rosidl}; do
                              ${pkgs.python3.pkgs.argcomplete}/bin/register-python-argcomplete $program > $out/share/$dir/_$program
                          done
                      done
                    '')
                  ];
                };
          });
    };
}

Then just add the zsh-completion-sync plugin to your zsh config.

@muellerbernd
Copy link
Contributor Author

Basically, just put the above derivation in your mkShell's packages. Below is an example flake:

{
  inputs = {
    ros-overlay.url = "github:lopsided98/nix-ros-overlay/master";
    nixpkgs.follows = "ros-overlay/nixpkgs";
  };

  outputs = { self, nixpkgs, ros-overlay, ... }:
    let
      forAllSystems = (f: nixpkgs.lib.genAttrs [ "x86_64-linux" ] (system:
        let
          pkgs = import nixpkgs {
            inherit system;
            overlays = [ self.overlays.default ];
          };
          ros-distro = pkgs.rosPackages.jazzy;
        in
        f {
          inherit system pkgs ros-distro;
        })
      );
    in
    {
      overlays.default = ros-overlay.overlays.default;

      devShells = forAllSystems
        ({ pkgs, ros-distro, ... }:
          {
            default =
              pkgs.mkShell
                {
                  name = "ros-shell";
                  packages = with pkgs; [
                    ros-distro.ros-core
                    colcon
                    (pkgs.runCommand "ros-autocompletions" { } ''
                      for dir in {bash-completion/completions,zsh/site-functions}; do
                          mkdir -p $out/share/$dir
                          for program in {ros2,colcon,rosidl}; do
                              ${pkgs.python3.pkgs.argcomplete}/bin/register-python-argcomplete $program > $out/share/$dir/_$program
                          done
                      done
                    '')
                  ];
                };
          });
    };
}

Then just add the zsh-completion-sync plugin to your zsh config.

Works for me. Thanks for this tip.

@GeFrIt42
Copy link

GeFrIt42 commented Jan 11, 2025

hi,
if you use pkgs.mkShell you could just add the shellHook, so when the shell starts it will initialize the autocomplete for you.
I have tested this with the flake.nix on the root of this repo.

          shellHook = ''
            eval "$(register-python-argcomplete ros2)"
            eval "$(register-python-argcomplete colcon)"
          '';

@liarokapisv
Copy link
Contributor

hi, if you use pkgs.mkShell you could just add the shellHook, so when the shell starts it will initialize the autocomplete for you. I have tested this with the flake.nix on the root of this repo.

          shellHook = ''
            eval "$(register-python-argcomplete ros2)"
            eval "$(register-python-argcomplete colcon)"
          '';

This only works if you are using bash as a shell.

@GeFrIt42
Copy link

GeFrIt42 commented Jan 11, 2025

hi, if you use pkgs.mkShell you could just add the shellHook, so when the shell starts it will initialize the autocomplete for you. I have tested this with the flake.nix on the root of this repo.

          shellHook = ''
            eval "$(register-python-argcomplete ros2)"
            eval "$(register-python-argcomplete colcon)"
          '';

This only works if you are using bash as a shell.

You are right:

  • It is not clear to me how argcomplete is implemented, but it seems that the registered completion do not get carried to the child shells, which means that the register commands need to be executed per shell.
  • At the moment there is no way to tell to nix shell to use a different shell other than bash link . in order to swap shell you have to start it from bash in the shellHook.

I see also that The previous solutions have a dependencies to the zsh-completion-sync that is not part of default omz plugins, it requires a little more configuration on the system level.

Would it be a good thing to have the shellHook solution merged in the README.md ?
It is not perfect, but it is more self contained and short, it would allow beginners to have the completion in bash.

@liarokapisv
Copy link
Contributor

If we add the autocomplete support to the appropriate packages (by adding the argcomplete files in the output), then it should automatically work for bash users without them having to add anything to the shellHook. Zsh / fish users can optionally add the corresponding sync package to their configuration to also take advantage of the support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants