use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct LayoutOverlay {
pub left_pct: u16,
pub middle_pct: u16,
pub right_pct: u16,
}
impl Default for LayoutOverlay {
fn default() -> Self {
Self {
left_pct: 10,
middle_pct: 30,
right_pct: 60,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum EnhancePolicy {
#[serde(alias = "always")]
Auto,
#[serde(alias = "never")]
Manual,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum ColumnStatsDisplay {
None,
#[default]
Abbrev,
Full,
}
impl ColumnStatsDisplay {
#[must_use]
pub const fn shows_tables(self) -> bool {
!matches!(self, Self::None)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Osc11BackgroundFormat {
#[default]
Rgba,
Hex8,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct EnhancePolicyEntry {
pub path: String,
pub policy: EnhancePolicy,
}
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
#[serde(default)]
pub struct UblxOverlay {
pub exclude: Option<Vec<String>>,
#[serde(rename = "show_hidden_files")]
pub show_hidden_files: Option<bool>,
pub hash: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub theme: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub layout: Option<LayoutOverlay>,
#[serde(skip_serializing_if = "Option::is_none")]
pub editor_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enable_enhance_all: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ask_enhance_on_new_root: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enhance_policy: Option<Vec<EnhancePolicyEntry>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bg_opacity: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub opacity_format: Option<Osc11BackgroundFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub run_snapshot_on_startup: Option<bool>,
#[serde(alias = "column_stats", skip_serializing_if = "Option::is_none")]
pub typed_column_tables: Option<ColumnStatsDisplay>,
}
#[inline]
pub fn strip_global_only_keys_from_local_overlay(overlay: &mut UblxOverlay) {
overlay.opacity_format = None;
overlay.ask_enhance_on_new_root = None;
}
impl UblxOverlay {
pub fn merge_from(&mut self, other: &UblxOverlay) {
if other.exclude.is_some() {
self.exclude.clone_from(&other.exclude);
}
if other.show_hidden_files.is_some() {
self.show_hidden_files = other.show_hidden_files;
}
if other.hash.is_some() {
self.hash = other.hash;
}
if other.theme.is_some() {
self.theme.clone_from(&other.theme);
}
if other.layout.is_some() {
self.layout.clone_from(&other.layout);
}
if other.editor_path.is_some() {
self.editor_path.clone_from(&other.editor_path);
}
if other.enable_enhance_all.is_some() {
self.enable_enhance_all = other.enable_enhance_all;
}
if other.ask_enhance_on_new_root.is_some() {
self.ask_enhance_on_new_root = other.ask_enhance_on_new_root;
}
if other.enhance_policy.is_some() {
self.enhance_policy.clone_from(&other.enhance_policy);
}
if other.bg_opacity.is_some() {
self.bg_opacity = other.bg_opacity;
}
if other.opacity_format.is_some() {
self.opacity_format = other.opacity_format;
}
if other.run_snapshot_on_startup.is_some() {
self.run_snapshot_on_startup = other.run_snapshot_on_startup;
}
if other.typed_column_tables.is_some() {
self.typed_column_tables = other.typed_column_tables;
}
}
pub fn backfill_missing_from_template(&mut self, template: &Self, local_scope: bool) -> bool {
let mut changed = false;
changed |= backfill_option(&mut self.exclude, template.exclude.clone());
changed |= backfill_option(&mut self.show_hidden_files, template.show_hidden_files);
changed |= backfill_option(&mut self.hash, template.hash);
changed |= backfill_option(&mut self.theme, template.theme.clone());
changed |= backfill_option(&mut self.layout, template.layout.clone());
changed |= backfill_option(&mut self.editor_path, template.editor_path.clone());
changed |= backfill_option(&mut self.enable_enhance_all, template.enable_enhance_all);
changed |= backfill_option(&mut self.enhance_policy, template.enhance_policy.clone());
changed |= backfill_option(&mut self.bg_opacity, template.bg_opacity);
changed |= backfill_option(
&mut self.run_snapshot_on_startup,
template.run_snapshot_on_startup,
);
changed |= backfill_option(&mut self.typed_column_tables, template.typed_column_tables);
if !local_scope {
changed |= backfill_option(
&mut self.ask_enhance_on_new_root,
template.ask_enhance_on_new_root,
);
changed |= backfill_option(&mut self.opacity_format, template.opacity_format);
}
changed
}
#[must_use]
pub fn merge(global: Option<UblxOverlay>, local: Option<UblxOverlay>) -> UblxOverlay {
let mut out = UblxOverlay::default();
if let Some(g) = global {
out.merge_from(&g);
}
if let Some(mut l) = local {
strip_global_only_keys_from_local_overlay(&mut l);
out.merge_from(&l);
}
out
}
}
fn backfill_option<T: Clone>(dst: &mut Option<T>, src: Option<T>) -> bool {
if dst.is_none() && src.is_some() {
*dst = src;
true
} else {
false
}
}