some work on the configuration file

This commit is contained in:
Alexandre Pasmantier 2024-11-06 00:23:59 +01:00
parent 6d48c87526
commit 4302b6189a
9 changed files with 80 additions and 51 deletions

View File

@ -1,3 +1,18 @@
# Television configuration file
# ----------------------------------------------------------------------------
#
# Ui settings
# ----------------------------------------------------------------------------
[ui]
# Whether to use nerd font icons in the UI
use_nerd_font_icons = false
# How much space to allocate for the UI (in percentage of the screen)
ui_scale = 80
# Keybindings
# ----------------------------------------------------------------------------
#
# Channel mode keybindings
[keybindings.Channel] [keybindings.Channel]
esc = "Quit" esc = "Quit"
down = "SelectNextEntry" down = "SelectNextEntry"
@ -11,6 +26,7 @@ ctrl-y = "CopyEntryToClipboard"
ctrl-r = "ToggleRemoteControl" ctrl-r = "ToggleRemoteControl"
ctrl-s = "ToggleSendToChannel" ctrl-s = "ToggleSendToChannel"
# Remote control mode keybindings
[keybindings.RemoteControl] [keybindings.RemoteControl]
esc = "Quit" esc = "Quit"
down = "SelectNextEntry" down = "SelectNextEntry"
@ -20,6 +36,7 @@ ctrl-p = "SelectPrevEntry"
enter = "SelectEntry" enter = "SelectEntry"
ctrl-r = "ToggleRemoteControl" ctrl-r = "ToggleRemoteControl"
# Send to channel mode keybindings
[keybindings.SendToChannel] [keybindings.SendToChannel]
esc = "Quit" esc = "Quit"
down = "SelectNextEntry" down = "SelectNextEntry"

View File

@ -49,27 +49,12 @@ jobs:
run: cargo clippy --all-targets --all-features --workspace -- -D warnings run: cargo clippy --all-targets --all-features --workspace -- -D warnings
docs: docs:
name: Docs name: Documentation
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
RUSTDOCFLAGS: -Dwarnings
steps: steps:
- name: Checkout repository - uses: actions/checkout@v4
uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly
- name: Install Rust toolchain - uses: dtolnay/install@cargo-docs-rs
uses: dtolnay/rust-toolchain@nightly - run: cargo docs-rs
- name: Configure cache
uses: Swatinem/rust-cache@v2
- name: Setup pages
id: pages
uses: actions/configure-pages@v4
- name: Clean docs folder
run: cargo clean --doc
- name: Build docs
run: cargo doc --no-deps
- name: Add redirect
run: echo '<meta http-equiv="refresh" content="0;url=tv/index.html">' > target/doc/index.html
- name: Remove lock file
run: rm target/doc/.lock
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: target/doc

View File

@ -6,8 +6,8 @@
# tasks # tasks
- [x] preview navigation - [x] preview navigation
- [x] add a way to open the selected file in the default editor (or maybe that - [ ] add a way to open the selected file in the default editor (or maybe that
should be achieved using pipes?) --> use xargs for that should be achieved using pipes?) --> xargs
- [x] maybe filter out image types etc. for now - [x] maybe filter out image types etc. for now
- [x] return selected entry on exit - [x] return selected entry on exit
- [x] piping output to another command - [x] piping output to another command

View File

