chore: use promkit-widgets v0.2.0 and remove promkit-core crate, render.rs

This commit is contained in:
ynqa
2025-07-17 23:08:34 +09:00
parent cc0f8b1202
commit 44f4b37634
14 changed files with 704 additions and 702 deletions
Generated
+539 -512
View File
File diff suppressed because it is too large Load Diff
+9 -7
View File
@@ -12,21 +12,23 @@ readme = "README.md"
anyhow = "1.0.97"
arboard = { version = "3.4.1", features = ["wayland-data-control"] }
async-trait = "0.1.88"
clap = { version = "4.5.34", features = ["derive"] }
clap = { version = "4.5.41", features = ["derive"] }
duration-string = { version = "0.5.2", features = ["serde"] }
derive_builder = "0.20.2"
dirs = "6.0.0"
futures = "0.3.30"
promkit-widgets = { version = "0.2.0", features = ["jsonstream", "listbox", "text", "texteditor"] }
serde = "1.0.219"
tokio = { version = "1.44.1", features = ["full"] }
tokio-stream = "0.1.16"
toml = "0.9.2"
# jaq dependencies
# TODO: bump up to v2.x.x
jaq-core = "1.2.1"
jaq-interpret = "1.2.1"
jaq-parse = "1.0.2"
jaq-std = "1.2.1"
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"
toml = "0.8.20"
# The profile that 'cargo dist' will build with
[profile.dist]
+6 -4
View File
@@ -1,10 +1,12 @@
use std::collections::HashSet;
use promkit_core::crossterm::{
event::{KeyCode, KeyModifiers},
style::{Attribute, Attributes, Color, ContentStyle},
use promkit_widgets::{
core::crossterm::{
event::{KeyCode, KeyModifiers},
style::{Attribute, Attributes, Color, ContentStyle},
},
text_editor::Mode,
};
use promkit_widgets::text_editor::Mode;
use serde::{Deserialize, Serialize};
use tokio::time::Duration;
+1 -1
View File
@@ -1,4 +1,4 @@
use promkit_core::crossterm::style::{Attribute, Attributes, Color, ContentStyle};
use promkit_widgets::core::crossterm::style::{Attribute, Attributes, Color, ContentStyle};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
+1 -1
View File
@@ -1,6 +1,6 @@
use std::collections::HashSet;
use promkit_core::crossterm::event::{
use promkit_widgets::core::crossterm::event::{
Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind,
};
use serde::{Deserialize, Serialize};
+7 -7
View File
@@ -1,13 +1,13 @@
use std::{future::Future, pin::Pin};
use promkit_core::{
crossterm::{
event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers},
style::{Color, ContentStyle},
},
Pane, PaneFactory,
};
use promkit_widgets::{
core::{
crossterm::{
event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers},
style::{Color, ContentStyle},
},
Pane, PaneFactory,
},
text::{self, Text},
text_editor,
};
+8 -8
View File
@@ -1,14 +1,14 @@
use jaq_interpret::{Ctx, FilterT, ParseCtx, RcIter, Val};
use promkit_core::{
crossterm::{
event::Event,
style::{Attribute, Attributes, Color, ContentStyle},
},
pane::Pane,
PaneFactory,
};
use promkit_widgets::{
core::{
crossterm::{
event::Event,
style::{Attribute, Attributes, Color, ContentStyle},
},
pane::Pane,
PaneFactory,
},
jsonstream::{self, format::RowFormatter, jsonz, JsonStream},
serde_json::{self, Deserializer, Value},
text::{self, Text},
+1 -3
View File
@@ -7,8 +7,8 @@ use std::{
use anyhow::anyhow;
use clap::Parser;
use config::Config;
use promkit_core::crossterm::style::Attribute;
use promkit_widgets::{
core::crossterm::style::Attribute,
jsonstream::format::RowFormatter,
listbox::{self, Listbox},
text_editor::{self, TextEditor},
@@ -25,8 +25,6 @@ use processor::{
ViewProvider, Visualizer,
};
mod prompt;
mod render;
use render::{PaneIndex, Renderer, EMPTY_PANE};
mod search;
use search::{IncrementalSearcher, SearchProvider};
+20 -15
View File
@@ -1,12 +1,17 @@
use std::sync::Arc;
use async_trait::async_trait;
use promkit_core::{crossterm::event::Event, pane::Pane};
use promkit_widgets::core::{
crossterm::event::Event,
pane::{Pane, EMPTY_PANE},
render::SharedRenderer,
};
use tokio::{sync::Mutex, task::JoinHandle};
use crate::{PaneIndex, Renderer, EMPTY_PANE};
pub mod init;
pub use init::ViewProvider;
use crate::prompt::Index;
pub mod monitor;
pub mod spinner;
@@ -58,7 +63,7 @@ impl Processor {
&self,
query: String,
shared_visualizer: Arc<Mutex<impl Visualizer>>,
shared_renderer: Arc<Mutex<Renderer>>,
shared_renderer: SharedRenderer<Index>,
) -> JoinHandle<()> {
let shared = self.shared.clone();
tokio::spawn(async move {
@@ -83,16 +88,16 @@ impl Processor {
}
{
// TODO: error handling
let _ = shared_renderer.lock().await.update_and_draw([
(
PaneIndex::Guide,
maybe_guide.unwrap_or(EMPTY_PANE.to_owned()),
),
(
PaneIndex::Processor,
maybe_resp.unwrap_or(EMPTY_PANE.to_owned()),
),
]);
let _ = shared_renderer
.update([
(Index::Guide, maybe_guide.unwrap_or(EMPTY_PANE.to_owned())),
(
Index::Processor,
maybe_resp.unwrap_or(EMPTY_PANE.to_owned()),
),
])
.render()
.await;
}
})
}
@@ -102,7 +107,7 @@ impl Processor {
shared_visualizer: Arc<Mutex<impl Visualizer>>,
area: (u16, u16),
query: String,
shared_renderer: Arc<Mutex<Renderer>>,
shared_renderer: SharedRenderer<Index>,
) {
{
let mut shared_state = self.shared.lock().await;
@@ -124,7 +129,7 @@ impl Processor {
&self,
shared_visualizer: Arc<Mutex<impl Visualizer>>,
query: String,
shared_renderer: Arc<Mutex<Renderer>>,
shared_renderer: SharedRenderer<Index>,
) {
{
let mut shared_state = self.shared.lock().await;
+6 -5
View File
@@ -1,10 +1,11 @@
use std::sync::Arc;
use async_trait::async_trait;
use promkit_widgets::core::render::SharedRenderer;
use tokio::sync::Mutex;
use super::{Context, State, Visualizer};
use crate::{config::JsonViewerKeybinds, PaneIndex, Renderer};
use crate::{config::JsonViewerKeybinds, prompt::Index};
#[async_trait]
pub trait ViewProvider {
@@ -29,7 +30,7 @@ impl ViewInitializer {
provider: &'a mut T,
item: &'static str,
area: (u16, u16),
shared_renderer: Arc<Mutex<Renderer>>,
shared_renderer: SharedRenderer<Index>,
keybinds: JsonViewerKeybinds,
) -> anyhow::Result<impl Visualizer + 'a> {
{
@@ -51,9 +52,9 @@ impl ViewInitializer {
{
// TODO: error handling
let _ = shared_renderer
.lock()
.await
.update_and_draw([(PaneIndex::Processor, pane)]);
.update([(Index::Processor, pane)])
.render()
.await;
}
Ok(visualizer)
+7 -6
View File
@@ -1,10 +1,11 @@
use std::sync::Arc;
use promkit_core::{grapheme::StyledGraphemes, Pane};
use promkit_widgets::core::{grapheme::StyledGraphemes, render::SharedRenderer, Pane};
use tokio::{sync::Mutex, task::JoinHandle, time::Duration};
use crate::prompt::Index;
use super::{Context, State};
use crate::{PaneIndex, Renderer};
const LOADING_FRAMES: [&str; 10] = ["", "", "", "", "", "", "", "", "", ""];
@@ -19,7 +20,7 @@ impl SpinnerSpawner {
pub fn spawn_spin_task(
&self,
shared_renderer: Arc<Mutex<Renderer>>,
shared_renderer: SharedRenderer<Index>,
spin_duration: Duration,
) -> JoinHandle<()> {
let shared = self.shared.clone();
@@ -42,9 +43,9 @@ impl SpinnerSpawner {
{
// TODO: error handling
let _ = shared_renderer
.lock()
.await
.update_and_draw([(PaneIndex::Processor, pane)]);
.update([(Index::Processor, pane)])
.render()
.await;
}
}
})
+95 -82
View File
@@ -2,17 +2,23 @@ use std::{io, sync::Arc, time::Duration};
use arboard::Clipboard;
use futures::StreamExt;
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},
use promkit_widgets::{
core::{
crossterm::{
cursor,
event::{
Event, EventStream, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers,
},
execute,
style::{Color, ContentStyle},
terminal::{self, disable_raw_mode, enable_raw_mode},
},
pane::EMPTY_PANE,
render::{Renderer, SharedRenderer},
PaneFactory,
},
PaneFactory,
text::{self, Text},
};
use promkit_widgets::text::{self, Text};
use tokio::{
sync::{mpsc, Mutex, RwLock},
task::JoinHandle,
@@ -20,8 +26,8 @@ use tokio::{
use crate::{
config::{event::Matcher, Keybinds, ReactivityControl},
Context, ContextMonitor, Editor, PaneIndex, Processor, Renderer, SearchProvider,
SpinnerSpawner, ViewInitializer, ViewProvider, Visualizer, EMPTY_PANE,
Context, ContextMonitor, Editor, Processor, SearchProvider, SpinnerSpawner, ViewInitializer,
ViewProvider, Visualizer,
};
fn spawn_debouncer<T: Send + 'static>(
@@ -90,6 +96,14 @@ enum Focus {
Processor,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Index {
Editor = 0,
Guide = 1,
Search = 2,
Processor = 3,
}
#[allow(clippy::too_many_arguments)]
pub async fn run<T: ViewProvider + SearchProvider>(
item: &'static str,
@@ -105,15 +119,19 @@ pub async fn run<T: ViewProvider + SearchProvider>(
let size = terminal::size()?;
let shared_renderer = Arc::new(Mutex::new(Renderer::try_init_draw(
[
editor.create_editor_pane(size.0, size.1),
EMPTY_PANE.to_owned(),
EMPTY_PANE.to_owned(),
EMPTY_PANE.to_owned(),
],
no_hint,
)?));
let shared_renderer = SharedRenderer::new(
Renderer::try_new_with_panes(
[
(Index::Editor, editor.create_editor_pane(size.0, size.1)),
(Index::Guide, EMPTY_PANE.to_owned()),
(Index::Search, EMPTY_PANE.to_owned()),
(Index::Processor, EMPTY_PANE.to_owned()),
]
.into_iter(),
true,
)
.await?,
);
let ctx = Arc::new(Mutex::new(Context::new(size)));
@@ -190,24 +208,23 @@ pub async fn run<T: ViewProvider + SearchProvider>(
kind: KeyEventKind::Press,
state: KeyEventState::NONE,
}) => {
let mut pane = EMPTY_PANE.to_owned();
if context_monitor.is_idle().await {
processor_copy_tx.send(()).await?;
} else {
} else if !no_hint{
let size = terminal::size()?;
pane = text::State {
text: Text::from("Failed to copy while rendering is in progress.".to_string()),
style: ContentStyle {
foreground_color: Some(Color::Yellow),
..Default::default()
},
..Default::default()
}.create_pane(size.0, size.1);
}
{
shared_renderer.lock().await.update_and_draw([
(PaneIndex::Guide, pane),
])?;
shared_renderer.update([
(
Index::Guide,
text::State {
text: Text::from("Failed to copy while rendering is in progress.".to_string()),
style: ContentStyle {
foreground_color: Some(Color::Yellow),
..Default::default()
},
..Default::default()
}.create_pane(size.0, size.1),
),
]).render().await?;
}
},
Event::Key(KeyEvent {
@@ -223,25 +240,23 @@ pub async fn run<T: ViewProvider + SearchProvider>(
}) => {
match focus {
Focus::Editor => {
let mut pane = EMPTY_PANE.to_owned();
if context_monitor.is_idle().await {
focus = Focus::Processor;
editor_focus_tx.send(false).await?;
} else {
} else if !no_hint{
let size = terminal::size()?;
pane = text::State {
text: Text::from("Failed to switch pane while rendering is in progress.".to_string()),
style: ContentStyle {
foreground_color: Some(Color::Yellow),
..Default::default()
},
..Default::default()
}.create_pane(size.0, size.1);
}
{
shared_renderer.lock().await.update_and_draw([
(PaneIndex::Guide, pane),
])?;
shared_renderer.update([
(
Index::Guide,
text::State {
text: Text::from("Failed to switch pane while rendering is in progress.".to_string()),
style: ContentStyle {
foreground_color: Some(Color::Yellow),
..Default::default()
},
..Default::default()
}.create_pane(size.0, size.1)),
]).render().await?;
}
},
Focus::Processor => {
@@ -290,25 +305,23 @@ pub async fn run<T: ViewProvider + SearchProvider>(
editor.create_guide_pane(size.0, size.1),
)
};
{
shared_renderer.lock().await.update_and_draw([
(PaneIndex::Editor, editor_pane),
(PaneIndex::Guide, guide_pane),
])?;
}
shared_renderer.update([
(Index::Editor, editor_pane),
(Index::Guide, if !no_hint { guide_pane } else { EMPTY_PANE.to_owned() }),
]).render().await?;
}
Some(()) = editor_copy_rx.recv() => {
let text = {
let editor = shared_editor.write().await;
let editor = shared_editor.read().await;
editor.text()
};
let guide = copy_to_clipboard(&text);
let size = terminal::size()?;
let pane = guide.create_pane(size.0, size.1);
{
shared_renderer.lock().await.update_and_draw([
(PaneIndex::Guide, pane),
])?;
if !no_hint {
let size = terminal::size()?;
let pane = guide.create_pane(size.0, size.1);
shared_renderer.update([
(Index::Guide, pane),
]).render().await?;
}
}
Some(event) = editor_event_rx.recv() => {
@@ -331,11 +344,11 @@ pub async fn run<T: ViewProvider + SearchProvider>(
)
};
{
shared_renderer.lock().await.update_and_draw([
(PaneIndex::Editor, editor_pane),
(PaneIndex::Guide, guide_pane),
(PaneIndex::Search, searcher_pane),
])?;
shared_renderer.update([
(Index::Editor, editor_pane),
(Index::Guide, if !no_hint { guide_pane } else { EMPTY_PANE.to_owned() }),
(Index::Search, searcher_pane),
]).render().await?;
}
}
else => {
@@ -358,12 +371,12 @@ pub async fn run<T: ViewProvider + SearchProvider>(
Some(()) = processor_copy_rx.recv() => {
let visualizer = shared_visualizer.lock().await;
let guide = copy_to_clipboard(&visualizer.content_to_copy().await);
let size = terminal::size()?;
let pane = guide.create_pane(size.0, size.1);
{
shared_renderer.lock().await.update_and_draw([
(PaneIndex::Guide, pane),
])?;
if !no_hint {
let size = terminal::size()?;
let pane = guide.create_pane(size.0, size.1);
shared_renderer.update([
(Index::Guide, pane),
]).render().await?;
}
}
Some(event) = processor_event_rx.recv() => {
@@ -372,9 +385,9 @@ pub async fn run<T: ViewProvider + SearchProvider>(
visualizer.create_pane_from_event((size.0, size.1), &event).await
};
{
shared_renderer.lock().await.update_and_draw([
(PaneIndex::Processor, pane),
])?;
shared_renderer.update([
(Index::Processor, pane),
]).render().await?;
}
}
Some(query) = last_query_rx.recv() => {
@@ -394,11 +407,11 @@ pub async fn run<T: ViewProvider + SearchProvider>(
)
};
{
shared_renderer.lock().await.update_and_draw([
(PaneIndex::Editor, editor_pane),
(PaneIndex::Guide, guide_pane),
(PaneIndex::Search, searcher_pane),
])?;
shared_renderer.update([
(Index::Editor, editor_pane),
(Index::Guide, if !no_hint { guide_pane } else { EMPTY_PANE.to_owned() }),
(Index::Search, searcher_pane),
]).render().await?;
}
let text = {
let editor = shared_editor.read().await;
-49
View File
@@ -1,49 +0,0 @@
use std::sync::LazyLock;
use promkit_core::{crossterm::cursor, pane::Pane, terminal::Terminal};
// TODO: One Guide is sufficient.
#[derive(Debug, PartialEq)]
pub enum PaneIndex {
Editor = 0,
Guide = 1,
Search = 2,
Processor = 3,
}
pub static EMPTY_PANE: LazyLock<Pane> = LazyLock::new(|| Pane::new(vec![], 0));
const PANE_SIZE: usize = PaneIndex::Processor as usize + 1;
pub struct Renderer {
no_hint: bool,
terminal: Terminal,
panes: [Pane; PANE_SIZE],
}
impl Renderer {
pub fn try_init_draw(init_panes: [Pane; PANE_SIZE], no_hint: bool) -> anyhow::Result<Self> {
let mut ret = Self {
no_hint,
terminal: Terminal {
position: cursor::position()?,
},
panes: init_panes,
};
ret.terminal.draw(&ret.panes)?;
Ok(ret)
}
pub fn update_and_draw<I: IntoIterator<Item = (PaneIndex, Pane)>>(
&mut self,
iter: I,
) -> anyhow::Result<()> {
for (index, pane) in iter {
if self.no_hint && index == PaneIndex::Guide {
continue;
}
self.panes[index as usize] = pane;
}
self.terminal.draw(&self.panes)?;
Ok(())
}
}
+4 -2
View File
@@ -2,8 +2,10 @@ use std::{collections::BTreeSet, sync::Arc};
use anyhow::anyhow;
use async_trait::async_trait;
use promkit_core::{pane::Pane, PaneFactory};
use promkit_widgets::listbox::{self, Listbox};
use promkit_widgets::{
core::{pane::Pane, PaneFactory},
listbox::{self, Listbox},
};
use tokio::{
sync::{Mutex, RwLock},
task::JoinHandle,