diff --git a/Cargo.lock b/Cargo.lock index 961e4bf..7b83bf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,9 +336,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -355,9 +355,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" @@ -501,15 +501,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "endian-type" -version = "0.1.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" @@ -851,7 +845,6 @@ dependencies = [ "arboard", "async-trait", "clap", - "crossterm", "derive_builder", "dirs", "duration-string", @@ -860,7 +853,8 @@ dependencies = [ "jaq-interpret", "jaq-parse", "jaq-std", - "promkit", + "promkit-core", + "promkit-widgets", "serde", "tokio", "tokio-stream", @@ -946,15 +940,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -1154,18 +1139,27 @@ dependencies = [ ] [[package]] -name = "promkit" -version = "0.8.0" +name = "promkit-core" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c6e59a653d881def8030e7c9a268cca224483b7dc1ad9f482fa4a1bd221a35" +checksum = "afdf9ca2b84218bffc62938a4755eb2c84c3015ed1eb98f2a4833701c9301a52" dependencies = [ "anyhow", "crossterm", - "radix_trie", + "unicode-width", +] + +[[package]] +name = "promkit-widgets" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528fb688a78893954d5b37e9b98ab98b669f9ec997ce6dc285e850b92e4ad257" +dependencies = [ + "anyhow", + "promkit-core", "rayon", "serde", "serde_json", - "unicode-width", ] [[package]] @@ -1177,16 +1171,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - [[package]] name = "rayon" version = "1.10.0" diff --git a/Cargo.toml b/Cargo.toml index 3c42847..e625a4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,15 +15,14 @@ async-trait = "0.1.88" clap = { version = "4.5.34", features = ["derive"] } duration-string = { version = "0.5.2", features = ["serde"] } derive_builder = "0.20.2" -# See https://github.com/crossterm-rs/crossterm/issues/935 -crossterm = { version = "0.28.1", features = ["use-dev-tty", "event-stream", "libc", "serde"] } dirs = "6.0.0" futures = "0.3.30" jaq-core = "1.2.1" jaq-interpret = "1.2.1" jaq-parse = "1.0.2" jaq-std = "1.2.1" -promkit = "0.8.0" +promkit-core = "0.1.0" +promkit-widgets = { version = "0.1.0", features = ["jsonstream", "listbox", "text", "texteditor"] } serde = "1.0.219" tokio = { version = "1.44.1", features = ["full"] } tokio-stream = "0.1.16" diff --git a/src/config.rs b/src/config.rs index e722373..0879386 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,10 +1,10 @@ use std::collections::HashSet; -use crossterm::{ +use promkit_core::crossterm::{ event::{KeyCode, KeyModifiers}, style::{Attribute, Attributes, Color, ContentStyle}, }; -use promkit::{style::StyleBuilder, text_editor::Mode}; +use promkit_widgets::text_editor::Mode; use serde::{Deserialize, Serialize}; use tokio::time::Duration; @@ -45,22 +45,31 @@ impl Default for EditorConfig { Self { theme_on_focus: EditorTheme { prefix: String::from("❯❯ "), - prefix_style: StyleBuilder::new().fgc(Color::Blue).build(), - active_char_style: StyleBuilder::new().bgc(Color::Magenta).build(), - inactive_char_style: StyleBuilder::new().build(), + prefix_style: ContentStyle { + foreground_color: Some(Color::Blue), + ..Default::default() + }, + active_char_style: ContentStyle { + background_color: Some(Color::Magenta), + ..Default::default() + }, + inactive_char_style: ContentStyle::default(), }, theme_on_defocus: EditorTheme { prefix: String::from("▼ "), - prefix_style: StyleBuilder::new() - .fgc(Color::Blue) - .attrs(Attributes::from(Attribute::Dim)) - .build(), - active_char_style: StyleBuilder::new() - .attrs(Attributes::from(Attribute::Dim)) - .build(), - inactive_char_style: StyleBuilder::new() - .attrs(Attributes::from(Attribute::Dim)) - .build(), + prefix_style: ContentStyle { + foreground_color: Some(Color::Blue), + attributes: Attributes::from(Attribute::Dim), + ..Default::default() + }, + active_char_style: ContentStyle { + attributes: Attributes::from(Attribute::Dim), + ..Default::default() + }, + inactive_char_style: ContentStyle { + attributes: Attributes::from(Attribute::Dim), + ..Default::default() + }, }, mode: Mode::Insert, word_break_chars: HashSet::from(['.', '|', '(', ')', '[', ']']), @@ -106,17 +115,28 @@ impl Default for JsonConfig { max_streams: None, theme: JsonTheme { indent: 2, - curly_brackets_style: StyleBuilder::new() - .attrs(Attributes::from(Attribute::Bold)) - .build(), - square_brackets_style: StyleBuilder::new() - .attrs(Attributes::from(Attribute::Bold)) - .build(), - key_style: StyleBuilder::new().fgc(Color::Cyan).build(), - string_value_style: StyleBuilder::new().fgc(Color::Green).build(), - number_value_style: StyleBuilder::new().build(), - boolean_value_style: StyleBuilder::new().build(), - null_value_style: StyleBuilder::new().fgc(Color::Grey).build(), + curly_brackets_style: ContentStyle { + attributes: Attributes::from(Attribute::Bold), + ..Default::default() + }, + square_brackets_style: ContentStyle { + attributes: Attributes::from(Attribute::Bold), + ..Default::default() + }, + key_style: ContentStyle { + foreground_color: Some(Color::Cyan), + ..Default::default() + }, + string_value_style: ContentStyle { + foreground_color: Some(Color::Green), + ..Default::default() + }, + number_value_style: ContentStyle::default(), + boolean_value_style: ContentStyle::default(), + null_value_style: ContentStyle { + foreground_color: Some(Color::Grey), + ..Default::default() + }, }, } } @@ -143,11 +163,15 @@ impl Default for CompletionConfig { cursor: String::from("❯ "), 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(), + active_item_style: ContentStyle { + foreground_color: Some(Color::Grey), + background_color: Some(Color::Yellow), + ..Default::default() + }, + inactive_item_style: ContentStyle { + foreground_color: Some(Color::Grey), + ..Default::default() + }, } } } diff --git a/src/config/content_style.rs b/src/config/content_style.rs index 03294de..3b2adc3 100644 --- a/src/config/content_style.rs +++ b/src/config/content_style.rs @@ -1,4 +1,4 @@ -use crossterm::style::{Attribute, Attributes, Color, ContentStyle}; +use promkit_core::crossterm::style::{Attribute, Attributes, Color, ContentStyle}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] diff --git a/src/config/event.rs b/src/config/event.rs index 4e50423..c95f478 100644 --- a/src/config/event.rs +++ b/src/config/event.rs @@ -1,6 +1,8 @@ use std::collections::HashSet; -use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind}; +use promkit_core::crossterm::event::{ + Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind, +}; use serde::{Deserialize, Serialize}; pub trait Matcher { diff --git a/src/config/text_editor.rs b/src/config/text_editor.rs index 318e372..9bfcac1 100644 --- a/src/config/text_editor.rs +++ b/src/config/text_editor.rs @@ -1,4 +1,4 @@ -use promkit::text_editor::Mode; +use promkit_widgets::text_editor::Mode; use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub mod text_editor_mode_serde { diff --git a/src/editor.rs b/src/editor.rs index 8f8f6ad..bc00158 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -1,14 +1,15 @@ use std::{future::Future, pin::Pin}; -use crossterm::{ - event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}, - style::Color, +use promkit_core::{ + crossterm::{ + event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}, + style::{Color, ContentStyle}, + }, + Pane, PaneFactory, }; -use promkit::{ - pane::Pane, - style::StyleBuilder, +use promkit_widgets::{ text::{self, Text}, - text_editor, PaneFactory, + text_editor, }; use crate::{ @@ -113,13 +114,19 @@ pub async fn edit<'a>(event: &'a Event, editor: &'a mut Editor) -> anyhow::Resul "Loaded all ({}) suggestions", result.load_state.loaded_item_len )); - editor.guide.style = StyleBuilder::new().fgc(Color::Green).build(); + editor.guide.style = ContentStyle { + foreground_color: Some(Color::Green), + ..Default::default() + }; } else { editor.guide.text = Text::from(format!( "Loaded partially ({}) suggestions", result.load_state.loaded_item_len )); - editor.guide.style = StyleBuilder::new().fgc(Color::Green).build(); + editor.guide.style = ContentStyle { + foreground_color: Some(Color::Green), + ..Default::default() + }; } editor.state.texteditor.replace(&head); editor.handler = BOXED_SEARCHER_HANDLER; @@ -127,12 +134,18 @@ pub async fn edit<'a>(event: &'a Event, editor: &'a mut Editor) -> anyhow::Resul None => { editor.guide.text = Text::from(format!("No suggestion found for '{}'", prefix)); - editor.guide.style = StyleBuilder::new().fgc(Color::Yellow).build(); + editor.guide.style = ContentStyle { + foreground_color: Some(Color::Yellow), + ..Default::default() + }; } }, Err(e) => { editor.guide.text = Text::from(format!("Failed to lookup suggestions: {}", e)); - editor.guide.style = StyleBuilder::new().fgc(Color::Yellow).build(); + editor.guide.style = ContentStyle { + foreground_color: Some(Color::Yellow), + ..Default::default() + }; } } } diff --git a/src/json.rs b/src/json.rs index 0eebc39..95d736c 100644 --- a/src/json.rs +++ b/src/json.rs @@ -1,17 +1,17 @@ -use crossterm::{ - event::Event, - style::{Attribute, Attributes}, -}; use jaq_interpret::{Ctx, FilterT, ParseCtx, RcIter, Val}; -use promkit::{ - crossterm::style::Color, - jsonstream::{self, JsonStream}, - jsonz::{self, format::RowFormatter}, +use promkit_core::{ + crossterm::{ + event::Event, + style::{Attribute, Attributes, Color, ContentStyle}, + }, pane::Pane, + PaneFactory, +}; + +use promkit_widgets::{ + jsonstream::{self, format::RowFormatter, jsonz, JsonStream}, serde_json::{self, Deserializer, Value}, - style::StyleBuilder, text::{self, Text}, - PaneFactory, }; use crate::{ @@ -112,10 +112,11 @@ impl Visualizer for Json { if ret.iter().all(|val| *val == Value::Null) { guide = Some(text::State { text: Text::from(format!("jq returned 'null', which may indicate a typo or incorrect filter: `{}`", input)), - style: StyleBuilder::new() - .fgc(Color::Yellow) - .attrs(Attributes::from(Attribute::Bold)) - .build(), + style: ContentStyle { + foreground_color: Some(Color::Yellow), + attributes: Attributes::from(Attribute::Bold), + ..Default::default() + }, ..Default::default() }.create_pane(area.0, area.1)); } @@ -128,10 +129,11 @@ impl Visualizer for Json { Some( text::State { text: Text::from(format!("jq failed: `{}`", e)), - style: StyleBuilder::new() - .fgc(Color::Red) - .attrs(Attributes::from(Attribute::Bold)) - .build(), + style: ContentStyle { + foreground_color: Some(Color::Red), + attributes: Attributes::from(Attribute::Bold), + ..Default::default() + }, ..Default::default() } .create_pane(area.0, area.1), diff --git a/src/main.rs b/src/main.rs index 4d4c9d9..943b5eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,9 @@ use std::{ use anyhow::anyhow; use clap::Parser; use config::Config; -use crossterm::style::Attribute; -use promkit::{ - jsonz::format::RowFormatter, +use promkit_core::crossterm::style::Attribute; +use promkit_widgets::{ + jsonstream::format::RowFormatter, listbox::{self, Listbox}, text_editor::{self, TextEditor}, }; diff --git a/src/processor.rs b/src/processor.rs index df01def..02dbb80 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -1,8 +1,7 @@ use std::sync::Arc; use async_trait::async_trait; -use crossterm::event::Event; -use promkit::pane::Pane; +use promkit_core::{crossterm::event::Event, pane::Pane}; use tokio::{sync::Mutex, task::JoinHandle}; use crate::{PaneIndex, Renderer, EMPTY_PANE}; diff --git a/src/processor/spinner.rs b/src/processor/spinner.rs index 42821b5..faacd0c 100644 --- a/src/processor/spinner.rs +++ b/src/processor/spinner.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use promkit::pane::Pane; +use promkit_core::{grapheme::StyledGraphemes, Pane}; use tokio::{sync::Mutex, task::JoinHandle, time::Duration}; use super::{Context, State}; @@ -38,12 +38,7 @@ impl SpinnerSpawner { frame_index = (frame_index + 1) % LOADING_FRAMES.len(); - let pane = Pane::new( - vec![promkit::grapheme::StyledGraphemes::from( - LOADING_FRAMES[frame_index], - )], - 0, - ); + let pane = Pane::new(vec![StyledGraphemes::from(LOADING_FRAMES[frame_index])], 0); { // TODO: error handling let _ = shared_renderer diff --git a/src/prompt.rs b/src/prompt.rs index 33fd176..42649cd 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -1,19 +1,18 @@ use std::{io, sync::Arc, time::Duration}; use arboard::Clipboard; -use crossterm::{ - self, cursor, - event::{Event, EventStream, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}, - execute, - style::Color, - terminal::{self, disable_raw_mode, enable_raw_mode}, -}; use futures::StreamExt; -use promkit::{ - style::StyleBuilder, - text::{self, Text}, +use promkit_core::{ + crossterm::{ + cursor, + event::{Event, EventStream, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}, + execute, + style::{Color, ContentStyle}, + terminal::{self, disable_raw_mode, enable_raw_mode}, + }, PaneFactory, }; +use promkit_widgets::text::{self, Text}; use tokio::{ sync::{mpsc, Mutex, RwLock}, task::JoinHandle, @@ -57,12 +56,18 @@ fn copy_to_clipboard(content: &str) -> text::State { Ok(mut clipboard) => match clipboard.set_text(content) { Ok(_) => text::State { text: Text::from("Copied to clipboard"), - style: StyleBuilder::new().fgc(Color::Green).build(), + style: ContentStyle { + foreground_color: Some(Color::Green), + ..Default::default() + }, ..Default::default() }, Err(e) => text::State { text: Text::from(format!("Failed to copy to clipboard: {}", e)), - style: StyleBuilder::new().fgc(Color::Red).build(), + style: ContentStyle { + foreground_color: Some(Color::Red), + ..Default::default() + }, ..Default::default() }, }, @@ -71,7 +76,10 @@ fn copy_to_clipboard(content: &str) -> text::State { // https://github.com/1Password/arboard/issues/153 Err(e) => text::State { text: Text::from(format!("Failed to setup clipboard: {}", e)), - style: StyleBuilder::new().fgc(Color::Red).build(), + style: ContentStyle { + foreground_color: Some(Color::Red), + ..Default::default() + }, ..Default::default() }, } @@ -190,7 +198,10 @@ pub async fn run( let size = terminal::size()?; pane = text::State { text: Text::from("Failed to copy while rendering is in progress.".to_string()), - style: StyleBuilder::new().fgc(Color::Yellow).build(), + style: ContentStyle { + foreground_color: Some(Color::Yellow), + ..Default::default() + }, ..Default::default() }.create_pane(size.0, size.1); } @@ -221,7 +232,10 @@ pub async fn run( let size = terminal::size()?; pane = text::State { text: Text::from("Failed to switch pane while rendering is in progress.".to_string()), - style: StyleBuilder::new().fgc(Color::Yellow).build(), + style: ContentStyle { + foreground_color: Some(Color::Yellow), + ..Default::default() + }, ..Default::default() }.create_pane(size.0, size.1); } diff --git a/src/render.rs b/src/render.rs index c1713ed..b026dd9 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,7 +1,6 @@ use std::sync::LazyLock; -use crossterm::{self, cursor}; -use promkit::{pane::Pane, terminal::Terminal}; +use promkit_core::{crossterm::cursor, pane::Pane, terminal::Terminal}; // TODO: One Guide is sufficient. #[derive(Debug, PartialEq)] diff --git a/src/search.rs b/src/search.rs index e9c4779..0deb0f2 100644 --- a/src/search.rs +++ b/src/search.rs @@ -2,11 +2,8 @@ use std::{collections::BTreeSet, sync::Arc}; use anyhow::anyhow; use async_trait::async_trait; -use promkit::{ - listbox::{self, Listbox}, - pane::Pane, - PaneFactory, -}; +use promkit_core::{pane::Pane, PaneFactory}; +use promkit_widgets::listbox::{self, Listbox}; use tokio::{ sync::{Mutex, RwLock}, task::JoinHandle,