@ -7,7 +7,7 @@ use directories::ProjectDirs;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use ratatui::style::{Color, Modifier, Style}; use ratatui::style::{Color, Modifier, Style};
use serde::{de::Deserializer, Deserialize}; use serde::{de::Deserializer, Deserialize};
use tracing::{error, info}; use tracing::{debug, error, info, warn};
use crate::{ use crate::{
action::Action, action::Action,
@ -26,6 +26,23 @@ pub struct AppConfig {
pub config_dir: PathBuf, pub config_dir: PathBuf,
} }
const DEFAULT_UI_SCALE: u16 = 90;
#[derive(Clone, Debug, Deserialize)]
pub struct UiConfig {
pub use_nerd_font_icons: bool,
pub ui_scale: u16,
}
impl Default for UiConfig {
fn default() -> Self {
Self {
use_nerd_font_icons: false,
ui_scale: DEFAULT_UI_SCALE,
}
}
}
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Clone, Debug, Default, Deserialize)] #[derive(Clone, Debug, Default, Deserialize)]
pub struct Config { pub struct Config {
@ -36,6 +53,7 @@ pub struct Config {
pub keybindings: KeyBindings, pub keybindings: KeyBindings,
#[serde(default)] #[serde(default)]
pub styles: Styles, pub styles: Styles,
pub ui: UiConfig,
} }
lazy_static! { lazy_static! {
@ -51,34 +69,32 @@ lazy_static! {
.map(PathBuf::from); .map(PathBuf::from);
} }
const CONFIG_FILE_NAME: &str = "config.toml";
impl Config { impl Config {
pub fn new() -> Result<Self, config::ConfigError> { pub fn new() -> Result<Self, config::ConfigError> {
let default_config: Config = toml::from_str(CONFIG).unwrap(); let default_config: Config =
toml::from_str(CONFIG).expect("default config");
let data_dir = get_data_dir(); let data_dir = get_data_dir();
let config_dir = get_config_dir(); let config_dir = get_config_dir();
let mut builder = config::Config::builder() let mut builder = config::Config::builder()
.set_default("data_dir", data_dir.to_str().unwrap())? .set_default("data_dir", data_dir.to_str().unwrap())?
.set_default("config_dir", config_dir.to_str().unwrap())?; .set_default("config_dir", config_dir.to_str().unwrap())?;
let config_files = [ // Load the default_config values as base defaults
("config.json5", config::FileFormat::Json5), builder = builder.add_source(config::File::from_str(
("config.json", config::FileFormat::Json), CONFIG,
("config.yaml", config::FileFormat::Yaml), config::FileFormat::Toml,
("config.toml", config::FileFormat::Toml), ));
("config.ini", config::FileFormat::Ini),
]; let source = config::File::from(config_dir.join(CONFIG_FILE_NAME))
let mut found_config = false; .format(config::FileFormat::Toml)
for (file, format) in &config_files {
let source = config::File::from(config_dir.join(file))
.format(*format)
.required(false); .required(false);
builder = builder.add_source(source); builder = builder.add_source(source);
if config_dir.join(file).exists() {
found_config = true; if !config_dir.join(CONFIG_FILE_NAME).is_file() {
} warn!("No config file found at {:?}", config_dir);
}
if !found_config {
error!("No configuration file found. Application may not behave as expected");
} }
let mut cfg: Self = builder.build()?.try_deserialize()?; let mut cfg: Self = builder.build()?.try_deserialize()?;

View File

@ -370,7 +370,7 @@ impl Television {
/// * `Result<()>` - An Ok result or an error. /// * `Result<()>` - An Ok result or an error.
pub fn draw(&mut self, f: &mut Frame, area: Rect) -> Result<()> { pub fn draw(&mut self, f: &mut Frame, area: Rect) -> Result<()> {
let layout = Layout::build( let layout = Layout::build(
&Dimensions::default(), &Dimensions::from(self.config.ui.ui_scale),
area, area,
!matches!(self.mode, Mode::Channel), !matches!(self.mode, Mode::Channel),
); );

View File

@ -12,6 +12,12 @@ impl Dimensions {
} }
} }
impl From<u16> for Dimensions {
fn from(x: u16) -> Self {
Self::new(x, x)
}
}
impl Default for Dimensions { impl Default for Dimensions {
fn default() -> Self { fn default() -> Self {
Self::new(UI_WIDTH_PERCENT, UI_HEIGHT_PERCENT) Self::new(UI_WIDTH_PERCENT, UI_HEIGHT_PERCENT)

View File

@ -31,12 +31,12 @@ impl Television {
preview: &Arc<Preview>, preview: &Arc<Preview>,
) -> Result<()> { ) -> Result<()> {
let mut preview_title_spans = Vec::new(); let mut preview_title_spans = Vec::new();
if let Some(icon) = &selected_entry.icon { if selected_entry.icon.is_some() && self.config.ui.use_nerd_font_icons
{
let icon = selected_entry.icon.as_ref().unwrap();
preview_title_spans.push(Span::styled( preview_title_spans.push(Span::styled(
{ {
// FIXME: this should be done using padding on the parent block let mut icon_str = String::from(icon.icon);
let mut icon_str = String::from(" ");
icon_str.push(icon.icon);
icon_str.push(' '); icon_str.push(' ');
icon_str icon_str
}, },
@ -53,6 +53,7 @@ impl Television {
let preview_title = Paragraph::new(Line::from(preview_title_spans)) let preview_title = Paragraph::new(Line::from(preview_title_spans))
.block( .block(
Block::default() Block::default()
.padding(Padding::horizontal(1))
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.border_style(Style::default().fg(BORDER_COLOR)), .border_style(Style::default().fg(BORDER_COLOR)),

View File

@ -64,6 +64,7 @@ impl Television {
ResultsListColors::default() ResultsListColors::default()
.result_name_fg(mode_color(self.mode)), .result_name_fg(mode_color(self.mode)),
), ),
self.config.ui.use_nerd_font_icons,
); );
f.render_stateful_widget( f.render_stateful_widget(

View File

@ -65,6 +65,7 @@ pub fn build_results_list<'a, 'b>(
entries: &'a [Entry], entries: &'a [Entry],
list_direction: ListDirection, list_direction: ListDirection,
results_list_colors: Option<ResultsListColors>, results_list_colors: Option<ResultsListColors>,
use_icons: bool,
) -> List<'a> ) -> List<'a>
where where
'b: 'a, 'b: 'a,
@ -73,7 +74,8 @@ where
List::new(entries.iter().map(|entry| { List::new(entries.iter().map(|entry| {
let mut spans = Vec::new(); let mut spans = Vec::new();
// optional icon // optional icon
if let Some(icon) = &entry.icon { if entry.icon.is_some() && use_icons {
let icon = entry.icon.as_ref().unwrap();
spans.push(Span::styled( spans.push(Span::styled(
icon.to_string(), icon.to_string(),
Style::default().fg(Color::from_str(icon.color).unwrap()), Style::default().fg(Color::from_str(icon.color).unwrap()),
@ -200,6 +202,7 @@ impl Television {
&entries, &entries,
ListDirection::BottomToTop, ListDirection::BottomToTop,
None, None,
self.config.ui.use_nerd_font_icons,
); );
f.render_stateful_widget( f.render_stateful_widget(