reactive_graph/client/repl/
mod.rs1use std::sync::Arc;
2
3use clap::Parser;
4use colored::*;
5use rustyline::Cmd;
6use rustyline::Editor;
7use rustyline::Event;
8use rustyline::KeyCode;
9use rustyline::KeyEvent;
10use rustyline::Modifiers;
11use rustyline::error::ReadlineError;
12use rustyline::history::DefaultHistory;
13use shellwords::split;
14
15use crate::client::handler::handle_command;
16use crate::client::repl::args::ReplArgs;
17use crate::client::repl::chars::*;
18use crate::client::repl::repl_helper::ReplHelper;
19use crate::client::repl::return_state::ReturnState;
20use reactive_graph_client::ReactiveGraphClient;
21
22pub(crate) mod args;
23pub(crate) mod chars;
24pub(crate) mod hint;
25pub(crate) mod repl_helper;
26pub(crate) mod return_state;
27
28pub(crate) async fn repl(client: &Arc<ReactiveGraphClient>) -> Result<(), i32> {
29 let mut rl = Editor::<ReplHelper, DefaultHistory>::new().map_err(|_| 255)?;
30 rl.set_helper(Some(ReplHelper::new()));
31 rl.bind_sequence(Event::KeySeq(vec![KeyEvent(KeyCode::Tab, Modifiers::NONE)]), Cmd::CompleteHint);
32
33 if rl.load_history("history.txt").is_err() {
34 println!("No previous history.");
35 }
36
37 let mut return_state = ReturnState::Neutral;
38 let mut break_state = false;
39 loop {
40 let prompt = format!("{} {} {} ", CHAR_PROMPT, client.remote().base_url().cyan().bold(), return_state);
41 let readline = rl.readline(prompt.as_str());
42 match readline {
43 Ok(line) => {
44 match line.as_str() {
45 "exit" | "quit" => break,
46 _ => match split(line.as_str())
47 .map(|mut args| {
48 args.insert(0, String::from(" "));
49 args
50 })
51 .map(ReplArgs::try_parse_from)
52 {
53 Ok(Ok(cli_args)) => {
54 let command = cli_args.commands;
55 match handle_command(client, command).await {
56 Ok(response) => {
57 println!("{response}");
58 return_state = ReturnState::Success;
60 break_state = false;
61 }
62 Err(e) => {
63 eprintln!("{}: {}", "Command failed with error".red(), e);
64 return_state = ReturnState::Error;
66 }
67 }
68 }
69 Ok(Err(e)) => {
70 eprintln!("{e}");
71 return_state = ReturnState::Error;
72 }
73 Err(r) => {
74 eprintln!("{}: {}", "Mismatched Quotes".red(), r);
75 return_state = ReturnState::Error;
76 }
77 },
78 }
79 let _ = rl.add_history_entry(line.as_str());
80 }
81 Err(ReadlineError::Interrupted) => {
83 if break_state {
84 break;
85 }
86 break_state = true;
87 println!("Press CTRL-C again to exit");
88 }
89 Err(ReadlineError::Eof) => break,
91 Err(e) => {
92 eprintln!("Error: {e:?}");
93 break;
94 }
95 }
96 }
97 let _ = rl.save_history("history.txt");
98 Ok(())
99}
100
101pub fn longest_common_prefix(s: &Vec<&String>) -> String {
102 let mut result = "".to_string();
103 let mut count = 0;
104 let mut found = false;
105 if s.is_empty() || s[0].is_empty() {
106 return result;
107 }
108 loop {
109 result.push_str(&s[0][count..count + 1]);
110 for item in s {
111 if item.len() < count + 1 || item[0..count + 1] != result {
112 found = true;
113 break;
114 }
115 }
116 match found {
117 true => break result[0..count].to_string(),
118 false => {
119 if count + 1 == s[0].len() {
120 break result;
121 }
122 }
123 }
124 count += 1;
125 }
126}