From 21d1be5bedb13d08462e9800a1c3cbf93dd585bc Mon Sep 17 00:00:00 2001 From: sigoden Date: Sat, 24 Feb 2024 19:13:48 +0800 Subject: [PATCH] refactor: improve prompt error handling (#319) --- Cargo.lock | 59 +++++++++++++++++++++++++++++++-------- Cargo.toml | 2 +- README.md | 11 ++++---- src/config/mod.rs | 22 ++++----------- src/main.rs | 5 ++-- src/utils/prompt_input.rs | 10 +++---- 6 files changed, 66 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 763e232..c1aa01a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,6 +285,12 @@ version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -293,9 +299,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" +checksum = "3286b845d0fccbdd15af433f61c5970e711987036cb468f437ff6badd70f4e24" [[package]] name = "cfg-if" @@ -773,6 +779,24 @@ dependencies = [ "slab", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -964,16 +988,17 @@ dependencies = [ [[package]] name = "inquire" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33e7c1ddeb15c9abcbfef6029d8e29f69b52b6d6c891031b88ed91b5065803b" +checksum = "bd05e4e63529f3c9c5f5c668c398217f72756ffe48c85266b49692c55accd1f7" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "crossterm 0.25.0", "dyn-clone", - "lazy_static", + "fuzzy-matcher", + "fxhash", "newline-converter", - "thiserror", + "once_cell", "unicode-segmentation", "unicode-width", ] @@ -1152,9 +1177,9 @@ dependencies = [ [[package]] name = "newline-converter" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f71d09d5c87634207f894c6b31b6a2b2c64ea3bdcf71bd5599fdbbe1600c00f" +checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f" dependencies = [ "unicode-segmentation", ] @@ -1837,12 +1862,12 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2007,6 +2032,16 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.3.34" diff --git a/Cargo.toml b/Cargo.toml index ea43b5e..0ed7e4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ bytes = "1.4.0" clap = { version = "4.4.8", features = ["derive"] } dirs = "5.0.0" futures-util = "0.3.29" -inquire = "0.6.2" +inquire = "0.7.0" is-terminal = "0.4.9" reedline = "0.29.0" serde = { version = "1.0.152", features = ["derive"] } diff --git a/README.md b/README.md index 528525b..95476e0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ AIChat in chat REPL mode: AIChat in command mode: -![command mode](https://github.com/sigoden/aichat/assets/4012553/26f7badc-1b1f-418b-99c1-fbc58bee0097) +![command mode](https://github.com/sigoden/aichat/assets/4012553/db96a38a-2f14-4127-91e7-4d111aba6ca9) ## Install @@ -58,10 +58,10 @@ Download it from [GitHub Releases](https://github.com/sigoden/aichat/releases), - Support [Roles](#roles) - Support context-aware conversation (session) - Support multimodal models (vision) -- Support executing commands using natural language +- Execute commands using natural language - Syntax highlighting for markdown and 200+ languages in code blocks - Stream output -- Support proxy +- Use proxy - With Dark/light theme - Save messages/sessions @@ -149,8 +149,9 @@ The Chat REPL supports: - Emacs/Vi keybinding - [Custom REPL Prompt](https://github.com/sigoden/aichat/wiki/Custom-REPL-Prompt) -- Tab Completion +- Tab Completions - Edit/paste multiline text +- Open an editor to modify the current prompt - Undo support ### `.help` - print help message @@ -395,7 +396,7 @@ aichat -e find all json files in current folder | pbcopy ## License -Copyright (c) 2023 aichat-developers. +Copyright (c) 2023-2024 aichat-developers. Aichat is made available under the terms of either the MIT License or the Apache License 2.0, at your option. diff --git a/src/config/mod.rs b/src/config/mod.rs index d38cbf3..f8d97c2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -11,7 +11,7 @@ use crate::client::{ Model, OpenAIClient, SendData, }; use crate::render::{MarkdownRender, RenderOptions}; -use crate::utils::{get_env_name, light_theme_from_colorfgbg, now, prompt_op_err, render_prompt}; +use crate::utils::{get_env_name, light_theme_from_colorfgbg, now, render_prompt}; use anyhow::{anyhow, bail, Context, Result}; use inquire::{Confirm, Select, Text}; @@ -577,8 +577,7 @@ impl Config { "Start a session that incorporates the last question and answer?", ) .with_default(false) - .prompt() - .map_err(prompt_op_err)?; + .prompt()?; if ans { session.add_message(input, output)?; } @@ -593,19 +592,13 @@ impl Config { self.last_message = None; self.temperature = self.default_temperature; if session.should_save() { - let ans = Confirm::new("Save session?") - .with_default(false) - .prompt() - .map_err(prompt_op_err)?; + let ans = Confirm::new("Save session?").with_default(false).prompt()?; if !ans { return Ok(()); } let mut name = session.name().to_string(); if session.is_temp() { - name = Text::new("Session name:") - .with_default(&name) - .prompt() - .map_err(prompt_op_err)?; + name = Text::new("Session name:").with_default(&name).prompt()?; } let session_path = Self::session_file(&name)?; let sessions_dir = session_path.parent().ok_or_else(|| { @@ -917,15 +910,12 @@ pub enum State { fn create_config_file(config_path: &Path) -> Result<()> { let ans = Confirm::new("No config file, create a new one?") .with_default(true) - .prompt() - .map_err(prompt_op_err)?; + .prompt()?; if !ans { exit(0); } - let client = Select::new("Platform:", list_client_types()) - .prompt() - .map_err(prompt_op_err)?; + let client = Select::new("Platform:", list_client_types()).prompt()?; let mut config = serde_json::json!({}); config["model"] = client.into(); diff --git a/src/main.rs b/src/main.rs index 8946985..29e034f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ mod utils; use crate::cli::Cli; use crate::config::{Config, GlobalConfig}; -use crate::utils::{prompt_op_err, run_command}; +use crate::utils::run_command; use anyhow::{bail, Result}; use clap::Parser; @@ -165,8 +165,7 @@ fn execute(config: &GlobalConfig, text: &str) -> Result<()> { )), } }) - .prompt() - .map_err(prompt_op_err)?; + .prompt()?; match anwser.as_str() { "E" | "e" => { diff --git a/src/utils/prompt_input.rs b/src/utils/prompt_input.rs index f63823a..e887b9f 100644 --- a/src/utils/prompt_input.rs +++ b/src/utils/prompt_input.rs @@ -10,7 +10,8 @@ pub fn prompt_input_string(desc: &str, required: bool) -> anyhow::Result } else { text = text.with_help_message(MSG_OPTIONAL) } - text.prompt().map_err(prompt_op_err) + let text = text.prompt()?; + Ok(text) } pub fn prompt_input_integer(desc: &str, required: bool) -> anyhow::Result { @@ -36,11 +37,8 @@ pub fn prompt_input_integer(desc: &str, required: bool) -> anyhow::Result(_: T) -> anyhow::Error { - anyhow::anyhow!("Not finish questionnaire, try again later!") + let text = text.prompt()?; + Ok(text) } #[derive(Debug, Clone, Copy)]