command_autocomplete/
nushell.rs1use crate::connection::{ConnectionSender, Transport};
2use crate::types::{CompleteParams, CompleteResult, Error};
3use anyhow::Context;
4use clap::Args;
5use serde_json::json;
6use std::process::{Command, Stdio};
7
8#[derive(Debug, Args)]
9pub struct NushellArgs {
10 #[arg(last = true)]
12 command: Vec<String>,
13}
14
15pub fn run_nushell(args: NushellArgs) -> anyhow::Result<()> {
16 let mut child = Command::new("command-autocomplete")
18 .args(["router"])
19 .stdin(Stdio::piped())
20 .stdout(Stdio::piped())
21 .spawn()?;
22
23 let stdin = child.stdin.take().context("missing stdin")?;
24 let stdout = child.stdout.take().context("missing stdout")?;
25
26 let (transport, join_handle) = Transport::raw(stdout, stdin);
27 let (sender, receiver) = crate::connection::new_connection(transport);
28
29 let recv_join_handle = std::thread::spawn(move || {
30 while let Some(req) = receiver.next_request() {
32 let r = req.reply_err(Error::invalid_request("no requests expected"));
33 if r.is_err() {
34 log::warn!("The connection closed unexpectedly, stopping the receving loop");
35 break;
36 }
37 }
38 });
39 if let Err(err) = complete_and_shutdown(args, sender) {
40 log::error!("Completion failed, will kill subprocess: {}", err);
41 if let Err(err) = child.kill() {
42 log::warn!("Failed to kill subprocess: {err}")
43 }
44 }
45
46 if let Err(err) = child.wait() {
47 log::warn!("Failed to wait for the subprocess: {err}");
48 }
49 if let Err(err) = recv_join_handle.join() {
50 log::warn!("receiving thread failed: {:?}", err);
51 }
52 if let Err(err) = join_handle.join() {
53 log::warn!("connection threads failed: {:?}", err);
54 }
55 Ok(())
56}
57
58fn complete_and_shutdown(args: NushellArgs, sender: ConnectionSender) -> anyhow::Result<()> {
59 let res_handle = sender
61 .send(
62 "complete",
63 CompleteParams {
64 args: args.command.clone(),
65 },
66 )
67 .context("complete command failed")?;
68
69 let result: CompleteResult = res_handle.wait().context("complete command failed")?;
71
72 sender.shutdown().unwrap().wait().unwrap();
74
75 println!(
76 "{}",
77 json!(result
78 .values
79 .into_iter()
80 .map(|v| {
81 json! ({
82 "value": v.value,
83 "description": v.description,
84 })
85 })
86 .collect::<Vec<_>>())
87 );
88 Ok(())
89}