mirror of
https://github.com/atuinsh/atuin.git
synced 2025-08-17 18:41:37 +02:00
Configurable bar colours
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -83,6 +83,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"clap_complete",
|
"clap_complete",
|
||||||
"colored",
|
"colored",
|
||||||
|
"colors-transform",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"directories",
|
"directories",
|
||||||
@ -152,6 +153,7 @@ name = "atuin-common"
|
|||||||
version = "14.0.0"
|
version = "14.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"colors-transform",
|
||||||
"serde",
|
"serde",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
@ -397,6 +399,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colors-transform"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9226dbc05df4fb986f48d730b001532580883c4c06c5d1c213f4b34c1c157178"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "config"
|
name = "config"
|
||||||
version = "0.13.2"
|
version = "0.13.2"
|
||||||
|
@ -80,6 +80,7 @@ colored = "2.0.0"
|
|||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
cassowary = "0.3"
|
cassowary = "0.3"
|
||||||
unicode-segmentation = "1.2"
|
unicode-segmentation = "1.2"
|
||||||
|
colors-transform = "0.2.11"
|
||||||
|
|
||||||
[dependencies.tracing-subscriber]
|
[dependencies.tracing-subscriber]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
|
@ -133,8 +133,15 @@ pub enum WordJumpMode {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct Bar {
|
pub struct Bar {
|
||||||
|
pub enabled: bool,
|
||||||
pub background_colour: String,
|
pub background_colour: String,
|
||||||
pub foreground_colour: String,
|
pub text_colour: String,
|
||||||
|
|
||||||
|
// parsed at load time from the above
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
pub background_colour_parsed: (f32, f32, f32),
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
pub text_colour_parsed: (f32, f32, f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
@ -355,6 +362,9 @@ impl Settings {
|
|||||||
.set_default("scroll_context_lines", 1)?
|
.set_default("scroll_context_lines", 1)?
|
||||||
.set_default("shell_up_key_binding", false)?
|
.set_default("shell_up_key_binding", false)?
|
||||||
.set_default("session_token", "")?
|
.set_default("session_token", "")?
|
||||||
|
.set_default("ui.bar.enabled", true)?
|
||||||
|
.set_default("ui.bar.background_colour", "#ffffff")?
|
||||||
|
.set_default("ui.bar.text_colour", "#000000")?
|
||||||
.add_source(
|
.add_source(
|
||||||
Environment::with_prefix("atuin")
|
Environment::with_prefix("atuin")
|
||||||
.prefix_separator("_")
|
.prefix_separator("_")
|
||||||
@ -393,6 +403,16 @@ impl Settings {
|
|||||||
let session_path = shellexpand::full(&session_path)?;
|
let session_path = shellexpand::full(&session_path)?;
|
||||||
settings.session_path = session_path.to_string();
|
settings.session_path = session_path.to_string();
|
||||||
|
|
||||||
|
// take the colours, parse them, whack the RGB into the settings
|
||||||
|
settings.ui.bar.background_colour_parsed = atuin_common::utils::parse_colour(
|
||||||
|
settings.ui.bar.background_colour.as_str(),
|
||||||
|
)
|
||||||
|
.expect("background_colour expects format rgb(r, g, b), hsl(h, s, l), or hex: #ffffff");
|
||||||
|
|
||||||
|
settings.ui.bar.text_colour_parsed =
|
||||||
|
atuin_common::utils::parse_colour(settings.ui.bar.text_colour.as_str())
|
||||||
|
.expect("text_colour expects format rgb(r, g, b), hsl(h, s, l), or hex: #ffffff");
|
||||||
|
|
||||||
// Finally, set the auth token
|
// Finally, set the auth token
|
||||||
if Path::new(session_path.to_string().as_str()).exists() {
|
if Path::new(session_path.to_string().as_str()).exists() {
|
||||||
let token = fs_err::read_to_string(session_path.to_string())?;
|
let token = fs_err::read_to_string(session_path.to_string())?;
|
||||||
|
@ -12,5 +12,6 @@ repository = "https://github.com/ellie/atuin"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
colors-transform = "0.2.11"
|
||||||
serde = { version = "1.0.145", features = ["derive"] }
|
serde = { version = "1.0.145", features = ["derive"] }
|
||||||
uuid = { version = "1.2", features = ["v4"] }
|
uuid = { version = "1.2", features = ["v4"] }
|
||||||
|
@ -4,6 +4,8 @@ use std::path::PathBuf;
|
|||||||
use chrono::{Months, NaiveDate};
|
use chrono::{Months, NaiveDate};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use colors_transform::{Color, Hsl, Rgb};
|
||||||
|
|
||||||
pub fn uuid_v4() -> String {
|
pub fn uuid_v4() -> String {
|
||||||
Uuid::new_v4().as_simple().to_string()
|
Uuid::new_v4().as_simple().to_string()
|
||||||
}
|
}
|
||||||
@ -24,6 +26,32 @@ pub fn home_dir() -> PathBuf {
|
|||||||
PathBuf::from(home)
|
PathBuf::from(home)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take a colour string as rgb, hsl, or hex and return the rgb. Allow fractional colours.
|
||||||
|
pub fn parse_colour(colour: &str) -> Option<(f32, f32, f32)> {
|
||||||
|
// Try loading RGB, then from hex, then HSL
|
||||||
|
|
||||||
|
let rgb = colour.parse::<colors_transform::Rgb>();
|
||||||
|
|
||||||
|
if let Ok(rgb) = rgb {
|
||||||
|
return Some((rgb.get_red(), rgb.get_green(), rgb.get_blue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let rgb = Rgb::from_hex_str(colour);
|
||||||
|
|
||||||
|
if let Ok(rgb) = rgb {
|
||||||
|
return Some((rgb.get_red(), rgb.get_green(), rgb.get_blue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let hsl = colour.parse::<colors_transform::Hsl>();
|
||||||
|
|
||||||
|
if let Ok(hsl) = hsl {
|
||||||
|
let rgb = hsl.to_rgb();
|
||||||
|
return Some((rgb.get_red(), rgb.get_green(), rgb.get_blue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn config_dir() -> PathBuf {
|
pub fn config_dir() -> PathBuf {
|
||||||
let config_dir =
|
let config_dir =
|
||||||
std::env::var("XDG_CONFIG_HOME").map_or_else(|_| home_dir().join(".config"), PathBuf::from);
|
std::env::var("XDG_CONFIG_HOME").map_or_else(|_| home_dir().join(".config"), PathBuf::from);
|
||||||
|
@ -99,6 +99,7 @@ impl State {
|
|||||||
|
|
||||||
let ctrl = input.modifiers.contains(KeyModifiers::CONTROL);
|
let ctrl = input.modifiers.contains(KeyModifiers::CONTROL);
|
||||||
let alt = input.modifiers.contains(KeyModifiers::ALT);
|
let alt = input.modifiers.contains(KeyModifiers::ALT);
|
||||||
|
|
||||||
// reset the state, will be set to true later if user really did change it
|
// reset the state, will be set to true later if user really did change it
|
||||||
self.switched_search_mode = false;
|
self.switched_search_mode = false;
|
||||||
match input.code {
|
match input.code {
|
||||||
@ -236,12 +237,12 @@ impl State {
|
|||||||
f: &mut Frame<'_, T>,
|
f: &mut Frame<'_, T>,
|
||||||
results: &[History],
|
results: &[History],
|
||||||
compact: bool,
|
compact: bool,
|
||||||
show_preview: bool,
|
settings: &Settings,
|
||||||
) {
|
) {
|
||||||
let border_size = if compact { 0 } else { 1 };
|
let border_size = if compact { 0 } else { 1 };
|
||||||
|
|
||||||
let preview_width = f.size().width - 2;
|
let preview_width = f.size().width - 2;
|
||||||
let preview_height = if show_preview {
|
let preview_height = if settings.show_preview {
|
||||||
let longest_command = results
|
let longest_command = results
|
||||||
.iter()
|
.iter()
|
||||||
.max_by(|h1, h2| h1.command.len().cmp(&h2.command.len()));
|
.max_by(|h1, h2| h1.command.len().cmp(&h2.command.len()));
|
||||||
@ -269,9 +270,9 @@ impl State {
|
|||||||
[
|
[
|
||||||
Constraint::Length(if show_help { 1 } else { 0 }),
|
Constraint::Length(if show_help { 1 } else { 0 }),
|
||||||
Constraint::Min(1),
|
Constraint::Min(1),
|
||||||
Constraint::Length(1),
|
|
||||||
Constraint::Length(1 + border_size),
|
Constraint::Length(1 + border_size),
|
||||||
Constraint::Length(preview_height),
|
Constraint::Length(preview_height),
|
||||||
|
Constraint::Length(if settings.ui.bar.enabled { 1 } else { 0 }),
|
||||||
]
|
]
|
||||||
.as_ref(),
|
.as_ref(),
|
||||||
)
|
)
|
||||||
@ -301,14 +302,14 @@ impl State {
|
|||||||
let results_list = Self::build_results_list(compact, results);
|
let results_list = Self::build_results_list(compact, results);
|
||||||
f.render_stateful_widget(results_list, chunks[1], &mut self.results_state);
|
f.render_stateful_widget(results_list, chunks[1], &mut self.results_state);
|
||||||
|
|
||||||
|
let input = self.build_input(compact, chunks[2].width.into());
|
||||||
|
f.render_widget(input, chunks[2]);
|
||||||
|
|
||||||
|
let preview = self.build_preview(results, compact, preview_width, chunks[2].width.into());
|
||||||
|
f.render_widget(preview, chunks[3]);
|
||||||
|
|
||||||
let selected_history = results[self.results_state.selected()].clone();
|
let selected_history = results[self.results_state.selected()].clone();
|
||||||
self.render_bar(f, &selected_history, chunks[2], compact);
|
self.render_bar(f, &selected_history, chunks[4], settings);
|
||||||
|
|
||||||
let input = self.build_input(compact, chunks[3].width.into());
|
|
||||||
f.render_widget(input, chunks[3]);
|
|
||||||
|
|
||||||
let preview = self.build_preview(results, compact, preview_width, chunks[3].width.into());
|
|
||||||
f.render_widget(preview, chunks[4]);
|
|
||||||
|
|
||||||
let extra_width = UnicodeWidthStr::width(self.search.input.substring());
|
let extra_width = UnicodeWidthStr::width(self.search.input.substring());
|
||||||
|
|
||||||
@ -376,25 +377,43 @@ impl State {
|
|||||||
f: &mut Frame<'_, T>,
|
f: &mut Frame<'_, T>,
|
||||||
history: &History,
|
history: &History,
|
||||||
chunk: Rect,
|
chunk: Rect,
|
||||||
compact: bool,
|
settings: &Settings,
|
||||||
) {
|
) {
|
||||||
let bar = Layout::default()
|
let bar = Layout::default()
|
||||||
.direction(Direction::Horizontal)
|
.direction(Direction::Horizontal)
|
||||||
.constraints([Constraint::Ratio(9, 10), Constraint::Ratio(1, 10)].as_ref())
|
.constraints([Constraint::Ratio(9, 10), Constraint::Ratio(1, 10)].as_ref())
|
||||||
.split(chunk);
|
.split(chunk);
|
||||||
|
|
||||||
let mut directory = Paragraph::new(Text::from(Span::raw(format!("{}", history.cwd,))))
|
let directory = Paragraph::new(Text::from(Span::raw(format!("{}", history.cwd,)))).style(
|
||||||
.style(Style::default().bg(Color::White).fg(Color::Black));
|
Style::default()
|
||||||
|
.bg(Color::Rgb(
|
||||||
|
settings.ui.bar.background_colour_parsed.0 as u8,
|
||||||
|
settings.ui.bar.background_colour_parsed.1 as u8,
|
||||||
|
settings.ui.bar.background_colour_parsed.2 as u8,
|
||||||
|
))
|
||||||
|
.fg(Color::Rgb(
|
||||||
|
settings.ui.bar.text_colour_parsed.0 as u8,
|
||||||
|
settings.ui.bar.text_colour_parsed.1 as u8,
|
||||||
|
settings.ui.bar.text_colour_parsed.2 as u8,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
if !compact {
|
let count = Paragraph::new(Text::from(Span::raw(format!("x{}", 0,)))).style(
|
||||||
directory = directory.block(
|
Style::default()
|
||||||
Block::default()
|
.bg(Color::Rgb(
|
||||||
.borders(Borders::LEFT)
|
settings.ui.bar.background_colour_parsed.0 as u8,
|
||||||
.border_type(BorderType::Rounded),
|
settings.ui.bar.background_colour_parsed.1 as u8,
|
||||||
);
|
settings.ui.bar.background_colour_parsed.2 as u8,
|
||||||
}
|
))
|
||||||
|
.fg(Color::Rgb(
|
||||||
|
settings.ui.bar.text_colour_parsed.0 as u8,
|
||||||
|
settings.ui.bar.text_colour_parsed.1 as u8,
|
||||||
|
settings.ui.bar.text_colour_parsed.2 as u8,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
f.render_widget(directory, bar[0]);
|
f.render_widget(directory, bar[0]);
|
||||||
|
f.render_widget(count, bar[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_input(&mut self, compact: bool, chunk_width: usize) -> Paragraph {
|
fn build_input(&mut self, compact: bool, chunk_width: usize) -> Paragraph {
|
||||||
@ -574,7 +593,7 @@ pub async fn history(
|
|||||||
atuin_client::settings::Style::Compact => true,
|
atuin_client::settings::Style::Compact => true,
|
||||||
atuin_client::settings::Style::Full => false,
|
atuin_client::settings::Style::Full => false,
|
||||||
};
|
};
|
||||||
terminal.draw(|f| app.draw(f, &results, compact, settings.show_preview))?;
|
terminal.draw(|f| app.draw(f, &results, compact, settings))?;
|
||||||
|
|
||||||
let initial_input = app.search.input.as_str().to_owned();
|
let initial_input = app.search.input.as_str().to_owned();
|
||||||
let initial_filter_mode = app.search.filter_mode;
|
let initial_filter_mode = app.search.filter_mode;
|
||||||
|
Reference in New Issue
Block a user