mirror of
https://seed.radicle.dev/rad:z39mP9rQAaGmERfUMPULfPUi473tY.git
synced 2026-10-18 19:10:36 +08:00
bin: Use theme settings in issue selection
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
**Binary features:**
|
||||
|
||||
- Issue preview widgets in `issue select`
|
||||
- Basic theming support with light and dark theme bundles
|
||||
- Support for application settings
|
||||
|
||||
**Library features:**
|
||||
|
||||
|
||||
Generated
+89
-4
@@ -364,6 +364,12 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.9.1"
|
||||
@@ -435,6 +441,12 @@ version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "coolor"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e93977247fb916abeee1ff8c6594c9b421fd9c26c9b720a3944acb2a7de27b"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
@@ -478,6 +490,31 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.5.5"
|
||||
@@ -1040,9 +1077,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
dependencies = [
|
||||
"spin",
|
||||
]
|
||||
@@ -1168,6 +1205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
@@ -1192,6 +1230,18 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@@ -1819,6 +1869,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"fuzzy-matcher",
|
||||
"inquire",
|
||||
"lazy_static",
|
||||
"lexopt",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -1832,6 +1883,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"signal-hook",
|
||||
"simple-logging",
|
||||
"terminal-light",
|
||||
"termion 3.0.0",
|
||||
"textwrap",
|
||||
"thiserror",
|
||||
@@ -2111,6 +2163,17 @@ dependencies = [
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
@@ -2221,9 +2284,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
@@ -2404,6 +2467,18 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal-light"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2ecb7b6ab8a3eeff2b61770d313d1e971f184e29321785c62ef523b132437b7"
|
||||
dependencies = [
|
||||
"coolor",
|
||||
"crossterm",
|
||||
"thiserror",
|
||||
"xterm-query",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "2.0.3"
|
||||
@@ -3071,6 +3146,16 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xterm-query"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f29504d0a2ca8c1714781c1395a8a660d2557b2cf9c9669433153fc903e9bfc"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
|
||||
@@ -26,6 +26,7 @@ anyhow = { version = "1" }
|
||||
inquire = { version = "0.7.4", default-features = false, features = ["termion", "editor"] }
|
||||
lexopt = { version = "0.3.0" }
|
||||
fuzzy-matcher = "0.3.7"
|
||||
lazy_static = { version = "1.5.0" }
|
||||
libc = { version = "^0.2" }
|
||||
log = { version = "0.4.19" }
|
||||
nom = { version = "^7.1.0" }
|
||||
@@ -40,6 +41,7 @@ serde_json = { version = "1.0" }
|
||||
signal-hook = { version = "0.3.17" }
|
||||
timeago = { version = "0.4.1" }
|
||||
termion = { version = "3" }
|
||||
terminal-light = { version = "1.4.0" }
|
||||
textwrap = { version = "0.16.0" }
|
||||
thiserror = { version = "1" }
|
||||
tokio = { version = "1.32.0", features = ["full"] }
|
||||
|
||||
+13
-1
@@ -7,6 +7,8 @@ use std::ffi::OsString;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use radicle::identity::RepoId;
|
||||
use radicle::issue;
|
||||
|
||||
@@ -18,6 +20,13 @@ use radicle_tui as tui;
|
||||
use tui::log;
|
||||
|
||||
use crate::cob;
|
||||
use crate::ui::TerminalInfo;
|
||||
|
||||
lazy_static! {
|
||||
static ref TERMINAL_INFO: TerminalInfo = TerminalInfo {
|
||||
luma: Some(terminal_light::luma().unwrap_or_default())
|
||||
};
|
||||
}
|
||||
|
||||
pub const HELP: Help = Help {
|
||||
name: "issue",
|
||||
@@ -143,6 +152,8 @@ pub async fn run(options: Options, ctx: impl terminal::Context) -> anyhow::Resul
|
||||
let (_, rid) = radicle::rad::cwd()
|
||||
.map_err(|_| anyhow!("this command must be run in the context of a project"))?;
|
||||
|
||||
let terminal_info = TERMINAL_INFO.clone();
|
||||
|
||||
match options.op {
|
||||
Operation::Select { opts } => {
|
||||
let profile = ctx.profile()?;
|
||||
@@ -157,7 +168,8 @@ pub async fn run(options: Options, ctx: impl terminal::Context) -> anyhow::Resul
|
||||
mode: opts.mode,
|
||||
filter: opts.filter.clone(),
|
||||
};
|
||||
let output = select::App::new(context).run().await?;
|
||||
|
||||
let output = select::App::new(context, terminal_info).run().await?;
|
||||
|
||||
let output = output
|
||||
.map(|o| serde_json::to_string(&o).unwrap_or_default())
|
||||
|
||||
@@ -23,9 +23,10 @@ use radicle_tui as tui;
|
||||
use tui::store;
|
||||
use tui::store::StateValue;
|
||||
use tui::ui::span;
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::ui::widget::container::{
|
||||
Column, Container, Footer, FooterProps, Header, HeaderProps, SectionGroup, SectionGroupProps,
|
||||
SplitContainer, SplitContainerFocus, SplitContainerProps,
|
||||
Column, Container, ContainerProps, Footer, FooterProps, Header, HeaderProps, SectionGroup,
|
||||
SectionGroupProps, SplitContainer, SplitContainerFocus, SplitContainerProps,
|
||||
};
|
||||
use tui::ui::widget::input::{TextView, TextViewProps};
|
||||
use tui::ui::widget::list::{Tree, TreeProps};
|
||||
@@ -34,8 +35,10 @@ use tui::ui::widget::{PredefinedLayout, ToWidget, Widget};
|
||||
use tui::{BoxedAny, Channel, Exit, PageStack};
|
||||
|
||||
use crate::cob::issue;
|
||||
use crate::settings::{self, ThemeBundle, ThemeMode};
|
||||
use crate::ui::items::{CommentItem, Filter, IssueItem, IssueItemFilter};
|
||||
use crate::ui::widget::{IssueDetails, IssueDetailsProps};
|
||||
use crate::ui::TerminalInfo;
|
||||
|
||||
use self::ui::{Browser, BrowserProps};
|
||||
|
||||
@@ -52,6 +55,7 @@ pub struct Context {
|
||||
|
||||
pub struct App {
|
||||
context: Context,
|
||||
terminal_info: TerminalInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
@@ -230,16 +234,34 @@ pub struct State {
|
||||
preview: PreviewState,
|
||||
section: Option<Section>,
|
||||
help: HelpState,
|
||||
theme: Theme,
|
||||
}
|
||||
|
||||
impl TryFrom<&Context> for State {
|
||||
impl TryFrom<(&Context, &TerminalInfo)> for State {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(context: &Context) -> Result<Self, Self::Error> {
|
||||
fn try_from(value: (&Context, &TerminalInfo)) -> Result<Self, Self::Error> {
|
||||
let (context, terminal_info) = value;
|
||||
let settings = settings::Settings::default();
|
||||
|
||||
let issues = issue::all(&context.profile, &context.repository)?;
|
||||
let search = StateValue::new(context.filter.to_string());
|
||||
let filter = IssueItemFilter::from_str(&search.read()).unwrap_or_default();
|
||||
|
||||
let default_bundle = ThemeBundle::default();
|
||||
let theme_bundle = settings.theme.active_bundle().unwrap_or(&default_bundle);
|
||||
let theme = match settings.theme.mode() {
|
||||
ThemeMode::Auto => {
|
||||
if terminal_info.is_dark() {
|
||||
theme_bundle.dark.clone()
|
||||
} else {
|
||||
theme_bundle.light.clone()
|
||||
}
|
||||
}
|
||||
ThemeMode::Light => theme_bundle.light.clone(),
|
||||
ThemeMode::Dark => theme_bundle.dark.clone(),
|
||||
};
|
||||
|
||||
// Convert into UI items
|
||||
let mut items = vec![];
|
||||
for issue in issues {
|
||||
@@ -282,6 +304,7 @@ impl TryFrom<&Context> for State {
|
||||
scroll: 0,
|
||||
cursor: (0, 0),
|
||||
},
|
||||
theme,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -426,13 +449,16 @@ impl store::State<Selection> for State {
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(context: Context) -> Self {
|
||||
Self { context }
|
||||
pub fn new(context: Context, terminal_info: TerminalInfo) -> Self {
|
||||
Self {
|
||||
context,
|
||||
terminal_info,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(&self) -> Result<Option<Selection>> {
|
||||
let channel = Channel::default();
|
||||
let state = State::try_from(&self.context)?;
|
||||
let state = State::try_from((&self.context, &self.terminal_info))?;
|
||||
let tx = channel.tx.clone();
|
||||
|
||||
let window = Window::default()
|
||||
@@ -471,6 +497,8 @@ fn browser_page(channel: &Channel<Message>) -> Widget<State, Message> {
|
||||
|
||||
ShortcutsProps::default()
|
||||
.shortcuts(&shortcuts)
|
||||
.shortcuts_keys_style(state.theme.shortcuts_keys_style)
|
||||
.shortcuts_action_style(state.theme.shortcuts_action_style)
|
||||
.to_boxed_any()
|
||||
.into()
|
||||
});
|
||||
@@ -548,9 +576,11 @@ fn issue(channel: &Channel<Message>) -> Widget<State, Message> {
|
||||
.top(issue_details(channel))
|
||||
.bottom(comment_tree(channel))
|
||||
.to_widget(tx.clone())
|
||||
.on_update(|_| {
|
||||
.on_update(|state| {
|
||||
SplitContainerProps::default()
|
||||
.heights([Constraint::Length(5), Constraint::Min(1)])
|
||||
.border_color(state.theme.border_color)
|
||||
.focus_border_color(state.theme.focus_border_color)
|
||||
.split_focus(SplitContainerFocus::Bottom)
|
||||
.to_boxed_any()
|
||||
.into()
|
||||
@@ -641,6 +671,13 @@ fn comment(channel: &Channel<Message>) -> Widget<State, Message> {
|
||||
}),
|
||||
)
|
||||
.to_widget(tx.clone())
|
||||
.on_update(|state| {
|
||||
ContainerProps::default()
|
||||
.border_color(state.theme.border_color)
|
||||
.focus_border_color(state.theme.focus_border_color)
|
||||
.to_boxed_any()
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
fn help_page(channel: &Channel<Message>) -> Widget<State, Message> {
|
||||
@@ -691,7 +728,14 @@ fn help_page(channel: &Channel<Message>) -> Widget<State, Message> {
|
||||
.into()
|
||||
}),
|
||||
)
|
||||
.to_widget(tx.clone());
|
||||
.to_widget(tx.clone())
|
||||
.on_update(|state| {
|
||||
ContainerProps::default()
|
||||
.border_color(state.theme.border_color)
|
||||
.focus_border_color(state.theme.focus_border_color)
|
||||
.to_boxed_any()
|
||||
.into()
|
||||
});
|
||||
|
||||
let shortcuts = Shortcuts::default().to_widget(tx.clone()).on_update(|_| {
|
||||
ShortcutsProps::default()
|
||||
|
||||
@@ -124,8 +124,11 @@ impl Browser {
|
||||
.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())
|
||||
.border_color(state.theme.border_color)
|
||||
.focus_border_color(state.theme.focus_border_color)
|
||||
.to_boxed_any()
|
||||
.into()
|
||||
}))
|
||||
@@ -155,12 +158,16 @@ impl Browser {
|
||||
|
||||
FooterProps::default()
|
||||
.columns(browse_footer(&props))
|
||||
.border_color(state.theme.border_color)
|
||||
.focus_border_color(state.theme.focus_border_color)
|
||||
.to_boxed_any()
|
||||
.into()
|
||||
}))
|
||||
.to_widget(tx.clone())
|
||||
.on_update(|state| {
|
||||
ContainerProps::default()
|
||||
.border_color(state.theme.border_color)
|
||||
.focus_border_color(state.theme.focus_border_color)
|
||||
.hide_footer(BrowserProps::from(state).show_search)
|
||||
.to_boxed_any()
|
||||
.into()
|
||||
|
||||
@@ -2,6 +2,7 @@ mod cob;
|
||||
mod commands;
|
||||
mod git;
|
||||
mod ui;
|
||||
mod settings;
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::io;
|
||||
|
||||
Reference in New Issue
Block a user