[Rust] Stuck on #CZ2 after a long time | stdout doesn't work properly

I’m stuck on Stage #CZ2.

After a long time I decided to continue and had many problems with the challenge. Looks like there is a new build pipeline. I copied the necessary code from another repo and gave executable permissions to them. I was trying to implement auto completion but now tester can’t even write anything to the shell in the raw mode.

Here are my logs:

[tester::#CZ2] Running tests for Stage #CZ2 (Handle invalid commands)
[tester::#CZ2] Running ./your_program.sh
[your-program] $ 
[tester::#CZ2] ^ Line does not match expected value.
[tester::#CZ2] Expected: "$ invalid_raspberry_command"
[tester::#CZ2] Received: "$ " (trailing space)
[tester::#CZ2] Test failed

And here’s a snippet of my code:

src/shell.rs

use std::io::{self, Error, ErrorKind, Stderr, Stdout, Write};

use core::{ShellCommandProvider, ShellInterpreter, ShellTokenizer};
use crossterm::{
    execute,
    style::Print,
    terminal::{disable_raw_mode, enable_raw_mode},
};

pub mod core;

pub struct Shell {
    pub(crate) buffer: String,
    pub(crate) stdout: Stdout,
    pub(crate) stderr: Stderr,

    // Auto Complete
    pub(crate) tab_query: String,
    pub(crate) tab_index: u8,
    // history: Vec<String>,
}

impl Shell {
    pub fn new() -> Self {
        Self {
            buffer: String::new(),
            stdout: io::stdout(),
            stderr: io::stderr(),
            tab_index: 0,
            tab_query: String::new(),
            // history: Vec::new(),
        }
    }

    pub async fn run<
        T,
        I: ShellInterpreter<T>,
        C: ShellCommandProvider<T>,
        K: ShellTokenizer<T>,
    >(
        &mut self,
    ) -> Result<(), Error> {
        self.init()?;
        self.stdout.flush()?;

        loop {
            let result = self.handle_event::<T, I, C, K>();

            if result.is_err() && result.unwrap_err().kind() == ErrorKind::Interrupted {
                break;
            }

            self.stdout.flush()?;
        }

        self.uninit()?;

        Ok(())
    }

    fn init(&mut self) -> Result<(), Error> {
        enable_raw_mode()?;

        execute!(self.stdout, Print("$ "),)?;
        Ok(())
    }

    fn uninit(&mut self) -> Result<(), Error> {
        disable_raw_mode()?;

        execute!(self.stdout)?;
        Ok(())
    }
}

src/modules/event_handler/key_handler/ch.rs

use crossterm::{
    cursor::{self, MoveToColumn},
    execute,
    style::Print,
    terminal::{Clear, ClearType},
};

use crate::shell::Shell;
use std::io::Error;

impl Shell {
    pub(crate) fn handle_ch(&mut self, ch: char) -> Result<(), Error> {
        let relative_cursor_x = cursor::position()?.0 as usize - super::PREFIX.len();

        if relative_cursor_x < self.buffer.len() {
            self.buffer.insert(relative_cursor_x, ch);

            execute!(
                self.stdout,
                Clear(ClearType::CurrentLine),
                MoveToColumn(0),
                Print(super::PREFIX),
                Print(&self.buffer),
                MoveToColumn((relative_cursor_x + 3) as u16)
            )?;
        } else {
            self.buffer.push(ch);
            execute!(self.stdout, Print(ch))?;
        }

        self.tab_index = 0;
        self.tab_query = String::new();
        Ok(())
    }
}

Here’s the repo link:

Hey @emrecancorapci, looks like there might be an issue with cursor::position(). Could you confirm whether it’s working as expected on your end?

I’m not an expert on Rust, so I might be missing something. Let me know what you find.