Skip to content

Commit

Permalink
chore!: Refactor popup (#49)
Browse files Browse the repository at this point in the history
These changes were done to relax the dependency on ratatui directly,
instead aiming to depend on ratatui-core.
To do this requires avoiding the unstable widget-ref feature. This is a
preparatory change to support that effort (if it's possible and aligns
to the ratatui modularization work going on in 0.30.0 (currently
pointing at the alpha.0 release).

BREAKING CHANGE: `SizedWidgetRef` is now `KnownSize`. It no longer
requires you to implement `WidgetRef` (this requirement is on the popup
now instead of in the trait). It also no longer requires you to
implement Debug.

`SizedWrapper` is now `KnownSizeWrapper`

The popup no longer implements `WidgetRef` and `StatefulWidgetRef`
directly, instead implements `{Stateful,}Widget for &Popup`

---

- **refactor: Move sized widget code to modules**
  
- **feat: impl SizeWidgetRef for String**
  
- **feat: impl StatefulWidget instead of _Ref**
  - impl StatefulWidget for Popup and &Popup
  - add tests
  - add PartialEq for testing Popups
  - add bacon setup for unit tests
  - remove --color always from bacon.toml
  
- **feat: impl Widget for Popup**
  impl Widget for &Popup and Popup Instead of WidgetRef (ratatui now has
  a blanket impl of WidgetRef for this.
  
  Remove the need for Widgets contained in the popup to implement debug.
  
- **chore: test SizedWrapper, add setters and new()**
  
- **feat!: Rename SizedWidgetRef to KnownSize**
The trait no longer requires implementors to also implement WidgetRef as
  that requirement is moved to the Popup generic bounds.
  
As a result, this means that a better name was needed. Sized is probably
the right name for this, except there is a well known trait in rust with
  the same name and this would be confusing. Instead I went with
  `KnownSize`.
  
  BREAKING CHANGE: SizedWidgetRef is now named `KnownSize` and no longer
  requires implementing WidgetRef.
  

- **feat: Rename SizedWrapper to KnownSizeWrapper.**
  

- **refactor: remove unnecessary generic bounds**
  

- **feat: implement KnownSize trait for Text**
  refactor popup rendering code, examples,
  • Loading branch information
joshka authored Nov 28, 2024
1 parent ebb8c96 commit c51ac3c
Show file tree
Hide file tree
Showing 12 changed files with 419 additions and 279 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ jobs:
checks: write
uses: joshka/github-workflows/.github/workflows/rust-check.yml@main
with:
msrv: 1.74.0
msrv: 1.80.0
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[workspace]
resolver = "2"
members = ["tui-*"]
default-members = ["tui-*"]

[workspace.package]
authors = ["Joshka"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/joshka/tui-widgets"
edition = "2021"
rust-version = "1.74.0"
rust-version = "1.80.0"
categories = ["command-line-interface", "gui"]
keywords = ["cli", "console", "ratatui", "terminal", "tui"]

Expand All @@ -23,6 +24,7 @@ futures = "0.3.31"
itertools = "0.13.0"
indoc = "2.0.5"
lipsum = "0.9.1"
pretty_assertions = "1.4.1"
ratatui = { version = "0.30.0-alpha.0", default-features = false }
ratatui-core = { version = "0.1.0-alpha.0" }
ratatui-macros = "0.7.0-alpha.0"
Expand Down
60 changes: 11 additions & 49 deletions bacon.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,23 @@
default_job = "check"

[jobs.check]
command = ["cargo", "check", "--workspace", "--color", "always"]
command = ["cargo", "check", "--workspace"]
need_stdout = false

[jobs.check-all]
command = [
"cargo",
"check",
"--workspace",
"--all-targets",
"--color",
"always",
]
command = ["cargo", "check", "--workspace", "--all-targets", "--all-features"]
need_stdout = false

[jobs.clippy]
command = [
"cargo",
"clippy",
"--workspace",
"--all-features",
"--all-targets",
"--color",
"always",
]
command = ["cargo", "clippy", "--workspace", "--all-features", "--all-targets"]
need_stdout = false

[jobs.test]
command = [
"cargo",
"test",
"--workspace",
"--color",
"always",
"--",
"--color",
"always", # see https://github.com/Canop/bacon/issues/124
]
command = ["cargo", "test", "--workspace"]
need_stdout = true

[jobs.test-unit]
command = ["cargo", "test", "--workspace", "--lib"]
need_stdout = true

[jobs.doc]
Expand All @@ -55,8 +35,6 @@ command = [
"-Zunstable-options",
"-Zrustdoc-scrape-examples",
"--all-features",
"--color",
"always",
"--no-deps",
]
need_stdout = false
Expand All @@ -71,8 +49,6 @@ command = [
"-Zunstable-options",
"-Zrustdoc-scrape-examples",
"--all-features",
"--color",
"always",
"--no-deps",
"--open",
]
Expand All @@ -84,27 +60,12 @@ on_success = "job:doc" # so that we don't open the browser at each change
# way. Don't forget the `--color always` part or the errors won't be
# properly parsed.
[jobs.run]
command = [
"cargo",
"run",
"--color",
"always",
# put launch parameters for your program behind a `--` separator
]
command = ["cargo", "run"]
need_stdout = true
allow_warnings = true

[jobs.coverage]
command = [
"cargo",
"llvm-cov",
"--workspace",
"--lcov",
"--output-path",
"target/lcov.info",
"--color",
"always",
]
command = ["cargo", "llvm-cov", "--workspace", "--lcov", "--output-path", "target/lcov.info"]

[jobs.format]
command = ["cargo", "+nightly", "fmt", "--", "--check"]
Expand All @@ -128,3 +89,4 @@ shift-r = "job:rdme"
f = "job:format"
o = "job:coverage"
v = "job:vhs"
u = "job:test-unit"
1 change: 1 addition & 0 deletions tui-popup/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ derive_setters.workspace = true
ratatui = { workspace = true, features = ["unstable-widget-ref"] }

[dev-dependencies]
pretty_assertions.workspace = true
color-eyre.workspace = true
lipsum.workspace = true

Expand Down
69 changes: 35 additions & 34 deletions tui-popup/examples/paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,57 @@ use ratatui::{
widgets::{Paragraph, Wrap},
Frame,
};
use tui_popup::{Popup, SizedWrapper};

mod terminal;
use tui_popup::{KnownSizeWrapper, Popup};

fn main() -> Result<()> {
let mut terminal = terminal::init()?;
let mut app = App::default();
while !app.should_exit {
terminal.draw(|frame| app.render(frame))?;
app.handle_events()?;
}
terminal::restore()?;
Ok(())
color_eyre::install()?;
let terminal = ratatui::init();
let result = App::default().run(terminal);
ratatui::restore();
result
}

#[derive(Default)]
struct App {
should_exit: bool,
lorem_ipsum: String,
scroll: u16,
}

impl App {
fn run(&mut self, mut terminal: ratatui::DefaultTerminal) -> Result<()> {
self.lorem_ipsum = lipsum(2000);
while !self.should_exit {
terminal.draw(|frame| self.render(frame))?;
self.handle_events()?;
}
Ok(())
}

fn render(&self, frame: &mut Frame) {
let area = frame.area();
let background = background(area);
self.render_background(frame, area);
self.render_popup(frame);
}

let paragraph = paragraph(self.scroll);
let popup = Popup::new(paragraph)
fn render_background(&self, frame: &mut Frame, area: Rect) {
let text = Text::raw(&self.lorem_ipsum);
let paragraph = Paragraph::new(text).wrap(Wrap { trim: false }).dark_gray();
frame.render_widget(paragraph, area);
}

fn render_popup(&self, frame: &mut Frame) {
let lines: Text = (0..10).map(|i| Span::raw(format!("Line {i}"))).collect();
let paragraph = Paragraph::new(lines).scroll((self.scroll, 0));
let wrapper = KnownSizeWrapper {
inner: &paragraph,
width: 21,
height: 5,
};
let popup = Popup::new(wrapper)
.title("scroll: ↑/↓ quit: Esc")
.style(Style::new().white().on_blue());

frame.render_widget(background, area);
frame.render_widget(&popup, area);
frame.render_widget(popup, frame.area());
}

fn handle_events(&mut self) -> Result<()> {
Expand All @@ -61,20 +79,3 @@ impl App {
self.scroll = self.scroll.saturating_add(1);
}
}

fn paragraph(scroll: u16) -> SizedWrapper<Paragraph<'static>> {
let lines: Text = (0..10).map(|i| Span::raw(format!("Line {i}"))).collect();
let paragraph = Paragraph::new(lines).scroll((scroll, 0));
SizedWrapper {
inner: paragraph,
width: 21,
height: 5,
}
}

fn background(area: Rect) -> Paragraph<'static> {
let lorem_ipsum = lipsum(area.area() as usize / 5);
Paragraph::new(lorem_ipsum)
.wrap(Wrap { trim: false })
.dark_gray()
}
26 changes: 13 additions & 13 deletions tui-popup/examples/popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@ use ratatui::{
};
use tui_popup::Popup;

mod terminal;

fn main() -> Result<()> {
let mut terminal = terminal::init()?;
color_eyre::install()?;
let mut terminal = ratatui::init();
let result = run(&mut terminal);
ratatui::restore();
result
}

fn run(terminal: &mut ratatui::DefaultTerminal) -> Result<()> {
loop {
terminal.draw(render)?;
if read_any_key()? {
break;
terminal.draw(|frame| {
render(frame);
})?;
if matches!(event::read()?, Event::Key(_)) {
break Ok(());
}
}
terminal::restore()?;
Ok(())
}

fn render(frame: &mut Frame) {
Expand All @@ -32,11 +37,6 @@ fn render(frame: &mut Frame) {
frame.render_widget(&popup, area);
}

fn read_any_key() -> Result<bool> {
let event = event::read()?;
Ok(matches!(event, Event::Key(_)))
}

fn background(area: Rect) -> Paragraph<'static> {
let lorem_ipsum = lipsum(area.area() as usize / 5);
Paragraph::new(lorem_ipsum)
Expand Down
Loading

0 comments on commit c51ac3c

Please sign in to comment.