Improve config defaults

- Rename `custom` field for node metadata to `meta`.
- Move `icon` to `meta.icon`.
- Rename `normal_ui` to `default_ui`.
- Rename `filetypes` to `node_types`.
- Split `modes` into `modes.builtin` and `modes.custom`.
- Add the missing `create file` mode.
- Rename `focused_ui` to `focus_ui`.
- Make `general.table.header` non-nullable.
- Add support for incremental configuration updates.

Ref: https://github.com/sayanarijit/xplr/issues/45
pull/48/head
Arijit Basu 3 years ago committed by Arijit Basu
parent 6aa3df301e
commit 3598be0f19

@ -1,6 +1,5 @@
use crate::config::Config;
use crate::config::Mode;
use crate::default_config::DEFAULT_CONFIG;
use crate::input::Key;
use anyhow::{bail, Result};
use chrono::{DateTime, Utc};
@ -185,6 +184,7 @@ pub enum InternalMsg {
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum NodeFilter {
RelativePathIs,
RelativePathIsNot,
@ -376,6 +376,7 @@ impl NodeFilter {
}
#[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NodeFilterApplicable {
filter: NodeFilter,
input: String,
@ -398,6 +399,7 @@ impl NodeFilterApplicable {
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NodeFilterFromInput {
filter: NodeFilter,
#[serde(default)]
@ -621,6 +623,7 @@ pub enum MsgIn {
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Command {
pub command: String,
@ -698,32 +701,24 @@ pub enum HelpMenuLine {
/// Major version should be the same.
/// Config minor version should be lower.
/// Patch/fix version can be anything.
pub fn is_compatible(configv: &str, appv: &str) -> bool {
let mut configv = configv
.strip_prefix('v')
.unwrap_or_default()
.split('.')
.map(|c| c.parse::<u64>().unwrap());
let mut appv = appv
.strip_prefix('v')
.unwrap_or_default()
.split('.')
.map(|c| c.parse::<u64>().unwrap());
let mut major_configv = configv.next().unwrap_or_default();
let mut minor_configv = configv.next().unwrap_or_default();
let mut major_appv = appv.next().unwrap_or_default();
let mut minor_appv = appv.next().unwrap_or_default();
pub fn is_compatible(configv: &str, appv: &str) -> Result<bool> {
let mut configv = configv.strip_prefix('v').unwrap_or_default().split('.');
let mut appv = appv.strip_prefix('v').unwrap_or_default().split('.');
let mut major_configv = configv.next().unwrap_or_default().parse::<u16>()?;
let mut minor_configv = configv.next().unwrap_or_default().parse::<u16>()?;
let mut major_appv = appv.next().unwrap_or_default().parse::<u16>()?;
let mut minor_appv = appv.next().unwrap_or_default().parse::<u16>()?;
if major_configv == 0 && major_appv == 0 {
major_configv = minor_configv;
minor_configv = configv.next().unwrap_or_default();
minor_configv = configv.next().unwrap_or_default().parse::<u16>()?;
major_appv = minor_appv;
minor_appv = appv.next().unwrap_or_default();
minor_appv = appv.next().unwrap_or_default().parse::<u16>()?;
};
major_configv == major_appv && minor_configv <= minor_appv
Ok(major_configv == major_appv && minor_configv <= minor_appv)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -750,15 +745,19 @@ impl App {
.join("xplr");
let config_file = config_dir.join("config.yml");
let default_config = Config::default();
let default_config_version = default_config.version.clone();
let config: Config = if config_file.exists() {
serde_yaml::from_reader(io::BufReader::new(&fs::File::open(&config_file)?))?
let c: Config =
serde_yaml::from_reader(io::BufReader::new(&fs::File::open(&config_file)?))?;
c.extended()
} else {
Config::default()
default_config
};
if config.version != DEFAULT_CONFIG.version
&& !is_compatible(&config.version, &DEFAULT_CONFIG.version)
if config.version != default_config_version
&& !is_compatible(&config.version, &default_config_version)?
{
bail!(
"incompatible configuration version in {}
@ -767,12 +766,12 @@ impl App {
Visit {}",
config_file.to_string_lossy().to_string(),
config.version,
DEFAULT_CONFIG.version,
default_config_version,
UPGRADE_GUIDE_LINK,
)
};
let mode = match config.modes.get(&"default".to_string()) {
let mode = match config.modes.builtin.get(&"default".to_string()) {
Some(m) => m.clone(),
None => {
bail!("'default' mode is missing")
@ -789,7 +788,7 @@ impl App {
.to_string();
let mut explorer_config = ExplorerConfig::default();
if !config.general.show_hidden {
if !config.general.show_hidden.unwrap_or_default() {
explorer_config.filters.insert(NodeFilterApplicable::new(
NodeFilter::RelativePathDoesNotStartWith,
".".into(),
@ -798,7 +797,7 @@ impl App {
}
Ok(Self {
version: DEFAULT_CONFIG.version.clone(),
version: Config::default().version,
config,
pwd: pwd.to_string_lossy().to_string(),
directory_buffers: Default::default(),
@ -1244,7 +1243,7 @@ impl App {
fn reset_node_filters(mut self) -> Result<Self> {
self.explorer_config.filters.clear();
if !self.config.general.show_hidden {
if !self.config.general.show_hidden.unwrap_or_default() {
self.add_node_filter(NodeFilterApplicable::new(
NodeFilter::RelativePathDoesNotStartWith,
".".into(),
@ -1412,29 +1411,47 @@ impl App {
}
pub fn global_help_menu_str(&self) -> String {
self.config()
.modes
.iter()
.map(|(name, mode)| {
let help = mode
.help_menu()
.iter()
.map(|l| match l {
HelpMenuLine::Paragraph(p) => format!("\t{}\n", p),
HelpMenuLine::KeyMap(k, h) => {
format!(" {:15} | {}\n", k, h)
}
})
.collect::<Vec<String>>()
.join("");
format!(
"### {}\n\n key | action\n --------------- | ------\n{}\n",
name, help
)
})
.collect::<Vec<String>>()
.join("\n")
let builtin = self.config().modes.builtin.clone();
let custom = self.config().modes.custom.clone();
[
(builtin.default.name.clone(), builtin.default),
(builtin.number.name.clone(), builtin.number),
(builtin.go_to.name.clone(), builtin.go_to),
(builtin.search.name.clone(), builtin.search),
(builtin.selection_ops.name.clone(), builtin.selection_ops),
(builtin.action.name.clone(), builtin.action),
(builtin.create.name.clone(), builtin.create),
(builtin.create_file.name.clone(), builtin.create_file),
(
builtin.create_directory.name.clone(),
builtin.create_directory,
),
(builtin.rename.name.clone(), builtin.rename),
(builtin.delete.name.clone(), builtin.delete),
]
.iter()
.chain(custom.into_iter().collect::<Vec<(String, Mode)>>().iter())
.map(|(name, mode)| {
let help = mode
.help_menu()
.iter()
.map(|l| match l {
HelpMenuLine::Paragraph(p) => format!("\t{}\n", p),
HelpMenuLine::KeyMap(k, h) => {
format!(" {:15} | {}\n", k, h)
}
})
.collect::<Vec<String>>()
.join("");
format!(
"### {}\n\n key | action\n --------------- | ------\n{}\n",
name, help
)
})
.collect::<Vec<String>>()
.join("\n")
}
/// Get a reference to the app's version.

@ -1,13 +1,56 @@
use crate::app::ExternalMsg;
use crate::app::HelpMenuLine;
use crate::default_config::DEFAULT_CONFIG;
use crate::default_config;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::collections::HashMap;
use tui::layout::Constraint as TuiConstraint;
use tui::style::Style;
use tui::style::Style as TuiStyle;
use tui::style::{Color, Modifier};
#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Style {
fg: Option<Color>,
bg: Option<Color>,
add_modifier: Option<Modifier>,
sub_modifier: Option<Modifier>,
}
impl Style {
pub fn extend(mut self, other: Self) -> Self {
self.fg = other.fg.or(self.fg);
self.bg = other.bg.or(self.bg);
self.add_modifier = other.add_modifier.or(self.add_modifier);
self.sub_modifier = other.sub_modifier.or(self.sub_modifier);
self
}
}
impl From<TuiStyle> for Style {
fn from(s: TuiStyle) -> Self {
Self {
fg: s.fg,
bg: s.bg,
add_modifier: Some(s.add_modifier),
sub_modifier: Some(s.sub_modifier),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
impl Into<TuiStyle> for Style {
fn into(self) -> TuiStyle {
TuiStyle {
fg: self.fg,
bg: self.bg,
add_modifier: self.add_modifier.unwrap_or_else(Modifier::empty),
sub_modifier: self.sub_modifier.unwrap_or_else(Modifier::empty),
}
}
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Action {
#[serde(default)]
pub help: Option<String>,
@ -16,68 +59,130 @@ pub struct Action {
pub messages: Vec<ExternalMsg>,
}
impl Action {
pub fn extend(mut self, other: Self) -> Self {
self.help = other.help.or(self.help);
self.messages = other.messages;
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct FileTypeConfig {
#[serde(default)]
pub icon: String,
#[serde(deny_unknown_fields)]
pub struct NodeTypeConfig {
#[serde(default)]
pub style: Style,
#[serde(default)]
pub custom: HashMap<String, String>,
pub meta: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileTypesConfig {
impl NodeTypeConfig {
pub fn extend(mut self, mut other: Self) -> Self {
self.style = other.style.extend(self.style);
other.meta.extend(self.meta);
self.meta = other.meta;
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NodeTypesConfig {
#[serde(default)]
pub directory: FileTypeConfig,
pub directory: NodeTypeConfig,
#[serde(default)]
pub file: FileTypeConfig,
pub file: NodeTypeConfig,
#[serde(default)]
pub symlink: FileTypeConfig,
pub symlink: NodeTypeConfig,
#[serde(default)]
pub mime_essence: HashMap<String, FileTypeConfig>,
pub mime_essence: HashMap<String, NodeTypeConfig>,
#[serde(default)]
pub extension: HashMap<String, FileTypeConfig>,
pub extension: HashMap<String, NodeTypeConfig>,
#[serde(default)]
pub special: HashMap<String, FileTypeConfig>,
pub special: HashMap<String, NodeTypeConfig>,
}
impl Default for FileTypesConfig {
fn default() -> Self {
DEFAULT_CONFIG.filetypes.clone()
impl NodeTypesConfig {
fn extend(mut self, mut other: Self) -> Self {
self.directory = other.directory.extend(self.directory);
self.file = other.file.extend(self.file);
self.symlink = other.symlink.extend(self.symlink);
other.mime_essence.extend(self.mime_essence);
self.mime_essence = other.mime_essence;
other.extension.extend(self.extension);
self.extension = other.extension;
other.special.extend(self.special);
self.special = other.special;
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct UiConfig {
#[serde(default)]
pub prefix: String,
pub prefix: Option<String>,
#[serde(default)]
pub suffix: String,
pub suffix: Option<String>,
#[serde(default)]
pub style: Style,
}
impl UiConfig {
fn extend(mut self, other: Self) -> Self {
self.prefix = other.prefix.or(self.prefix);
self.suffix = other.suffix.or(self.suffix);
self.style = other.style.extend(self.style);
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct UiElement {
#[serde(default)]
pub format: String,
pub format: Option<String>,
#[serde(default)]
pub style: Style,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TableRowConfig {
#[serde(default)]
pub cols: Vec<UiElement>,
pub cols: Option<Vec<UiElement>>,
#[serde(default)]
pub style: Style,
#[serde(default)]
pub height: u16,
pub height: Option<u16>,
}
impl TableRowConfig {
fn extend(mut self, other: Self) -> Self {
self.cols = other.cols.or(self.cols);
self.style = other.style.extend(self.style);
self.height = other.height.or(self.height);
self
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Constraint {
Percentage(u16),
Ratio(u32, u32),
@ -105,46 +210,71 @@ impl Into<TuiConstraint> for Constraint {
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TableConfig {
#[serde(default)]
pub header: Option<TableRowConfig>,
pub header: TableRowConfig,
#[serde(default)]
pub row: TableRowConfig,
#[serde(default)]
pub style: Style,
#[serde(default)]
pub tree: Option<(UiElement, UiElement, UiElement)>,
#[serde(default)]
pub col_spacing: u16,
pub col_spacing: Option<u16>,
#[serde(default)]
pub col_widths: Vec<Constraint>,
pub col_widths: Option<Vec<Constraint>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
impl TableConfig {
pub fn extend(mut self, other: Self) -> Self {
self.header = other.header.extend(self.header);
self.row = other.row.extend(self.row);
self.style = other.style.extend(self.style);
self.tree = other.tree.or(self.tree);
self.col_spacing = other.col_spacing.or(self.col_spacing);
self.col_widths = other.col_widths.or(self.col_widths);
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct GeneralConfig {
#[serde(default)]
pub show_hidden: bool,
pub show_hidden: Option<bool>,
#[serde(default)]
pub table: TableConfig,
#[serde(default)]
pub normal_ui: UiConfig,
pub default_ui: UiConfig,
#[serde(default)]
pub focused_ui: UiConfig,
pub focus_ui: UiConfig,
#[serde(default)]
pub selection_ui: UiConfig,
}
impl Default for GeneralConfig {
fn default() -> Self {
DEFAULT_CONFIG.general.clone()
impl GeneralConfig {
pub fn extend(mut self, other: Self) -> Self {
self.show_hidden = other.show_hidden.or(self.show_hidden);
self.table = other.table.extend(self.table);
self.default_ui = other.default_ui.extend(self.default_ui);
self.focus_ui = other.focus_ui.extend(self.focus_ui);
self.selection_ui = other.selection_ui.extend(self.selection_ui);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct KeyBindings {
#[serde(default)]
pub on_key: BTreeMap<String, Action>,
@ -162,8 +292,22 @@ pub struct KeyBindings {
pub default: Option<Action>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
impl KeyBindings {
pub fn extend(mut self, mut other: Self) -> Self {
other.on_key.extend(self.on_key);
self.on_key = other.on_key;
self.on_alphabet = other.on_alphabet.or(self.on_alphabet);
self.on_number = other.on_number.or(self.on_number);
self.on_special_character = other.on_special_character.or(self.on_special_character);
self.default = other.default.or(self.default);
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Mode {
#[serde(default)]
pub name: String,
#[serde(default)]
@ -172,10 +316,18 @@ pub struct Mode {
#[serde(default)]
pub extra_help: Option<String>,
#[serde(default)]
pub key_bindings: KeyBindings,
}
impl Mode {
pub fn extend(mut self, other: Self) -> Self {
self.help = other.help.or(self.help);
self.extra_help = other.extra_help.or(self.extra_help);
self.key_bindings = other.key_bindings.extend(self.key_bindings);
self
}
pub fn help_menu(&self) -> Vec<HelpMenuLine> {
let extra_help_lines = self.extra_help.clone().map(|e| {
e.lines()
@ -230,7 +382,104 @@ impl Mode {
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct BuiltinModesConfig {
#[serde(default)]
pub default: Mode,
#[serde(default)]
pub selection_ops: Mode,
#[serde(default)]
pub create: Mode,
#[serde(default)]
pub create_directory: Mode,
#[serde(default)]
pub create_file: Mode,
#[serde(default)]
pub number: Mode,
#[serde(default)]
pub go_to: Mode,
#[serde(default)]
pub rename: Mode,
#[serde(default)]
pub delete: Mode,
#[serde(default)]
pub action: Mode,
#[serde(default)]
pub search: Mode,
}
impl BuiltinModesConfig {
pub fn extend(mut self, other: Self) -> Self {
self.default = other.default.extend(self.default);
self.selection_ops = other.selection_ops.extend(self.selection_ops);
self.go_to = other.go_to.extend(self.go_to);
self.create = other.create.extend(self.create);
self.create_file = other.create_file.extend(self.create_file);
self.create_directory = other.create_directory.extend(self.create_directory);
self.rename = other.rename.extend(self.rename);
self.delete = other.delete.extend(self.delete);
self.number = other.number.extend(self.number);
self.action = other.action.extend(self.action);
self.search = other.search.extend(self.search);
self
}
pub fn get(&self, name: &str) -> Option<&Mode> {
match name {
"default" => Some(&self.default),
"selection ops" => Some(&self.selection_ops),
"selection_ops" => Some(&self.selection_ops),
"create" => Some(&self.create),
"create file" => Some(&self.create_file),
"create_file" => Some(&self.create_file),
"create directory" => Some(&self.create_directory),
"create_directory" => Some(&self.create_directory),
"number" => Some(&self.number),
"go to" => Some(&self.go_to),
"go_to" => Some(&self.go_to),
"rename" => Some(&self.rename),
"delete" => Some(&self.delete),
"action" => Some(&self.action),
"search" => Some(&self.search),
_ => None,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ModesConfig {
#[serde(default)]
pub builtin: BuiltinModesConfig,
#[serde(default)]
pub custom: HashMap<String, Mode>,
}
impl ModesConfig {
pub fn get(&self, name: &str) -> Option<&Mode> {
self.builtin.get(name).or_else(|| self.custom.get(name))
}
pub fn extend(mut self, other: Self) -> Self {
self.builtin = other.builtin.extend(self.builtin);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub version: String,
@ -238,18 +487,29 @@ pub struct Config {
pub general: GeneralConfig,
#[serde(default)]
pub filetypes: FileTypesConfig,
pub node_types: NodeTypesConfig,
pub modes: HashMap<String, Mode>,
#[serde(default)]
pub modes: ModesConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
version: DEFAULT_CONFIG.version.clone(),
general: Default::default(),
filetypes: Default::default(),
modes: DEFAULT_CONFIG.modes.clone(),
version: default_config::version(),
general: default_config::general(),
node_types: default_config::node_types(),
modes: default_config::modes(),
}
}
}
impl Config {
pub fn extended(mut self) -> Self {
let default = Self::default();
self.general = default.general.extend(self.general);
self.node_types = default.node_types.extend(self.node_types);
self.modes = default.modes.extend(self.modes);
self
}
}

File diff suppressed because it is too large Load Diff

@ -1,8 +1,24 @@
pub const DEFAULT_CONFIG_YAML: &str = include_str!("config.yml");
const DEFAULT_CONFIG_YAML: &str = include_str!("config.yml");
use crate::config::Config;
use crate::config::{self, Config};
use lazy_static::lazy_static;
lazy_static! {
pub static ref DEFAULT_CONFIG: Config = serde_yaml::from_str(DEFAULT_CONFIG_YAML).unwrap();
static ref DEFAULT_CONFIG: Config = serde_yaml::from_str(DEFAULT_CONFIG_YAML).unwrap();
}
pub fn version() -> String {
DEFAULT_CONFIG.version.clone()
}
pub fn general() -> config::GeneralConfig {
DEFAULT_CONFIG.general.clone()
}
pub fn node_types() -> config::NodeTypesConfig {
DEFAULT_CONFIG.node_types.clone()
}
pub fn modes() -> config::ModesConfig {
DEFAULT_CONFIG.modes.clone()
}

@ -124,8 +124,10 @@ fn main() -> Result<()> {
.table
.row
.cols
.to_owned()
.unwrap_or_default()
.iter()
.map(|c| c.format.to_string())
.map(|c| c.format.clone().unwrap_or_default())
.collect::<Vec<String>>()
.join("\t"),
)?;

@ -36,13 +36,12 @@ struct NodeUiMetadata {
pub is_before_focus: bool,
pub is_after_focus: bool,
pub tree: String,
pub icon: String,
pub prefix: String,
pub suffix: String,
pub is_selected: bool,
pub is_focused: bool,
pub total: usize,
pub custom: HashMap<String, String>,
pub meta: HashMap<String, String>,
}
impl NodeUiMetadata {
@ -53,13 +52,12 @@ impl NodeUiMetadata {
is_before_focus: bool,
is_after_focus: bool,
tree: String,
icon: String,
prefix: String,
suffix: String,
is_selected: bool,
is_focused: bool,
total: usize,
custom: HashMap<String, String>,
meta: HashMap<String, String>,
) -> Self {
Self {
parent: node.parent.clone(),
@ -76,13 +74,12 @@ impl NodeUiMetadata {
is_before_focus,
is_after_focus,
tree,
icon,
prefix,
suffix,
is_selected,
is_focused,
total,
custom,
meta,
}
}
}
@ -110,11 +107,11 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
let is_selected = app.selection().contains(&node);
let ui = if is_focused {
&config.general.focused_ui
&config.general.focus_ui
} else if is_selected {
&config.general.selection_ui
} else {
&config.general.normal_ui
&config.general.default_ui
};
let is_first = index == 0;
@ -136,19 +133,19 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
})
.unwrap_or_default();
let filetype = config
.filetypes
let node_type = config
.node_types
.special
.get(&node.relative_path)
.or_else(|| config.filetypes.extension.get(&node.extension))
.or_else(|| config.filetypes.mime_essence.get(&node.mime_essence))
.or_else(|| config.node_types.extension.get(&node.extension))
.or_else(|| config.node_types.mime_essence.get(&node.mime_essence))
.unwrap_or_else(|| {
if node.is_symlink {
&config.filetypes.symlink
&config.node_types.symlink
} else if node.is_dir {
&config.filetypes.directory
&config.node_types.directory
} else {
&config.filetypes.file
&config.node_types.file
}
});
@ -165,14 +162,13 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
relative_index,
is_before_focus,
is_after_focus,
tree,
filetype.icon.clone(),
ui.prefix.clone(),
ui.suffix.clone(),
tree.unwrap_or_default(),
ui.prefix.to_owned().unwrap_or_default(),
ui.suffix.to_owned().unwrap_or_default(),
is_selected,
is_focused,
dir.total,
filetype.custom.clone(),
node_type.meta.clone(),
);
let cols = hb
@ -184,29 +180,29 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
.collect::<Vec<Cell>>();
let style = if is_focused {
config.general.focused_ui.style
config.general.focus_ui.style
} else if is_selected {
config.general.selection_ui.style
} else {
config
.filetypes
.node_types
.special
.get(&node.relative_path)
.or_else(|| config.filetypes.extension.get(&node.extension))
.or_else(|| config.filetypes.mime_essence.get(&node.mime_essence))
.or_else(|| config.node_types.extension.get(&node.extension))
.or_else(|| config.node_types.mime_essence.get(&node.mime_essence))
.unwrap_or_else(|| {
if node.is_symlink {
&config.filetypes.symlink
&config.node_types.symlink
} else if node.is_dir {
&config.filetypes.directory
&config.node_types.directory
} else {
&config.filetypes.file
&config.node_types.file
}
})
.style
};
Row::new(cols).style(style)
Row::new(cols).style(style.into())
})
.collect::<Vec<Row>>()
})
@ -217,39 +213,37 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
.table
.col_widths
.clone()
.unwrap_or_default()
.into_iter()
.map(|c| c.into())
.collect();
let table = Table::new(rows)
.widths(&table_constraints)
.style(config.general.table.style)
.highlight_style(config.general.focused_ui.style)
.column_spacing(config.general.table.col_spacing)
.style(config.general.table.style.into())
.highlight_style(config.general.focus_ui.style.into())
.column_spacing(config.general.table.col_spacing.unwrap_or_default())
.block(
Block::default()
.borders(Borders::ALL)
.title(format!(" {} ", app.pwd())),
);
let table = config
.general
.table
.header
.clone()
.map(|h| {
table.clone().header(
Row::new(
h.cols
.iter()
.map(|c| Cell::from(c.format.to_owned()))
.collect::<Vec<Cell>>(),
)
.height(h.height)
.style(h.style),
)
})
.unwrap_or_else(|| table.clone());
let table = table.clone().header(
Row::new(
config
.general
.table
.header
.cols
.unwrap_or_default()
.iter()
.map(|c| Cell::from(c.format.to_owned().unwrap_or_default()))
.collect::<Vec<Cell>>(),
)
.height(config.general.table.header.height.unwrap_or_default())
.style(config.general.table.header.style.into()),
);
let mut table_state = TableState::default();
table_state.select(app.directory_buffer().map(|dir| dir.focus));

Loading…
Cancel
Save