ruststdoutstdinneovimlanguage-server-protocol

How can I read from neovim's stdin, using rust?


I'm pretty new to rust and I thought I could get some help here.

I'm trying to follow a guide about making LSPs from TJ DeVries, he is coding it in Go but I'm trying to follow along in Rust. I'm stuck at the part where he is reading input from neovim's stdout. Neovim should send JSON-RPC messages to my program's stdin. Right now all I'm trying to do is read what I'm getting from neovim and print it to a file.

I already have a logger set up, all it does is add text to a log file, and the program is running when opening a neovim file.

From my understanding, I'm supposed to read whatever neovim throws in stdin until the program is closed, but I can't seem to read all the JSON RPC message from neovim (I'm only getting the Content-Length part).

This is the code in main.rs:

fn main() {
    let stdin_lock = io::stdin().lock();
    let mut lines = stdin_lock.lines();
    
    loop {
        let next_line = match lines.next() {
            Some(val) => val,
            None => {
                continue;
            }
        }
        .unwrap();
    
        logger::print_logs(String::from("printing line..."), None).unwrap();
        logger::print_logs(next_line, None).unwrap();
    }
}

logger.rs:

pub fn print_logs(message: String, file_name: Option<&str>) -> std::io::Result<()> {
    fs::create_dir_all(LOGS_FOLDER)?;

    let file_name = file_name.unwrap_or(DEFAULT_LOGS_FILE);
    let file_location = format!("{}/{}", LOGS_FOLDER, file_name);

    let file_contents = read_to_string(file_location.clone()).unwrap();

    let mut file = File::create(file_location)?;

    let full_message = format!("{}\n{}", file_contents, message);

    file.write_all(&full_message.into_bytes())?;

    Ok(())
}

and this is the output in my log file:

printing line...
Content-Length: 3085
printing line...

I'm expecting this file to also have a JSON after the last printing line....


Solution

  • Firstly, according to the specification, between the header part and the content part, there is an empty line. Therefore, the empty line after the last "printing line..." is expected (try changing logger::print_logs(next_line, None).unwrap(); to print_logs2(format!("line: {}", next_line), None).unwrap();)

    The reason no json is printed is because the content does not end with a newline. You need to read until exactly the specified number of bytes are read (according to the Content-Length header).