Search code examples
rustcommand-line-interfacefish

CLI tool written in rust occurs error when using completion of fish at the first time


Problem describe:

I have written a CLI tool for wsl to learn rust. It can open files using explorer.exe of Windows. I call it 'op'.

The problem is every time I open a new wsl and type 'op ' in fish shell, and use 'Tab' to get completions, then there will raise an error:

> op error: the directory does not exist
Oops: command not found
- (line 1):
Oops "./completion"
^~~^
from sourcing file -
        called on line 1 of file /usr/share/fish/completions/op.fish
from sourcing file /usr/share/fish/completions/op.fish

(Text 'op' is colored and others are white)

/usr/share/fish/completions/op.fish:

op completion fish | source

It seems relates to fish shell (3.6.0) (bash no bug because there is no completions). But this bug only occurs one time, command 'op' will make sense as expect after that.

I have a 'minigrep' which following the book. It run perfectly with no bug.

Source code (main.rs):

// This is a minimal frame
// The complete code is in https://github.com/GlekoMa/op
use std::env;
use std::path::Path;
use std::process::Command;

fn main() {
    // 0. get env args
    let args: Vec<String> = env::args().collect();

    // 1. convert args[1] to Path
    let path = Path::new(&args[1]);

    // 2. parse path to parent and file_name
    let parent = path.parent().unwrap();
    let file_name = path.file_name().unwrap().to_str().unwrap();

    // 3. cd parent path
    env::set_current_dir(parent).unwrap();

    // 4. execute open (using exeplorer.exe) cmd
    let cmd_open = format!("explorer.exe {file_name}");
    Command::new("sh").arg("-c").arg(cmd_open).output().unwrap();
}

Behavior expected:

Type 'op ' and use 'Tab' for completion will raise no error.


Update & Solution

Thanks to @faho, the source of this bug (is not related to the rust source code) is described below:

Somehow there is a completion fish script op.fish (generally is generated by software with same name.) in /usr/share/fish/completions. But my 'op' does not generate it, so this op.fish clashed with my 'op' for completion.

There are two simple ways to fix it:

  1. Rename 'op' (not by alias but by rebuilding).

  2. Write an empty file to ~/.config/fish/completions/op.fish so that fish will load it instead of /usr/share/fish/completions/op.fish.

I have used 2nd way and 'op' works well now!


Solution

  • Your code has a debug print:

    https://github.com/GlekoMa/op/blob/7ae843acbd37a3f64b162aaf4b984094c7be0aa8/src/main.rs#L17

    println!("Oops {:?}", path); // This code is for debug.
    

    This prints Oops ..., and so fish will, because you told it to source the output, attempt to run it as a command, and the command "Oops" won't exist and so it will print an error.

    This will only happen when the completions are loaded, which fish typically does the first time you try to complete something.

    Remove that debug statement, don't print it when generating the completions (i.e. you get the completion subcommand), print it to stderr instead (which means it will show up when the completions are loaded!) or prefix it with a // to make it a comment.