From f24fc7574fac02ed3c5c15bf2a67c54cb675e838 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Fri, 31 May 2024 13:49:51 +0200 Subject: [PATCH] patch: Adjust to new API --- bin/commands/patch/select.rs | 285 ++++++++++++++++++-- bin/commands/patch/select/ui.rs | 456 +++----------------------------- src/ui/widget/list.rs | 1 + 3 files changed, 303 insertions(+), 439 deletions(-) diff --git a/bin/commands/patch/select.rs b/bin/commands/patch/select.rs index 799b39a4..1855fd55 100644 --- a/bin/commands/patch/select.rs +++ b/bin/commands/patch/select.rs @@ -11,16 +11,23 @@ use radicle::Profile; use radicle_tui as tui; +use ratatui::layout::Constraint; +use ratatui::style::Stylize; +use ratatui::text::{Line, Span, Text}; + +use termion::event::Key; use tui::cob::patch; use tui::store; use tui::ui::items::{Filter, PatchItem, PatchItemFilter}; -use tui::ui::widget::window::{Window, WindowProps}; -use tui::ui::widget::ToWidget; +use tui::ui::span; +use tui::ui::widget::container::{Column, Container, Footer, FooterProps, Header, HeaderProps}; +use tui::ui::widget::text::{Paragraph, ParagraphProps}; +use tui::ui::widget::window::{Page, PageProps, Shortcuts, ShortcutsProps, Window, WindowProps}; +use tui::ui::widget::{ToWidget, Widget}; use tui::{BoxedAny, Channel, Exit, PageStack}; -use self::ui::HelpPage; -use self::ui::{BrowserPage, BrowserPageProps}; +use self::ui::{Browser, BrowserProps}; use super::common::Mode; @@ -38,7 +45,7 @@ pub struct App { } #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum Page { +pub enum AppPage { Browse, Help, } @@ -72,7 +79,7 @@ pub struct HelpState { #[derive(Clone, Debug)] pub struct State { mode: Mode, - pages: PageStack, + pages: PageStack, browser: BrowserState, help: HelpState, } @@ -96,7 +103,7 @@ impl TryFrom<&Context> for State { Ok(Self { mode: context.mode.clone(), - pages: PageStack::new(vec![Page::Browse]), + pages: PageStack::new(vec![AppPage::Browse]), browser: BrowserState { items, selected: Some(0), @@ -176,7 +183,7 @@ impl store::State for State { None } Message::OpenHelp => { - self.pages.push(Page::Help); + self.pages.push(AppPage::Help); None } Message::LeavePage => { @@ -204,17 +211,12 @@ impl App { let tx = channel.tx.clone(); let window = Window::default() - .page( - Page::Browse, - BrowserPage::new(tx.clone()) - .to_widget(tx.clone()) - .on_update(|state| BrowserPageProps::from(state).to_boxed_any().into()), - ) - .page(Page::Help, HelpPage::new(tx.clone()).to_widget(tx.clone())) + .page(AppPage::Browse, browser_page(&state, &channel)) + .page(AppPage::Help, help_page(&state, &channel)) .to_widget(tx.clone()) .on_update(|state| { WindowProps::default() - .current_page(state.pages.peek().unwrap_or(&Page::Browse).clone()) + .current_page(state.pages.peek().unwrap_or(&AppPage::Browse).clone()) .to_boxed_any() .into() }); @@ -222,3 +224,254 @@ impl App { tui::run(channel, state, window).await } } + +fn browser_page(_state: &State, channel: &Channel) -> Widget { + let tx = channel.tx.clone(); + + let content = Browser::new(tx.clone()) + .to_widget(tx.clone()) + .on_update(|state| BrowserProps::from(state).to_boxed_any().into()); + + let shortcuts = Shortcuts::default() + .to_widget(tx.clone()) + .on_update(|state: &State| { + let shortcuts = if state.browser.show_search { + vec![("esc", "cancel"), ("enter", "apply")] + } else { + match state.mode { + Mode::Id => vec![("enter", "select"), ("/", "search")], + Mode::Operation => vec![ + ("enter", "show"), + ("c", "checkout"), + ("d", "diff"), + ("/", "search"), + ("?", "help"), + ], + } + }; + + ShortcutsProps::default() + .shortcuts(&shortcuts) + .to_boxed_any() + .into() + }); + + Page::default() + .content(content) + .shortcuts(shortcuts) + .to_widget(tx.clone()) + .on_event(|key, _, props| { + let default = PageProps::default(); + let props = props + .and_then(|props| props.inner_ref::()) + .unwrap_or(&default); + + if props.handle_keys { + match key { + Key::Esc | Key::Ctrl('c') => Some(Message::Exit { selection: None }), + Key::Char('?') => Some(Message::OpenHelp), + _ => None, + } + } else { + None + } + }) + .on_update(|state: &State| { + PageProps::default() + .page_size(state.browser.page_size) + .handle_keys(!state.browser.show_search) + .to_boxed_any() + .into() + }) + .on_render(|props, render| { + let default = PageProps::default(); + let props = props + .and_then(|props| props.inner_ref::()) + .unwrap_or(&default); + let page_size = render.area.height.saturating_sub(6) as usize; + + if page_size != props.page_size { + return Some(Message::BrowserPageSize(page_size)); + } + None + }) +} + +fn help_page(_state: &State, channel: &Channel) -> Widget { + let tx = channel.tx.clone(); + + let content = Container::default() + .header(Header::default().to_widget(tx.clone()).on_update(|_| { + HeaderProps::default() + .columns([Column::new(" Help ", Constraint::Fill(1))].to_vec()) + .to_boxed_any() + .into() + })) + .content( + Paragraph::default() + .to_widget(tx.clone()) + .on_event(|_, s, _| { + Some(Message::ScrollHelp { + progress: s.and_then(|p| p.unwrap_usize()).unwrap_or_default(), + }) + }) + .on_update(|state: &State| { + ParagraphProps::default() + .text(&help_text()) + .page_size(state.help.page_size) + .to_boxed_any() + .into() + }), + ) + .footer( + Footer::default() + .to_widget(tx.clone()) + .on_update(|state: &State| { + FooterProps::default() + .columns( + [ + Column::new(Text::raw(""), Constraint::Fill(1)), + Column::new( + span::default(&format!("{}%", state.help.progress)).dim(), + Constraint::Min(4), + ), + ] + .to_vec(), + ) + .to_boxed_any() + .into() + }), + ) + .to_widget(tx.clone()); + + let shortcuts = Shortcuts::default().to_widget(tx.clone()).on_update(|_| { + ShortcutsProps::default() + .shortcuts(&[("?", "close")]) + .to_boxed_any() + .into() + }); + + Page::default() + .content(content) + .shortcuts(shortcuts) + .to_widget(tx.clone()) + .on_event(|key, _, _| match key { + Key::Esc | Key::Ctrl('c') => Some(Message::Exit { selection: None }), + Key::Char('?') => Some(Message::LeavePage), + _ => None, + }) + .on_update(|state: &State| { + PageProps::default() + .page_size(state.help.page_size) + .handle_keys(true) + .to_boxed_any() + .into() + }) + .on_render(|props, render| { + let default = PageProps::default(); + let props = props + .and_then(|props| props.inner_ref::()) + .unwrap_or(&default); + let page_size = render.area.height.saturating_sub(6) as usize; + + if page_size != props.page_size { + return Some(Message::HelpPageSize(page_size)); + } + None + }) +} + +fn help_text() -> Text<'static> { + Text::from( + [ + Line::from(Span::raw("Generic keybindings").cyan()), + Line::raw(""), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "↑,k")).gray(), + Span::raw(" "), + Span::raw("move cursor one line up").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "↓,j")).gray(), + Span::raw(" "), + Span::raw("move cursor one line down").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "PageUp")).gray(), + Span::raw(" "), + Span::raw("move cursor one page up").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "PageDown")).gray(), + Span::raw(" "), + Span::raw("move cursor one page down").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "Home")).gray(), + Span::raw(" "), + Span::raw("move cursor to the first line").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "End")).gray(), + Span::raw(" "), + Span::raw("move cursor to the last line").gray().dim(), + ]), + Line::raw(""), + Line::from(Span::raw("Specific keybindings").cyan()), + Line::raw(""), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "enter")).gray(), + Span::raw(" "), + Span::raw("Select patch (if --mode id)").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "enter")).gray(), + Span::raw(" "), + Span::raw("Show patch").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "c")).gray(), + Span::raw(" "), + Span::raw("Checkout patch").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "d")).gray(), + Span::raw(" "), + Span::raw("Show patch diff").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "/")).gray(), + Span::raw(" "), + Span::raw("Search").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "?")).gray(), + Span::raw(" "), + Span::raw("Show help").gray().dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "Esc")).gray(), + Span::raw(" "), + Span::raw("Quit / cancel").gray().dim(), + ]), + Line::raw(""), + Line::from(Span::raw("Searching").cyan()), + Line::raw(""), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "Pattern")).gray(), + Span::raw(" "), + Span::raw("is: | is:authored | authors:[, ] | ") + .gray() + .dim(), + ]), + Line::from(vec![ + Span::raw(format!("{key:>10}", key = "Example")).gray(), + Span::raw(" "), + Span::raw("is:open is:authored improve").gray().dim(), + ]), + Line::raw(""), + Line::raw(""), + ] + .to_vec(), + ) +} diff --git a/bin/commands/patch/select/ui.rs b/bin/commands/patch/select/ui.rs index a9c3a54d..ce7c8add 100644 --- a/bin/commands/patch/select/ui.rs +++ b/bin/commands/patch/select/ui.rs @@ -9,7 +9,7 @@ use termion::event::Key; use ratatui::layout::{Constraint, Layout}; use ratatui::style::Stylize; -use ratatui::text::{Line, Span, Text}; +use ratatui::text::{Line, Text}; use radicle::patch; use radicle::patch::Status; @@ -20,13 +20,10 @@ use tui::ui::items::{PatchItem, PatchItemFilter}; use tui::ui::span; use tui::ui::widget; use tui::ui::widget::container::{ - Column, Container, ContainerProps, Footer, FooterProps, Header, HeaderProps, SectionGroup, - SectionGroupProps, + Column, Container, ContainerProps, Footer, FooterProps, Header, HeaderProps, }; use tui::ui::widget::input::{TextField, TextFieldProps}; use tui::ui::widget::list::{Table, TableProps, TableUtils}; -use tui::ui::widget::text::{Paragraph, ParagraphProps}; -use tui::ui::widget::window::{Shortcuts, ShortcutsProps}; use tui::ui::widget::ViewProps; use tui::ui::widget::{RenderProps, ToWidget, View}; @@ -139,15 +136,18 @@ pub struct Browser { } impl Browser { - fn new(tx: UnboundedSender) -> Self { + pub fn new(tx: UnboundedSender) -> Self { Self { patches: Container::default() - .header( - Header::default() - // .columns(props.header.clone()) - // .cutoff(props.cutoff, props.cutoff_after) - .to_widget(tx.clone()), - ) + .header(Header::default().to_widget(tx.clone()).on_update(|state| { + // TODO: remove and use state directly + let props = BrowserProps::from(state); + HeaderProps::default() + .columns(props.header.clone()) + .cutoff(props.cutoff, props.cutoff_after) + .to_boxed_any() + .into() + })) .content( Table::::default() .to_widget(tx.clone()) @@ -157,8 +157,8 @@ impl Browser { }) }) .on_update(|state| { + // TODO: remove and use state directly let props = BrowserProps::from(state); - TableProps::default() .columns(props.columns) .items(state.browser.patches()) @@ -171,10 +171,11 @@ impl Browser { }), ) .footer(Footer::default().to_widget(tx.clone()).on_update(|state| { + // TODO: remove and use state directly let props = BrowserProps::from(state); FooterProps::default() - .columns(browse_footer(&props, props.selected)) + .columns(browser_footer(&props, props.selected)) .to_boxed_any() .into() })) @@ -185,7 +186,23 @@ impl Browser { .to_boxed_any() .into() }), - search: Search::new(tx.clone()).to_widget(tx.clone()), + search: TextField::default() + .to_widget(tx.clone()) + .on_event(|key, s, _| match key { + Key::Esc => Some(Message::CloseSearch), + Key::Char('\n') => Some(Message::ApplySearch), + _ => Some(Message::UpdateSearch { + value: s.and_then(|i| i.unwrap_string()).unwrap_or_default(), + }), + }) + .on_update(|state: &State| { + TextFieldProps::default() + .text(&state.browser.search.read().to_string()) + .title("Search") + .inline(true) + .to_boxed_any() + .into() + }), } } } @@ -277,319 +294,7 @@ impl View for Browser { } } -#[derive(Clone, Default)] -pub struct BrowserPageProps<'a> { - /// Current page size (height of table content). - page_size: usize, - /// If this pages' keys should be handled (`false` if search is shown). - handle_keys: bool, - /// This pages' shortcuts. - shortcuts: Vec<(&'a str, &'a str)>, -} - -impl<'a> From<&State> for BrowserPageProps<'a> { - fn from(state: &State) -> Self { - Self { - page_size: state.browser.page_size, - handle_keys: !state.browser.show_search, - shortcuts: if state.browser.show_search { - vec![("esc", "cancel"), ("enter", "apply")] - } else { - match state.mode { - Mode::Id => vec![("enter", "select"), ("/", "search")], - Mode::Operation => vec![ - ("enter", "show"), - ("c", "checkout"), - ("d", "diff"), - ("/", "search"), - ("?", "help"), - ], - } - }, - } - } -} - -pub struct BrowserPage { - /// Sections widget - sections: Widget, - /// Shortcut widget - shortcuts: Widget, -} - -impl BrowserPage { - pub fn new(tx: UnboundedSender) -> Self { - Self { - sections: SectionGroup::default() - .section(Browser::new(tx.clone()).to_widget(tx.clone())) - .to_widget(tx.clone()) - .on_update(|state| { - let props = BrowserPageProps::from(state); - SectionGroupProps::default() - .handle_keys(props.handle_keys) - .to_boxed_any() - .into() - }), - shortcuts: Shortcuts::default() - .to_widget(tx.clone()) - .on_update(|state| { - ShortcutsProps::default() - .shortcuts(&BrowserPageProps::from(state).shortcuts) - .to_boxed_any() - .into() - }), - } - } -} - -impl View for BrowserPage { - type Message = Message; - type State = State; - - fn handle_event(&mut self, props: Option<&ViewProps>, key: Key) -> Option { - let default = BrowserPageProps::default(); - let props = props - .and_then(|props| props.inner_ref::()) - .unwrap_or(&default); - - self.sections.handle_event(key); - - if props.handle_keys { - return match key { - Key::Esc | Key::Ctrl('c') => Some(Message::Exit { selection: None }), - Key::Char('?') => Some(Message::OpenHelp), - _ => None, - }; - } - - None - } - - fn update(&mut self, _props: Option<&ViewProps>, state: &Self::State) { - self.sections.update(state); - self.shortcuts.update(state); - } - - fn render(&self, props: Option<&ViewProps>, render: RenderProps, frame: &mut Frame) { - let default = BrowserPageProps::default(); - let props = props - .and_then(|props| props.inner_ref::()) - .unwrap_or(&default); - - let page_size = render.area.height.saturating_sub(6) as usize; - - let [content_area, shortcuts_area] = - Layout::vertical([Constraint::Min(1), Constraint::Length(1)]).areas(render.area); - - self.sections.render( - RenderProps::from(content_area) - .layout(Layout::horizontal([Constraint::Min(1)])) - .focus(true), - frame, - ); - self.shortcuts - .render(RenderProps::from(shortcuts_area), frame); - - // TODO: Find better solution - if page_size != props.page_size { - self.sections.send(Message::BrowserPageSize(page_size)); - } - } -} - -#[derive(Clone)] -pub struct SearchProps {} - -pub struct Search { - /// Search input field - input: Widget, -} - -impl Search { - fn new(tx: UnboundedSender) -> Self - where - Self: Sized, - { - Self { - input: TextField::default() - .to_widget(tx.clone()) - .on_event(|s, _| { - Some(Message::UpdateSearch { - value: s.and_then(|i| i.unwrap_string()).unwrap_or_default(), - }) - }) - .on_update(|state: &State| { - TextFieldProps::default() - .text(&state.browser.search.read().to_string()) - .title("Search") - .inline(true) - .to_boxed_any() - .into() - }), - } - } -} - -impl View for Search { - type Message = Message; - type State = State; - - fn handle_event(&mut self, _props: Option<&ViewProps>, key: Key) -> Option { - match key { - Key::Esc => Some(Message::CloseSearch), - Key::Char('\n') => Some(Message::ApplySearch), - _ => { - self.input.handle_event(key); - None - } - } - } - - fn update(&mut self, _props: Option<&ViewProps>, state: &Self::State) { - self.input.update(state); - } - - fn render(&self, _props: Option<&ViewProps>, render: RenderProps, frame: &mut Frame) { - let layout = Layout::horizontal(Constraint::from_mins([0])) - .horizontal_margin(1) - .split(render.area); - - self.input.render(RenderProps::from(layout[0]), frame); - } -} - -#[derive(Clone, Default)] -struct HelpPageProps<'a> { - /// Current page size (height of table content). - page_size: usize, - /// Scroll progress of help paragraph. - help_progress: usize, - /// This pages' shortcuts. - shortcuts: Vec<(&'a str, &'a str)>, -} - -impl<'a> From<&State> for HelpPageProps<'a> { - fn from(state: &State) -> Self { - Self { - page_size: state.help.page_size, - help_progress: state.help.progress, - shortcuts: vec![("?", "close")], - } - } -} - -pub struct HelpPage { - /// Content widget - content: Widget, - /// Shortcut widget - shortcuts: Widget, -} - -impl HelpPage { - pub fn new(tx: UnboundedSender) -> Self - where - Self: Sized, - { - Self { - content: Container::default() - .header(Header::default().to_widget(tx.clone()).on_update(|_| { - HeaderProps::default() - .columns([Column::new(" Help ", Constraint::Fill(1))].to_vec()) - .to_boxed_any() - .into() - })) - .content( - Paragraph::default() - .to_widget(tx.clone()) - .on_event(|_, s, _| { - Some(Message::ScrollHelp { - progress: s.and_then(|p| p.unwrap_usize()).unwrap_or_default(), - }) - }) - .on_update(|state| { - let props = HelpPageProps::from(state); - - ParagraphProps::default() - .text(&help_text()) - .page_size(props.page_size) - .to_boxed_any() - .into() - }), - ) - .footer(Footer::default().to_widget(tx.clone()).on_update(|state| { - let props = HelpPageProps::from(state); - - FooterProps::default() - .columns( - [ - Column::new(Text::raw(""), Constraint::Fill(1)), - Column::new( - span::default(&format!("{}%", props.help_progress)).dim(), - Constraint::Min(4), - ), - ] - .to_vec(), - ) - .to_boxed_any() - .into() - })) - .to_widget(tx.clone()), - shortcuts: Shortcuts::default() - .to_widget(tx.clone()) - .on_update(|state| { - ShortcutsProps::default() - .shortcuts(&HelpPageProps::from(state).shortcuts) - .to_boxed_any() - .into() - }), - } - } -} - -impl View for HelpPage { - type Message = Message; - type State = State; - - fn handle_event(&mut self, _props: Option<&ViewProps>, key: Key) -> Option { - match key { - Key::Esc | Key::Ctrl('c') => Some(Message::Exit { selection: None }), - Key::Char('?') => Some(Message::LeavePage), - _ => { - self.content.handle_event(key); - None - } - } - } - - fn update(&mut self, _props: Option<&ViewProps>, state: &Self::State) { - self.content.update(state); - self.shortcuts.update(state); - } - - fn render(&self, props: Option<&ViewProps>, render: RenderProps, frame: &mut Frame) { - let default = HelpPageProps::default(); - let props = props - .and_then(|props| props.inner_ref::()) - .unwrap_or(&default); - - let page_size = render.area.height.saturating_sub(6) as usize; - - let [content_area, shortcuts_area] = - Layout::vertical([Constraint::Min(1), Constraint::Length(1)]).areas(render.area); - - self.content - .render(RenderProps::from(content_area).focus(true), frame); - self.shortcuts - .render(RenderProps::from(content_area).focus(true), frame); - - // TODO: Find better solution - if page_size != props.page_size { - self.content.send(Message::HelpPageSize(page_size)); - } - } -} - -fn browse_footer<'a>(props: &BrowserProps<'a>, selected: Option) -> Vec> { +fn browser_footer<'a>(props: &BrowserProps<'a>, selected: Option) -> Vec> { let filter = PatchItemFilter::from_str(&props.search).unwrap_or_default(); let search = Line::from(vec![ @@ -673,98 +378,3 @@ fn browse_footer<'a>(props: &BrowserProps<'a>, selected: Option) -> Vec Text<'static> { - Text::from( - [ - Line::from(Span::raw("Generic keybindings").cyan()), - Line::raw(""), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "↑,k")).gray(), - Span::raw(" "), - Span::raw("move cursor one line up").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "↓,j")).gray(), - Span::raw(" "), - Span::raw("move cursor one line down").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "PageUp")).gray(), - Span::raw(" "), - Span::raw("move cursor one page up").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "PageDown")).gray(), - Span::raw(" "), - Span::raw("move cursor one page down").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "Home")).gray(), - Span::raw(" "), - Span::raw("move cursor to the first line").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "End")).gray(), - Span::raw(" "), - Span::raw("move cursor to the last line").gray().dim(), - ]), - Line::raw(""), - Line::from(Span::raw("Specific keybindings").cyan()), - Line::raw(""), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "enter")).gray(), - Span::raw(" "), - Span::raw("Select patch (if --mode id)").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "enter")).gray(), - Span::raw(" "), - Span::raw("Show patch").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "c")).gray(), - Span::raw(" "), - Span::raw("Checkout patch").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "d")).gray(), - Span::raw(" "), - Span::raw("Show patch diff").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "/")).gray(), - Span::raw(" "), - Span::raw("Search").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "?")).gray(), - Span::raw(" "), - Span::raw("Show help").gray().dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "Esc")).gray(), - Span::raw(" "), - Span::raw("Quit / cancel").gray().dim(), - ]), - Line::raw(""), - Line::from(Span::raw("Searching").cyan()), - Line::raw(""), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "Pattern")).gray(), - Span::raw(" "), - Span::raw("is: | is:authored | authors:[, ] | ") - .gray() - .dim(), - ]), - Line::from(vec![ - Span::raw(format!("{key:>10}", key = "Example")).gray(), - Span::raw(" "), - Span::raw("is:open is:authored improve").gray().dim(), - ]), - Line::raw(""), - Line::raw(""), - ] - .to_vec(), - ) -} diff --git a/src/ui/widget/list.rs b/src/ui/widget/list.rs index f52c6b31..e7cbfe51 100644 --- a/src/ui/widget/list.rs +++ b/src/ui/widget/list.rs @@ -209,6 +209,7 @@ where // .and_then(|props| props.inner_ref::>()) // .unwrap_or(&default); + // TODO // if props.selected != self.state.selected() { // self.state.select(props.selected); // }