diff --git a/src/config.rs b/src/config.rs index e61cd5b..a2669fd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -187,6 +187,71 @@ impl JsonTheme { } } +#[derive(Clone, Serialize, Deserialize, Builder)] +#[builder(derive(Serialize, Deserialize))] +#[builder(name = "CompletionConfigFromFile")] +pub(crate) struct CompletionConfig { + pub lines: Option, + + #[builder_field_attr(serde(default))] + pub search_result_chunk_size: usize, + + #[builder_field_attr(serde(default))] + pub search_load_chunk_size: usize, + + #[serde(with = "content_style_serde")] + #[builder_field_attr(serde(default, with = "option_content_style_serde"))] + pub active_item_style: ContentStyle, + + #[serde(with = "content_style_serde")] + #[builder_field_attr(serde(default, with = "option_content_style_serde"))] + pub inactive_item_style: ContentStyle, +} + +impl Default for CompletionConfig { + fn default() -> Self { + Self { + lines: Some(3), + search_result_chunk_size: 100, + search_load_chunk_size: 50000, + active_item_style: StyleBuilder::new() + .fgc(Color::Grey) + .bgc(Color::Yellow) + .build(), + inactive_item_style: StyleBuilder::new().fgc(Color::Grey).build(), + } + } +} + +impl CompletionConfigFromFile { + /// Load the config from a string. + pub fn load_from(content: &str) -> anyhow::Result { + toml::from_str(content).map_err(Into::into) + } +} + +impl CompletionConfig { + pub fn patch_with(&mut self, config: CompletionConfigFromFile) { + // TODO: This is awful verbose. Can we do better? + match config.lines { + Some(val) => self.lines = val, + None => self.lines = None, + } + if let Some(val) = config.search_result_chunk_size { + self.search_result_chunk_size = val; + } + if let Some(val) = config.search_load_chunk_size { + self.search_load_chunk_size = val; + } + if let Some(val) = config.active_item_style { + self.active_item_style = val; + } + if let Some(val) = config.inactive_item_style { + self.inactive_item_style = val; + } + } +} + #[derive(Serialize, Deserialize, Builder)] #[builder(derive(Serialize, Deserialize))] #[builder(name = "ConfigFromFile")] @@ -202,34 +267,14 @@ pub(crate) struct Config { #[serde(with = "duration_serde")] #[builder_field_attr(serde(default, with = "option_duration_serde"))] pub spin_duration: Duration, - - #[builder_field_attr(serde(default))] - pub search_result_chunk_size: usize, - - #[builder_field_attr(serde(default))] - pub search_load_chunk_size: usize, - - #[serde(with = "content_style_serde")] - #[builder_field_attr(serde(default, with = "option_content_style_serde"))] - pub active_item_style: ContentStyle, - #[serde(with = "content_style_serde")] - #[builder_field_attr(serde(default, with = "option_content_style_serde"))] - pub inactive_item_style: ContentStyle, } impl Default for Config { fn default() -> Self { Self { - active_item_style: StyleBuilder::new() - .fgc(Color::Grey) - .bgc(Color::Yellow) - .build(), - inactive_item_style: StyleBuilder::new().fgc(Color::Grey).build(), - search_result_chunk_size: 100, query_debounce_duration: Duration::from_millis(600), resize_debounce_duration: Duration::from_millis(200), spin_duration: Duration::from_millis(300), - search_load_chunk_size: 50000, } } } @@ -252,18 +297,6 @@ impl Config { if let Some(val) = config.spin_duration { self.spin_duration = val; } - if let Some(val) = config.search_result_chunk_size { - self.search_result_chunk_size = val; - } - if let Some(val) = config.search_load_chunk_size { - self.search_load_chunk_size = val; - } - if let Some(val) = config.active_item_style { - self.active_item_style = val; - } - if let Some(val) = config.inactive_item_style { - self.inactive_item_style = val; - } } } diff --git a/src/main.rs b/src/main.rs index f1eeccb..138af7f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,8 @@ use std::{ use anyhow::anyhow; use clap::Parser; use config::{ - Config, ConfigFromFile, EditorConfig, EditorConfigFromFile, JsonTheme, JsonThemeFromFile, - Keybinds, KeybindsFromFile, + CompletionConfig, CompletionConfigFromFile, Config, ConfigFromFile, EditorConfig, + EditorConfigFromFile, JsonTheme, JsonThemeFromFile, Keybinds, KeybindsFromFile, }; use crossterm::style::Attribute; use promkit::{ @@ -109,18 +109,6 @@ pub struct Args { " )] pub max_streams: Option, - - #[arg( - long = "suggestions", - default_value = "3", - help = "Number of autocomplete suggestions to show", - long_help = " - Sets the number of autocomplete suggestions displayed during incremental search. - Higher values show more suggestions but may occupy more screen space. - Adjust this value based on your screen size and preference. - " - )] - pub suggestions: usize, } fn edit_mode_validator(val: &str) -> anyhow::Result { @@ -208,11 +196,19 @@ async fn main() -> anyhow::Result<()> { let args = Args::parse(); let input = parse_input(&args)?; - let (mut config, mut keybinds, mut editor_config, mut json_theme) = ( + #[rustfmt::skip] + let ( + mut config, + mut keybinds, + mut editor_config, + mut json_theme, + mut comp_config, + ) = ( Config::default(), Keybinds::default(), EditorConfig::default(), JsonTheme::default(), + CompletionConfig::default(), ); if let Ok(config_file) = determine_config_file(args.config_file, &config) { // Note that the configuration file absolutely exists. @@ -221,31 +217,29 @@ async fn main() -> anyhow::Result<()> { let keybinds_from_file = KeybindsFromFile::load_from(&content)?; let editor_config_from_file = EditorConfigFromFile::load_from(&content)?; let json_theme_from_file = JsonThemeFromFile::load_from(&content)?; + let comp_config_from_file = CompletionConfigFromFile::load_from(&content)?; config.patch_with(config_from_file); keybinds.patch_with(keybinds_from_file); editor_config.patch_with(editor_config_from_file); json_theme.patch_with(json_theme_from_file); + comp_config.patch_with(comp_config_from_file); } let config::Config { - search_result_chunk_size, query_debounce_duration, resize_debounce_duration, - search_load_chunk_size, - active_item_style, - inactive_item_style, spin_duration, } = config; let listbox_state = listbox::State { listbox: Listbox::default(), cursor: String::from("❯ "), - active_item_style: Some(active_item_style), - inactive_item_style: Some(inactive_item_style), - lines: Some(args.suggestions), + active_item_style: Some(comp_config.active_item_style), + inactive_item_style: Some(comp_config.inactive_item_style), + lines: comp_config.lines, }; - let searcher = IncrementalSearcher::new(listbox_state, search_result_chunk_size); + let searcher = IncrementalSearcher::new(listbox_state, comp_config.search_result_chunk_size); let text_editor_state = text_editor::State { texteditor: Default::default(), @@ -278,7 +272,8 @@ async fn main() -> anyhow::Result<()> { let item = Box::leak(input.into_boxed_str()); - let loading_suggestions_task = searcher.spawn_load_task(provider, item, search_load_chunk_size); + let loading_suggestions_task = + searcher.spawn_load_task(provider, item, comp_config.search_load_chunk_size); let editor = Editor::new( text_editor_state,