Make config private

This commit is contained in:
Arijit Basu 2021-04-26 11:52:46 +05:30 committed by Arijit Basu
parent 2470827aac
commit 8ddc000895
5 changed files with 590 additions and 206 deletions

View File

@ -1398,7 +1398,7 @@ impl App {
let config_file = config_dir.join("config.yml");
let default_config = Config::default();
let default_config_version = default_config.version.clone();
let default_config_version = default_config.version().clone();
let config: Config = if config_file.exists() {
let c: Config =
@ -1415,16 +1415,16 @@ impl App {
Required version is : {}
Visit {}",
config_file.to_string_lossy().to_string(),
config.version,
config.version(),
default_config_version,
UPGRADE_GUIDE_LINK,
)
};
let mode = match config.modes.builtin.get(&"default".to_string()) {
let mode = match config.modes().builtin().get(&"default".to_string()) {
Some(m) => m
.clone()
.sanitized(config.general.read_only.unwrap_or_default()),
.sanitized(config.general().read_only().unwrap_or_default()),
None => {
bail!("'default' mode is missing")
}
@ -1440,14 +1440,14 @@ impl App {
.to_string();
let mut explorer_config = ExplorerConfig::default();
if !config.general.show_hidden.unwrap_or_default() {
if !config.general().show_hidden().unwrap_or_default() {
explorer_config.filters.replace(NodeFilterApplicable::new(
NodeFilter::RelativePathDoesNotStartWith,
".".into(),
));
}
if let Some(sorters) = &config.general.initial_sorting {
if let Some(sorters) = &config.general().initial_sorting() {
explorer_config.sorters = sorters.clone();
};
@ -1455,7 +1455,7 @@ impl App {
history = history.push(pwd.to_string_lossy().to_string());
let mut app = Self {
version: Config::default().version,
version: Config::default().version().clone(),
config: config.clone(),
pwd: pwd.to_string_lossy().to_string(),
directory_buffers: Default::default(),
@ -1474,7 +1474,9 @@ impl App {
if let Some(notif) = config.upgrade_notification()? {
let notif = format!(
"{}. To stop seeing this log, update your config version from {} to {}.",
&notif, &config.version, &app.version
&notif,
config.version(),
app.version()
);
app = app.enqueue(Task::new(
MsgIn::External(ExternalMsg::LogInfo(notif)),
@ -1517,7 +1519,7 @@ impl App {
}
fn handle_external(self, msg: ExternalMsg, key: Option<Key>, last_app: &Self) -> Result<Self> {
if self.config().general.read_only.unwrap_or_default() && !msg.is_read_only() {
if self.config().general().read_only().unwrap_or_default() && !msg.is_read_only() {
self.log_error("Cannot call shell command in read-only mode.".into())
} else {
match msg {
@ -1604,27 +1606,29 @@ impl App {
}
fn handle_key(mut self, key: Key) -> Result<Self> {
let kb = self.mode.key_bindings.clone();
let kb = self.mode().key_bindings().clone();
let key_str = key.to_string();
let default = kb.default.clone();
let default = kb.default().clone();
let msgs = kb
.remaps
.remaps()
.get(&key_str)
.and_then(|k| kb.on_key.get(k))
.or_else(|| kb.on_key.get(&key_str))
.map(|a| Some(a.messages.clone()))
.and_then(|k| kb.on_key().get(k))
.or_else(|| kb.on_key().get(&key_str))
.map(|a| Some(a.messages().clone()))
.unwrap_or_else(|| {
if key.is_alphabet() {
kb.on_alphabet.map(|a| a.messages)
kb.on_alphabet().clone().map(|a| a.messages().clone())
} else if key.is_number() {
kb.on_number.map(|a| a.messages)
kb.on_number().clone().map(|a| a.messages().clone())
} else if key.is_special_character() {
kb.on_special_character.map(|a| a.messages)
kb.on_special_character()
.clone()
.map(|a| a.messages().clone())
} else {
None
}
})
.unwrap_or_else(|| default.map(|a| a.messages).unwrap_or_default());
.unwrap_or_else(|| default.map(|a| a.messages().clone()).unwrap_or_default());
for msg in msgs {
self = self.enqueue(Task::new(MsgIn::External(msg), Some(key)));
@ -1891,11 +1895,11 @@ impl App {
}
fn switch_mode(mut self, mode: &str) -> Result<Self> {
if let Some(mode) = self.config.modes.get(mode) {
if let Some(mode) = self.config().modes().clone().get(mode) {
self.input_buffer = None;
self.mode = mode
.to_owned()
.sanitized(self.config.general.read_only.unwrap_or_default());
.sanitized(self.config().general().read_only().unwrap_or_default());
self.msg_out.push_back(MsgOut::Refresh);
};
Ok(self)
@ -2066,7 +2070,7 @@ impl App {
fn reset_node_filters(mut self) -> Result<Self> {
self.explorer_config.filters.clear();
if !self.config.general.show_hidden.unwrap_or_default() {
if !self.config().general().show_hidden().unwrap_or_default() {
self.add_node_filter(NodeFilterApplicable::new(
NodeFilter::RelativePathDoesNotStartWith,
".".into(),
@ -2125,9 +2129,9 @@ impl App {
fn reset_node_sorters(mut self) -> Result<Self> {
self.explorer_config.sorters = self
.config
.general
.initial_sorting
.config()
.general()
.initial_sorting()
.to_owned()
.unwrap_or_default();
Ok(self)
@ -2207,7 +2211,7 @@ impl App {
}
pub fn mode_str(&self) -> String {
format!("{}\n", &self.mode.name)
format!("{}\n", &self.mode.name())
}
/// Get a reference to the app's directory buffers.
@ -2288,28 +2292,28 @@ impl App {
}
pub fn global_help_menu_str(&self) -> String {
let builtin = self.config().modes.builtin.clone();
let custom = self.config().modes.custom.clone();
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.default().name().clone(), builtin.default().clone()),
(builtin.number().name().clone(), builtin.number().clone()),
(builtin.go_to().name().clone(), builtin.go_to().clone()),
(builtin.search().name().clone(), builtin.search().clone()),
(builtin.selection_ops().name().clone(), builtin.selection_ops().clone()),
(builtin.action().name().clone(), builtin.action().clone()),
(builtin.create().name().clone(), builtin.create().clone()),
(builtin.create_file().name().clone(), builtin.create_file().clone()),
(
builtin.create_directory.name.clone(),
builtin.create_directory,
builtin.create_directory().name().clone(),
builtin.create_directory().clone(),
),
(builtin.rename.name.clone(), builtin.rename),
(builtin.delete.name.clone(), builtin.delete),
(builtin.sort.name.clone(), builtin.sort),
(builtin.filter.name.clone(), builtin.filter),
(builtin.relative_path_does_contain.name.clone(), builtin.relative_path_does_contain),
(builtin.relative_path_does_not_contain.name.clone(), builtin.relative_path_does_not_contain),
(builtin.rename().name().clone(), builtin.rename().clone()),
(builtin.delete().name().clone(), builtin.delete().clone()),
(builtin.sort().name().clone(), builtin.sort().clone()),
(builtin.filter().name().clone(), builtin.filter().clone()),
(builtin.relative_path_does_contain().name().clone(), builtin.relative_path_does_contain().clone()),
(builtin.relative_path_does_not_contain().name().clone(), builtin.relative_path_does_not_contain().clone()),
]
.iter()
.chain(custom.into_iter().collect::<Vec<(String, Mode)>>().iter())
@ -2322,8 +2326,8 @@ impl App {
HelpMenuLine::KeyMap(k, h) => {
let remaps = self
.mode()
.key_bindings
.remaps
.key_bindings()
.remaps()
.iter()
.filter(|(_, t)| t == &k)
.map(|(f, _)| f.clone())

View File

@ -16,10 +16,10 @@ use tui::layout::Constraint as TuiConstraint;
#[serde(deny_unknown_fields)]
pub struct Action {
#[serde(default)]
pub help: Option<String>,
help: Option<String>,
#[serde(default)]
pub messages: Vec<ExternalMsg>,
messages: Vec<ExternalMsg>,
}
impl Action {
@ -42,16 +42,26 @@ impl Action {
self.messages = other.messages;
self
}
/// Get a reference to the action's help.
pub fn help(&self) -> &Option<String> {
&self.help
}
/// Get a reference to the action's messages.
pub fn messages(&self) -> &Vec<ExternalMsg> {
&self.messages
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NodeTypeConfig {
#[serde(default)]
pub style: Style,
style: Style,
#[serde(default)]
pub meta: HashMap<String, String>,
meta: HashMap<String, String>,
}
impl NodeTypeConfig {
@ -60,28 +70,38 @@ impl NodeTypeConfig {
self.meta.extend(other.meta);
self
}
/// Get a reference to the node type config's style.
pub fn style(&self) -> Style {
self.style
}
/// Get a reference to the node type config's meta.
pub fn meta(&self) -> &HashMap<String, String> {
&self.meta
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NodeTypesConfig {
#[serde(default)]
pub directory: NodeTypeConfig,
directory: NodeTypeConfig,
#[serde(default)]
pub file: NodeTypeConfig,
file: NodeTypeConfig,
#[serde(default)]
pub symlink: NodeTypeConfig,
symlink: NodeTypeConfig,
#[serde(default)]
pub mime_essence: HashMap<String, NodeTypeConfig>,
mime_essence: HashMap<String, NodeTypeConfig>,
#[serde(default)]
pub extension: HashMap<String, NodeTypeConfig>,
extension: HashMap<String, NodeTypeConfig>,
#[serde(default)]
pub special: HashMap<String, NodeTypeConfig>,
special: HashMap<String, NodeTypeConfig>,
}
impl NodeTypesConfig {
@ -94,19 +114,49 @@ impl NodeTypesConfig {
self.special.extend(other.special);
self
}
/// Get a reference to the node types config's directory.
pub fn directory(&self) -> &NodeTypeConfig {
&self.directory
}
/// Get a reference to the node types config's file.
pub fn file(&self) -> &NodeTypeConfig {
&self.file
}
/// Get a reference to the node types config's symlink.
pub fn symlink(&self) -> &NodeTypeConfig {
&self.symlink
}
/// Get a reference to the node types config's mime essence.
pub fn mime_essence(&self) -> &HashMap<String, NodeTypeConfig> {
&self.mime_essence
}
/// Get a reference to the node types config's extension.
pub fn extension(&self) -> &HashMap<String, NodeTypeConfig> {
&self.extension
}
/// Get a reference to the node types config's special.
pub fn special(&self) -> &HashMap<String, NodeTypeConfig> {
&self.special
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct UiConfig {
#[serde(default)]
pub prefix: Option<String>,
pub(crate) prefix: Option<String>,
#[serde(default)]
pub suffix: Option<String>,
pub(crate) suffix: Option<String>,
#[serde(default)]
pub style: Style,
pub(crate) style: Style,
}
impl UiConfig {
@ -116,16 +166,31 @@ impl UiConfig {
self.style = self.style.extend(other.style);
self
}
/// Get a reference to the ui config's prefix.
pub fn prefix(&self) -> &Option<String> {
&self.prefix
}
/// Get a reference to the ui config's suffix.
pub fn suffix(&self) -> &Option<String> {
&self.suffix
}
/// Get a reference to the ui config's style.
pub fn style(&self) -> Style {
self.style
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct UiElement {
#[serde(default)]
pub format: Option<String>,
format: Option<String>,
#[serde(default)]
pub style: Style,
style: Style,
}
impl UiElement {
@ -134,19 +199,29 @@ impl UiElement {
self.style = self.style.extend(other.style);
self
}
/// Get a reference to the ui element's format.
pub fn format(&self) -> &Option<String> {
&self.format
}
/// Get a reference to the ui element's style.
pub fn style(&self) -> Style {
self.style
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TableRowConfig {
#[serde(default)]
pub cols: Option<Vec<UiElement>>,
cols: Option<Vec<UiElement>>,
#[serde(default)]
pub style: Style,
style: Style,
#[serde(default)]
pub height: Option<u16>,
height: Option<u16>,
}
impl TableRowConfig {
@ -156,6 +231,21 @@ impl TableRowConfig {
self.height = other.height.or(self.height);
self
}
/// Get a reference to the table row config's cols.
pub fn cols(&self) -> &Option<Vec<UiElement>> {
&self.cols
}
/// Get a reference to the table row config's style.
pub fn style(&self) -> Style {
self.style
}
/// Get a reference to the table row config's height.
pub fn height(&self) -> Option<u16> {
self.height
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
@ -190,22 +280,22 @@ impl Into<TuiConstraint> for Constraint {
#[serde(deny_unknown_fields)]
pub struct TableConfig {
#[serde(default)]
pub header: TableRowConfig,
header: TableRowConfig,
#[serde(default)]
pub row: TableRowConfig,
row: TableRowConfig,
#[serde(default)]
pub style: Style,
style: Style,
#[serde(default)]
pub tree: Option<(UiElement, UiElement, UiElement)>,
tree: Option<(UiElement, UiElement, UiElement)>,
#[serde(default)]
pub col_spacing: Option<u16>,
col_spacing: Option<u16>,
#[serde(default)]
pub col_widths: Option<Vec<Constraint>>,
col_widths: Option<Vec<Constraint>>,
}
impl TableConfig {
@ -218,19 +308,49 @@ impl TableConfig {
self.col_widths = other.col_widths.or(self.col_widths);
self
}
/// Get a reference to the table config's header.
pub fn header(&self) -> &TableRowConfig {
&self.header
}
/// Get a reference to the table config's row.
pub fn row(&self) -> &TableRowConfig {
&self.row
}
/// Get a reference to the table config's style.
pub fn style(&self) -> Style {
self.style
}
/// Get a reference to the table config's tree.
pub fn tree(&self) -> &Option<(UiElement, UiElement, UiElement)> {
&self.tree
}
/// Get a reference to the table config's col spacing.
pub fn col_spacing(&self) -> Option<u16> {
self.col_spacing
}
/// Get a reference to the table config's col widths.
pub fn col_widths(&self) -> &Option<Vec<Constraint>> {
&self.col_widths
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LogsConfig {
#[serde(default)]
pub info: UiElement,
info: UiElement,
#[serde(default)]
pub success: UiElement,
success: UiElement,
#[serde(default)]
pub error: UiElement,
error: UiElement,
}
impl LogsConfig {
@ -240,16 +360,31 @@ impl LogsConfig {
self.error = self.error.extend(other.error);
self
}
/// Get a reference to the logs config's info.
pub fn info(&self) -> &UiElement {
&self.info
}
/// Get a reference to the logs config's success.
pub fn success(&self) -> &UiElement {
&self.success
}
/// Get a reference to the logs config's error.
pub fn error(&self) -> &UiElement {
&self.error
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SortDirectionIdentifiersUi {
#[serde(default)]
pub forward: UiElement,
forward: UiElement,
#[serde(default)]
pub reverse: UiElement,
reverse: UiElement,
}
impl SortDirectionIdentifiersUi {
@ -258,22 +393,32 @@ impl SortDirectionIdentifiersUi {
self.reverse = self.reverse.extend(other.reverse);
self
}
/// Get a reference to the sort direction identifiers ui's forward.
pub fn forward(&self) -> &UiElement {
&self.forward
}
/// Get a reference to the sort direction identifiers ui's reverse.
pub fn reverse(&self) -> &UiElement {
&self.reverse
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SortAndFilterUi {
#[serde(default)]
pub separator: UiElement,
separator: UiElement,
#[serde(default)]
pub sort_direction_identifiers: SortDirectionIdentifiersUi,
sort_direction_identifiers: SortDirectionIdentifiersUi,
#[serde(default)]
pub sorter_identifiers: HashMap<NodeSorter, UiElement>,
sorter_identifiers: HashMap<NodeSorter, UiElement>,
#[serde(default)]
pub filter_identifiers: HashMap<NodeFilter, UiElement>,
filter_identifiers: HashMap<NodeFilter, UiElement>,
}
impl SortAndFilterUi {
@ -286,47 +431,67 @@ impl SortAndFilterUi {
self.filter_identifiers.extend(other.filter_identifiers);
self
}
/// Get a reference to the sort and filter ui's separator.
pub fn separator(&self) -> &UiElement {
&self.separator
}
/// Get a reference to the sort and filter ui's sort direction identifiers.
pub fn sort_direction_identifiers(&self) -> &SortDirectionIdentifiersUi {
&self.sort_direction_identifiers
}
/// Get a reference to the sort and filter ui's sorter identifiers.
pub fn sorter_identifiers(&self) -> &HashMap<NodeSorter, UiElement> {
&self.sorter_identifiers
}
/// Get a reference to the sort and filter ui's filter identifiers.
pub fn filter_identifiers(&self) -> &HashMap<NodeFilter, UiElement> {
&self.filter_identifiers
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct GeneralConfig {
#[serde(default)]
pub show_hidden: Option<bool>,
show_hidden: Option<bool>,
#[serde(default)]
pub read_only: Option<bool>,
read_only: Option<bool>,
#[serde(default)]
pub cursor: UiElement,
cursor: UiElement,
#[serde(default)]
pub prompt: UiElement,
prompt: UiElement,
#[serde(default)]
pub logs: LogsConfig,
logs: LogsConfig,
#[serde(default)]
pub table: TableConfig,
table: TableConfig,
#[serde(default)]
pub default_ui: UiConfig,
default_ui: UiConfig,
#[serde(default)]
pub focus_ui: UiConfig,
focus_ui: UiConfig,
#[serde(default)]
pub selection_ui: UiConfig,
selection_ui: UiConfig,
#[serde(default)]
pub sort_and_filter_ui: SortAndFilterUi,
sort_and_filter_ui: SortAndFilterUi,
#[serde(default)]
pub initial_sorting: Option<IndexSet<NodeSorterApplicable>>,
initial_sorting: Option<IndexSet<NodeSorterApplicable>>,
}
impl GeneralConfig {
pub fn extend(mut self, other: Self) -> Self {
fn extend(mut self, other: Self) -> Self {
self.show_hidden = other.show_hidden.or(self.show_hidden);
self.read_only = other.read_only.or(self.read_only);
self.cursor = self.cursor.extend(other.cursor);
@ -340,28 +505,83 @@ impl GeneralConfig {
self.initial_sorting = other.initial_sorting.or(self.initial_sorting);
self
}
/// Get a reference to the general config's show hidden.
pub fn show_hidden(&self) -> Option<bool> {
self.show_hidden
}
/// Get a reference to the general config's read only.
pub fn read_only(&self) -> Option<bool> {
self.read_only
}
/// Get a reference to the general config's cursor.
pub fn cursor(&self) -> &UiElement {
&self.cursor
}
/// Get a reference to the general config's prompt.
pub fn prompt(&self) -> &UiElement {
&self.prompt
}
/// Get a reference to the general config's logs.
pub fn logs(&self) -> &LogsConfig {
&self.logs
}
/// Get a reference to the general config's table.
pub fn table(&self) -> &TableConfig {
&self.table
}
/// Get a reference to the general config's default ui.
pub fn default_ui(&self) -> &UiConfig {
&self.default_ui
}
/// Get a reference to the general config's focus ui.
pub fn focus_ui(&self) -> &UiConfig {
&self.focus_ui
}
/// Get a reference to the general config's selection ui.
pub fn selection_ui(&self) -> &UiConfig {
&self.selection_ui
}
/// Get a reference to the general config's sort and filter ui.
pub fn sort_and_filter_ui(&self) -> &SortAndFilterUi {
&self.sort_and_filter_ui
}
/// Get a reference to the general config's initial sorting.
pub fn initial_sorting(&self) -> &Option<IndexSet<NodeSorterApplicable>> {
&self.initial_sorting
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct KeyBindings {
#[serde(default)]
pub remaps: BTreeMap<String, String>,
remaps: BTreeMap<String, String>,
#[serde(default)]
pub on_key: BTreeMap<String, Action>,
on_key: BTreeMap<String, Action>,
#[serde(default)]
pub on_alphabet: Option<Action>,
on_alphabet: Option<Action>,
#[serde(default)]
pub on_number: Option<Action>,
on_number: Option<Action>,
#[serde(default)]
pub on_special_character: Option<Action>,
on_special_character: Option<Action>,
#[serde(default)]
pub default: Option<Action>,
default: Option<Action>,
}
impl KeyBindings {
@ -391,7 +611,7 @@ impl KeyBindings {
}
}
pub fn extend(mut self, other: Self) -> Self {
fn extend(mut self, other: Self) -> Self {
self.remaps.extend(other.remaps);
self.on_key.extend(other.on_key);
self.on_alphabet = other.on_alphabet.or(self.on_alphabet);
@ -400,22 +620,52 @@ impl KeyBindings {
self.default = other.default.or(self.default);
self
}
/// Get a reference to the key bindings's remaps.
pub fn remaps(&self) -> &BTreeMap<String, String> {
&self.remaps
}
/// Get a reference to the key bindings's on key.
pub fn on_key(&self) -> &BTreeMap<String, Action> {
&self.on_key
}
/// Get a reference to the key bindings's on alphabet.
pub fn on_alphabet(&self) -> &Option<Action> {
&self.on_alphabet
}
/// Get a reference to the key bindings's on number.
pub fn on_number(&self) -> &Option<Action> {
&self.on_number
}
/// Get a reference to the key bindings's on special character.
pub fn on_special_character(&self) -> &Option<Action> {
&self.on_special_character
}
/// Get a reference to the key bindings's default.
pub fn default(&self) -> &Option<Action> {
&self.default
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Mode {
#[serde(default)]
pub name: String,
name: String,
#[serde(default)]
pub help: Option<String>,
help: Option<String>,
#[serde(default)]
pub extra_help: Option<String>,
extra_help: Option<String>,
#[serde(default)]
pub key_bindings: KeyBindings,
key_bindings: KeyBindings,
}
impl Mode {
@ -424,7 +674,7 @@ impl Mode {
self
}
pub fn extend(mut self, other: Self) -> Self {
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 = self.key_bindings.extend(other.key_bindings);
@ -489,55 +739,75 @@ impl Mode {
.collect()
})
}
/// Get a reference to the mode's name.
pub fn name(&self) -> &String {
&self.name
}
/// Get a reference to the mode's help.
pub fn help(&self) -> &Option<String> {
&self.help
}
/// Get a reference to the mode's extra help.
pub fn extra_help(&self) -> &Option<String> {
&self.extra_help
}
/// Get a reference to the mode's key bindings.
pub fn key_bindings(&self) -> &KeyBindings {
&self.key_bindings
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct BuiltinModesConfig {
#[serde(default)]
pub default: Mode,
default: Mode,
#[serde(default)]
pub selection_ops: Mode,
selection_ops: Mode,
#[serde(default)]
pub create: Mode,
create: Mode,
#[serde(default)]
pub create_directory: Mode,
create_directory: Mode,
#[serde(default)]
pub create_file: Mode,
create_file: Mode,
#[serde(default)]
pub number: Mode,
number: Mode,
#[serde(default)]
pub go_to: Mode,
go_to: Mode,
#[serde(default)]
pub rename: Mode,
rename: Mode,
#[serde(default)]
pub delete: Mode,
delete: Mode,
#[serde(default)]
pub action: Mode,
action: Mode,
#[serde(default)]
pub search: Mode,
search: Mode,
#[serde(default)]
pub filter: Mode,
filter: Mode,
#[serde(default)]
pub relative_path_does_contain: Mode,
relative_path_does_contain: Mode,
#[serde(default)]
pub relative_path_does_not_contain: Mode,
relative_path_does_not_contain: Mode,
#[serde(default)]
pub sort: Mode,
sort: Mode,
}
impl BuiltinModesConfig {
@ -590,16 +860,91 @@ impl BuiltinModesConfig {
_ => None,
}
}
/// Get a reference to the builtin modes config's default.
pub fn default(&self) -> &Mode {
&self.default
}
/// Get a reference to the builtin modes config's selection ops.
pub fn selection_ops(&self) -> &Mode {
&self.selection_ops
}
/// Get a reference to the builtin modes config's create.
pub fn create(&self) -> &Mode {
&self.create
}
/// Get a reference to the builtin modes config's create directory.
pub fn create_directory(&self) -> &Mode {
&self.create_directory
}
/// Get a reference to the builtin modes config's create file.
pub fn create_file(&self) -> &Mode {
&self.create_file
}
/// Get a reference to the builtin modes config's number.
pub fn number(&self) -> &Mode {
&self.number
}
/// Get a reference to the builtin modes config's go to.
pub fn go_to(&self) -> &Mode {
&self.go_to
}
/// Get a reference to the builtin modes config's rename.
pub fn rename(&self) -> &Mode {
&self.rename
}
/// Get a reference to the builtin modes config's delete.
pub fn delete(&self) -> &Mode {
&self.delete
}
/// Get a reference to the builtin modes config's action.
pub fn action(&self) -> &Mode {
&self.action
}
/// Get a reference to the builtin modes config's search.
pub fn search(&self) -> &Mode {
&self.search
}
/// Get a reference to the builtin modes config's filter.
pub fn filter(&self) -> &Mode {
&self.filter
}
/// Get a reference to the builtin modes config's relative path does contain.
pub fn relative_path_does_contain(&self) -> &Mode {
&self.relative_path_does_contain
}
/// Get a reference to the builtin modes config's relative path does not contain.
pub fn relative_path_does_not_contain(&self) -> &Mode {
&self.relative_path_does_not_contain
}
/// Get a reference to the builtin modes config's sort.
pub fn sort(&self) -> &Mode {
&self.sort
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ModesConfig {
#[serde(default)]
pub builtin: BuiltinModesConfig,
builtin: BuiltinModesConfig,
#[serde(default)]
pub custom: HashMap<String, Mode>,
custom: HashMap<String, Mode>,
}
impl ModesConfig {
@ -612,21 +957,31 @@ impl ModesConfig {
self.custom.extend(other.custom);
self
}
/// Get a reference to the modes config's builtin.
pub fn builtin(&self) -> &BuiltinModesConfig {
&self.builtin
}
/// Get a reference to the modes config's custom.
pub fn custom(&self) -> &HashMap<String, Mode> {
&self.custom
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub version: String,
version: String,
#[serde(default)]
pub general: GeneralConfig,
general: GeneralConfig,
#[serde(default)]
pub node_types: NodeTypesConfig,
node_types: NodeTypesConfig,
#[serde(default)]
pub modes: ModesConfig,
modes: ModesConfig,
}
impl Default for Config {
@ -693,6 +1048,26 @@ impl Config {
Ok(result)
}
/// Get a reference to the config's version.
pub fn version(&self) -> &String {
&self.version
}
/// Get a reference to the config's general.
pub fn general(&self) -> &GeneralConfig {
&self.general
}
/// Get a reference to the config's node types.
pub fn node_types(&self) -> &NodeTypesConfig {
&self.node_types
}
/// Get a reference to the config's modes.
pub fn modes(&self) -> &ModesConfig {
&self.modes
}
}
#[cfg(test)]

View File

@ -8,17 +8,17 @@ lazy_static! {
}
pub fn version() -> String {
DEFAULT_CONFIG.version.clone()
DEFAULT_CONFIG.version().clone()
}
pub fn general() -> config::GeneralConfig {
DEFAULT_CONFIG.general.clone()
DEFAULT_CONFIG.general().clone()
}
pub fn node_types() -> config::NodeTypesConfig {
DEFAULT_CONFIG.node_types.clone()
DEFAULT_CONFIG.node_types().clone()
}
pub fn modes() -> config::ModesConfig {
DEFAULT_CONFIG.modes.clone()
DEFAULT_CONFIG.modes().clone()
}

View File

@ -38,7 +38,7 @@ fn call(app: &app::App, cmd: app::Command, silent: bool) -> io::Result<ExitStatu
Command::new(cmd.command().clone())
.env("XPLR_APP_VERSION", app.version())
.env("XPLR_CONFIG_VERSION", &app.config().version)
.env("XPLR_CONFIG_VERSION", app.config().version())
.env("XPLR_PID", &app.pid().to_string())
.env("XPLR_INPUT_BUFFER", app.input_buffer().unwrap_or_default())
.env("XPLR_FOCUS_PATH", app.focused_node_str())
@ -83,14 +83,14 @@ pub fn run(mut app: app::App, focused_path: Option<String>) -> Result<Option<Str
hb.register_template_string(
app::TEMPLATE_TABLE_ROW,
&app.config()
.general
.table
.row
.cols
.to_owned()
.general()
.table()
.row()
.cols()
.clone()
.unwrap_or_default()
.iter()
.map(|c| c.format.clone().unwrap_or_default())
.map(|c| c.format().clone().unwrap_or_default())
.collect::<Vec<String>>()
.join("\t"),
)?;

147
src/ui.rs
View File

@ -169,7 +169,7 @@ impl NodeUiMetadata {
fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Handlebars) {
let config = app.config().to_owned();
let header_height = config.general.table.header.height.unwrap_or(1);
let header_height = config.general().table().header().height().unwrap_or(1);
let height: usize = (rect.height.max(header_height + 2) - (header_height + 2)).into();
let rows = app
@ -190,34 +190,34 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
let is_last = index == dir.total().max(1) - 1;
let tree = config
.general
.table
.tree
.general()
.table()
.tree()
.clone()
.map(|t| {
if is_last {
t.2.format
t.2.format().clone()
} else if is_first {
t.0.format
t.0.format().clone()
} else {
t.1.format
t.1.format().clone()
}
})
.unwrap_or_default();
let node_type = config
.node_types
.special
.node_types()
.special()
.get(node.relative_path())
.or_else(|| config.node_types.extension.get(node.extension()))
.or_else(|| config.node_types.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.node_types.symlink
&config.node_types().symlink()
} else if node.is_dir() {
&config.node_types.directory
&config.node_types().directory()
} else {
&config.node_types.file
&config.node_types().file()
}
});
@ -229,22 +229,26 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
};
let (mut prefix, mut suffix, mut style) = {
let ui = config.general.default_ui.clone();
(ui.prefix, ui.suffix, ui.style.extend(node_type.style))
let ui = config.general().default_ui().clone();
(
ui.prefix().clone(),
ui.suffix().clone(),
ui.style().extend(node_type.style()),
)
};
if is_selected {
let ui = config.general.selection_ui.clone();
prefix = ui.prefix.or(prefix);
suffix = ui.suffix.or(suffix);
style = style.extend(ui.style);
let ui = config.general().selection_ui().clone();
prefix = ui.prefix().clone().or(prefix);
suffix = ui.suffix().clone().or(suffix);
style = style.extend(ui.style());
};
if is_focused {
let ui = config.general.focus_ui.clone();
prefix = ui.prefix.or(prefix);
suffix = ui.suffix.or(suffix);
style = style.extend(ui.style);
let ui = config.general().focus_ui().clone();
prefix = ui.prefix().clone().or(prefix);
suffix = ui.suffix().clone().or(suffix);
style = style.extend(ui.style());
};
let meta = NodeUiMetadata::new(
@ -259,7 +263,7 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
is_selected,
is_focused,
dir.total(),
node_type.meta.clone(),
node_type.meta().clone(),
);
let cols = hb
@ -277,9 +281,9 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
.unwrap_or_default();
let table_constraints: Vec<TuiConstraint> = config
.general
.table
.col_widths
.general()
.table()
.col_widths()
.clone()
.unwrap_or_default()
.into_iter()
@ -288,9 +292,9 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
let table = Table::new(rows)
.widths(&table_constraints)
.style(config.general.table.style.into())
.highlight_style(config.general.focus_ui.style.into())
.column_spacing(config.general.table.col_spacing.unwrap_or_default())
.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(),
@ -300,17 +304,18 @@ fn draw_table<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, hb: &Han
let table = table.clone().header(
Row::new(
config
.general
.table
.header
.cols
.general()
.table()
.header()
.cols()
.clone()
.unwrap_or_default()
.iter()
.map(|c| Cell::from(c.format.to_owned().unwrap_or_default()))
.map(|c| Cell::from(c.format().to_owned().unwrap_or_default()))
.collect::<Vec<Cell>>(),
)
.height(header_height)
.style(config.general.table.header.style.into()),
.style(config.general().table().header().style().into()),
);
f.render_widget(table, rect);
@ -349,8 +354,8 @@ fn draw_help_menu<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, _: &
HelpMenuLine::KeyMap(k, h) => {
let remaps = app
.mode()
.key_bindings
.remaps
.key_bindings()
.remaps()
.iter()
.filter(|(_, t)| t == &&k)
.map(|(f, _)| f.clone())
@ -361,7 +366,7 @@ fn draw_help_menu<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, _: &
})
.collect::<Vec<Row>>();
let read_only_indicator = if app.config().general.read_only.unwrap_or_default() {
let read_only_indicator = if app.config().general().read_only().unwrap_or_default() {
"(r)"
} else {
""
@ -370,7 +375,7 @@ fn draw_help_menu<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, _: &
let help_menu = Table::new(help_menu_rows)
.block(Block::default().borders(Borders::ALL).title(format!(
" Help [{}{}] ",
&app.mode().name,
&app.mode().name(),
read_only_indicator
)))
.widths(&[
@ -385,22 +390,22 @@ fn draw_input_buffer<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, _
let input_buf = Paragraph::new(Spans::from(vec![
Span::styled(
app.config()
.general
.prompt
.format
.general()
.prompt()
.format()
.clone()
.unwrap_or_default(),
app.config().general.prompt.style.into(),
app.config().general().prompt().style().into(),
),
Span::raw(app.input_buffer().unwrap_or_else(|| "".into())),
Span::styled(
app.config()
.general
.cursor
.format
.general()
.cursor()
.format()
.clone()
.unwrap_or_default(),
app.config().general.cursor.style.into(),
app.config().general().cursor().style().into(),
),
]))
.block(Block::default().borders(Borders::ALL).title(" Input "));
@ -408,35 +413,35 @@ fn draw_input_buffer<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, _
}
fn draw_sort_n_filter_by<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, _: &Handlebars) {
let ui = app.config().general.sort_and_filter_ui.clone();
let ui = app.config().general().sort_and_filter_ui().clone();
let filter_by = app.explorer_config().filters();
let sort_by = app.explorer_config().sorters();
let forward = Span::styled(
ui.sort_direction_identifiers
.forward
.format
ui.sort_direction_identifiers()
.forward()
.format()
.to_owned()
.unwrap_or_default(),
ui.sort_direction_identifiers.forward.style.into(),
ui.sort_direction_identifiers().forward().style().into(),
);
let reverse = Span::styled(
ui.sort_direction_identifiers
.reverse
.format
ui.sort_direction_identifiers()
.reverse()
.format()
.to_owned()
.unwrap_or_default(),
ui.sort_direction_identifiers.reverse.style.into(),
ui.sort_direction_identifiers().reverse().style().into(),
);
let mut spans = filter_by
.iter()
.map(|f| {
ui.filter_identifiers
ui.filter_identifiers()
.get(&f.filter())
.map(|u| {
(
Span::styled(u.format.to_owned().unwrap_or_default(), u.style.into()),
Span::styled(u.format().to_owned().unwrap_or_default(), u.style().into()),
Span::raw(f.input().clone()),
)
})
@ -449,19 +454,19 @@ fn draw_sort_n_filter_by<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::Ap
forward.clone()
};
ui.sorter_identifiers
ui.sorter_identifiers()
.get(&s.sorter())
.map(|u| {
(
Span::styled(u.format.to_owned().unwrap_or_default(), u.style.into()),
Span::styled(u.format().to_owned().unwrap_or_default(), u.style().into()),
direction.clone(),
)
})
.unwrap_or_else(|| (Span::raw("s"), direction.clone()))
}))
.zip(std::iter::repeat(Span::styled(
ui.separator.format.to_owned().unwrap_or_default(),
ui.separator.style.into(),
ui.separator().format().to_owned().unwrap_or_default(),
ui.separator().style().into(),
)))
.map(|((a, b), c)| vec![a, b, c])
.flatten()
@ -476,7 +481,7 @@ fn draw_sort_n_filter_by<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::Ap
}
fn draw_logs<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, _: &Handlebars) {
let config = app.config().general.logs.clone();
let config = app.config().general().logs().clone();
let logs = app
.logs()
.iter()
@ -489,24 +494,24 @@ fn draw_logs<B: Backend>(f: &mut Frame<B>, rect: Rect, app: &app::App, _: &Handl
app::LogLevel::Info => ListItem::new(format!(
"{} | {} | {}",
&time,
&config.info.format.to_owned().unwrap_or_default(),
&config.info().format().to_owned().unwrap_or_default(),
l.message()
))
.style(config.info.style.into()),
.style(config.info().style().into()),
app::LogLevel::Success => ListItem::new(format!(
"{} | {} | {}",
&time,
&config.success.format.to_owned().unwrap_or_default(),
&config.success().format().to_owned().unwrap_or_default(),
l.message()
))
.style(config.success.style.into()),
.style(config.success().style().into()),
app::LogLevel::Error => ListItem::new(format!(
"{} | {} | {}",
&time,
&config.error.format.to_owned().unwrap_or_default(),
&config.error().format().to_owned().unwrap_or_default(),
l.message()
))
.style(config.error.style.into()),
.style(config.error().style().into()),
}
})
.collect::<Vec<ListItem>>();