summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDLFW <daniel@llin.info>2023-10-09 04:39:00 +0200
committerGitHub <noreply@github.com>2023-10-08 22:39:00 -0400
commit8412f0534c7c7c64d3a5ebc602fbb298b9f6eba7 (patch)
tree8eb39b1a3bb138d08dc963c93acd19f0a810de2c
parent55d50925498c5b92cb7a327b506cd16f8c611255 (diff)
Scrollable tab-bar (#437)
This implements a scrollable tab bar, like discussed in #233. This makes tabs easier to read, better utilizes the space in the top-bar and makes handling many tabs way easier. The display of the current directory has been removed. The current tab will show the directory always in full form. The directories of other tabs will be shown in full form if there is enough space, otherwise, they will be shown in a short form. If the available space in the top-bar is still not sufficient, scroll tags will be added at each end. The long-form is currently defined as the full, absolute path. The short-form is currently defined as the last directory element of the path. The tab-bar is configurable in terms of font styling and style character (like dividers, prefixes, and postfixes). Documentation has been created in a separate file. Collateral impact: * The `tilde_in_titlebar` option for `[display]` in `joshuto.toml` has been removed. (Because the "current dir display" has been removed.) * The `display_mode` option for `[tabs]` in `joshuto.toml` has been removed and with it, also the `tab_bar_mode` command. The appearance of index-numbers in tags is not configurable anymore. Numbers are shown if and only if there are more than one tab. This feature can be re-introduced later in some other form if still desired with the new tab-bar. With the new tab-bar, this configuration option did not make sense the way it was designed. * The `max_len` option for `[tabs]` in `joshuto.toml` has been removed. (Because tabs don't have a fixed width anymore.) * The function/feature of shortening paths by replacing heading path elements with their first character only has been removed. (Because I expect that this hard-to-interpret representation of a path will rarely be beneficial, now that there is a better space utilization in the top bar.) * The "old" tab-bar configuration options have been removed. * A `AppStyleOptionsRaw` struct has been introduced to allow handling of more complex default styling logic. Each styling attribute is defined there as an `Option` to indicate if a styling option has been set by the user or not. * A `PathStyleIfSome` trait is now available in "utils" to patch ratatui styles with another, _optional_ style.
-rw-r--r--config/joshuto.toml1
-rw-r--r--config/theme.toml28
-rw-r--r--docs/configuration/joshuto.toml.md8
-rw-r--r--docs/configuration/tabbar/README.md264
-rw-r--r--docs/configuration/tabbar/nerdfont_bar_1.pngbin0 -> 51742 bytes
-rw-r--r--docs/configuration/theme.toml.md2
-rw-r--r--src/commands/mod.rs1
-rw-r--r--src/commands/tab_bar_mode.rs11
-rw-r--r--src/config/clean/app/display/config.rs7
-rw-r--r--src/config/clean/app/tab/config.rs66
-rw-r--r--src/config/clean/theme/tab.rs197
-rw-r--r--src/config/raw/app/display/tab.rs12
-rw-r--r--src/config/raw/theme/style.rs131
-rw-r--r--src/config/raw/theme/tab.rs48
-rw-r--r--src/context/app_context.rs2
-rw-r--r--src/context/tab_context.rs44
-rw-r--r--src/key_command/command.rs2
-rw-r--r--src/key_command/constants.rs1
-rw-r--r--src/key_command/impl_appcommand.rs1
-rw-r--r--src/key_command/impl_appexecute.rs3
-rw-r--r--src/key_command/impl_comment.rs14
-rw-r--r--src/key_command/impl_from_str.rs5
-rw-r--r--src/tab/tab_struct.rs9
-rw-r--r--src/ui/mod.rs2
-rw-r--r--src/ui/tab_list_builder.rs1040
-rw-r--r--src/ui/views/tui_folder_view.rs26
-rw-r--r--src/ui/views/tui_hsplit_view.rs19
-rw-r--r--src/ui/views/tui_worker_view.rs3
-rw-r--r--src/ui/widgets/mod.rs2
-rw-r--r--src/ui/widgets/tui_tab.rs62
-rw-r--r--src/ui/widgets/tui_topbar.rs78
-rw-r--r--src/util/format.rs24
-rw-r--r--src/util/style.rs17
33 files changed, 1714 insertions, 416 deletions
diff --git a/config/joshuto.toml b/config/joshuto.toml
index 9219ca0..455210d 100644
--- a/config/joshuto.toml
+++ b/config/joshuto.toml
@@ -18,7 +18,6 @@ scroll_offset = 6
show_borders = true
show_hidden = false
show_icons = true
-tilde_in_titlebar = true
# none, absolute, relative
line_number_style = "none"
diff --git a/config/theme.toml b/config/theme.toml
index c26502f..fce3633 100644
--- a/config/theme.toml
+++ b/config/theme.toml
@@ -2,12 +2,30 @@
## Tabs
##########################################
-# Inactive tabs
-[tabs.inactive]
+[tabs]
+[tabs.styles]
-# Active tabs
-[tabs.active]
-invert=true
+# Style of active tab & current directory
+[tabs.styles.active]
+bg = "light_blue"
+fg = "black"
+bold = true
+
+# Style of inactive tabs
+[tabs.styles.inactive]
+
+# Style of the left/front tab scroll tag (when tabs overflow)
+[tabs.styles.scroll_front]
+fg = "yellow"
+bold = true
+
+# Style of the right/back tab scroll tag (when tabs overflow)
+[tabs.styles.scroll_back]
+fg = "yellow"
+bold = true
+
+# There are more style options and strings to configure
+# the tab-bar theme.
##########################################
## File List - Selections
diff --git a/docs/configuration/joshuto.toml.md b/docs/configuration/joshuto.toml.md
index 6a77f53..ee88c33 100644
--- a/docs/configuration/joshuto.toml.md
+++ b/docs/configuration/joshuto.toml.md
@@ -119,14 +119,6 @@ fzf_case_sensitivity = "insensitive"
# ...
[tab]
-
-# Options include
-# - num
-# - dir
-# - all
-# also can be changed with the 'tab_bar_mode' command
-display_mode = "all"
-
# inherit, home, root
home_page = "home"
```
diff --git a/docs/configuration/tabbar/README.md b/docs/configuration/tabbar/README.md
new file mode 100644
index 0000000..9cdd5b4
--- /dev/null
+++ b/docs/configuration/tabbar/README.md
@@ -0,0 +1,264 @@
+# Theming the Tab-Bar
+The tab bar in the title row can be configured in various aspects.
+This page explains the tab-related configuration options and gives
+configuration examples at the end.
+
+## Elements of the Tab-Bar
+Of course, the tab-bar is composed from one or more tabs.
+Tabs are separated by a _divider_, and if there are more tabs than fit into the window,
+there will be _scroll tags_ at the beginning and at the end of the tab bar.
+The scroll tags indicate that there are more tabs and each end's scroll tag shows the number
+of tabs that did not fit into the tab-bar on that particular side.
+
+The right scroll tag is always right-aligned.
+The space between the right scroll tag and the right-most tab is filled by a "padding" segment.
+
+Furthermore, each tab, the padding segment, and the scroll tags, all have a _prefix_ and a _postfix_.
+Prefixes and postfixes are additional sub-elements that
+help to better visualize the tabs and
+allow for some more styling options.
+
+
+The following list shows an example sequence with four tabs
+that includes all the possible segments of a tab-bar.
+
+* <div style="font-family: monospace;">
+ <span style="background:#BB0505">&nbsp;[pre]&nbsp;</span>
+ <span style="background:#EE2222">&nbsp;[scroll-f]&nbsp;</span>
+ <span style="background:#BB0505">&nbsp;[post]&nbsp;</span>&nbsp;&nbsp;(left scroll tag)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#888888">&nbsp;[pre]&nbsp;</span>
+ <span style="background:#AAAAAA">&nbsp;[tab 1]&nbsp;</span>
+ <span style="background:#888888">&nbsp;[post]&nbsp;</span>&nbsp;&nbsp;(inactive tab)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#779999">&nbsp;[ii]&nbsp;</span>&nbsp;&nbsp;(divider between two inactive tabs)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#888888">&nbsp;[pre]&nbsp;</span>
+ <span style="background:#AAAAAA">&nbsp;[tab 2]&nbsp;</span>
+ <span style="background:#888888">&nbsp;[post]&nbsp;</span>&nbsp;&nbsp;(inactive tab)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#77AA77">&nbsp;[ia]&nbsp;</span>&nbsp;&nbsp;(divider before active tab)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#8888BB">&nbsp;[pre]&nbsp;</span>
+ <span style="background:#9090F0">&nbsp;[tab 3]&nbsp;</span>
+ <span style="background:#8888BB">&nbsp;[post]&nbsp;</span>&nbsp;&nbsp;(active tab)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#77AA77">&nbsp;[ai]&nbsp;</span>&nbsp;&nbsp;(divider after active tab)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#888888">&nbsp;[pre]&nbsp;</span>
+ <span style="background:#AAAAAA"> tab 4</span>
+ <span style="background:#888888">&nbsp;[post]&nbsp;</span>&nbsp;&nbsp;(inactive tab)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#CCBB55">&nbsp;[pre]&nbsp;</span>
+ <span style="background:#EEDD99">&nbsp;[pad]&nbsp;</span>
+ <span style="background:#CCBB55">&nbsp;[post]&nbsp;</span>&nbsp;&nbsp;(padding)
+ </div>
+* <div style="font-family: monospace;">
+ <span style="background:#BB0505">&nbsp;[pre]&nbsp;</span>
+ <span style="background:#EE2222">&nbsp;[scroll-b]&nbsp;</span>
+ <span style="background:#BB0505">&nbsp;[post]&nbsp;</span>&nbsp;&nbsp;(right scroll tag)
+
+<!--
+<pre>
+<span style="background:#BB0505"> pre </span>
+<span style="background:#EE2222"> scroll-f </span>
+<span style="background:#BB0505"> post </span>
+<span style="background:#888888"> pre </span>
+<span style="background:#AAAAAA"> tab 1 </span>
+<span style="background:#888888"> post </span>
+<span style="background:#779999"> ii </span>
+<span style="background:#888888"> pre </span>
+<span style="background:#AAAAAA"> tab 2 </span>
+<span style="background:#888888"> post </span>
+<span style="background:#77AA77"> ia </span>
+<span style="background:#8888BB"> pre </span>
+<span style="background:#9090F0"> tab 3 </span>
+<span style="background:#8888BB"> post </span>
+<span style="background:#77AA77"> ai </span>
+<span style="background:#888888"> pre </span>
+<span style="background:#AAAAAA"> tab 4</span>
+<span style="background:#888888"> post </span>
+<span style="background:#CCBB55"> pre </span>
+<span style="background:#EEDD99"> pad </span>
+<span style="background:#CCBB55"> post </span>
+<span style="background:#BB0505"> pre </span>
+<span style="background:#EE2222"> scroll-b </span>
+<span style="background:#BB0505"> post </span>
+</pre>
+-->
+
+## Configuring the Characters
+Characters for prefixes, postfixes and some other elements can be configured under a `[tabs.chars]`
+section.
+This is a complete example for the configuration of the default values:
+```toml
+[tabs.chars]
+active_prefix = " "
+active_postfix = " "
+inactive_prefix = "["
+inactive_postfix = "]"
+divider = " "
+scroll_front_prefix = ""
+scroll_front_postfix = ""
+scroll_front_prestring = "«"
+scroll_front_poststring = " "
+scroll_back_prefix = ""
+scroll_back_postfix = ""
+scroll_back_prestring = " "
+scroll_back_poststring = "»"
+padding_prefix = " "
+padding_postfix = " "
+padding_fill = " "
+```
+Be aware that all elements for the padding segment are chars and can't be of zero length
+or `None`, while the other pre- and postfixes are strings and can also be an empty string.
+
+Further note that the scroll tags also have a `prestring` and `poststring`,
+which are strings shown before and after the number in the scroll tag but are still part of the
+tag's "body". While the pre- and postfix can have a separate font style (e.g. color),
+the pre- and post-string are styled just as the number.
+
+## Configuring Styles (Colors and Font Styles)
+Each element of the tab-bar can be configured with a separate style.
+The divider can even be configured with three different styles,
+one for dividers between two inactive tabs (`divider_ii`),
+one for the divider before the active tab (`divider_ia`),
+and one for the divider after the active tab (`divider_ai`).
+
+All styles are sub-elements of `[tabs.styles]`.
+
+To ease configuration, most styles are derived from another style and one only
+has to specify the deviation.
+
+The following image visualizes all styles and how they are derived from others.
+
+```mermaid
+classDiagram
+ direction LR
+
+ active <|-- prefix_active
+ prefix_active <|-- postfix_active
+
+ inactive <|-- prefix_inactive
+ prefix_inactive <|-- postfix_inactive
+
+ divider_ii <|-- divider_ia
+ divider_ia <|-- divider_ai
+
+ scroll_front <|-- scroll_front_prefix
+ scroll_front_prefix <|-- scroll_front_postfix
+
+ scroll_back <|-- scroll_back_prefix
+ scroll_back_prefix <|-- scroll_back_postfix
+
+ padding_fill <|-- padding_prefix
+ padding_prefix <|-- padding_postfix
+```
+The left-most styles in the diagram are basic styles which are not
+derived from another style.
+The default configuration uses these:
+
+```toml
+[tabs.styles]
+
+[tabs.styles.active]
+bg = "light_blue"
+fg = "black"
+bold = true
+
+[tabs.styles.scroll_front]
+fg = "yellow"
+bold = true
+
+[tabs.styles.scroll_back]
+fg = "yellow"
+bold = true
+```
+
+The remaining base styles use the terminal default background and foreground.
+The derived styles are all empty by default and therewith equal to their "root-style".
+
+Hint: If one changes even only one attribute of one of the base styles, the default
+is not used anymore. For example, if only `[tabs.styles.active.bg]` is set in
+`theme.toml`, the two other defaults (`fg` and `bold`) are not used anymore
+from the default configuration and need to be specified explicitly if wanted.
+If they are specified, they will fall back to the terminal default style.
+
+## Examples
+
+### Rounded Tabs with Arrow-like Scroll Tags
+This styling requires a **nerdfont** being used by the terminal.
+
+![Fancy Tab-Bar with Nerdfont](nerdfont_bar_1.png)
+
+This is the configuration that can be copied to `theme.toml`:
+```toml
+[tabs]
+
+[tabs.chars]
+divider = " "
+active_prefix = ""
+active_postfix = ""
+inactive_prefix = ""
+inactive_postfix = ""
+scroll_front_prefix = ""
+scroll_front_postfix = ""
+scroll_front_prestring = ""
+scroll_front_poststring = " "
+scroll_back_prefix = ""
+scroll_back_postfix = ""
+scroll_back_prestring = " "
+scroll_back_poststring = ""
+
+[tabs.styles]
+
+[tabs.styles.active]
+fg = "black"
+bg = "light_blue"
+bold = true
+
+[tabs.styles.active_prefix]
+fg = "light_blue"
+bg = "reset"
+
+[tabs.styles.inactive]
+fg = "black"
+bg = "gray"
+
+[tabs.styles.inactive_prefix]
+fg = "gray"
+bg = "reset"
+
+[tabs.styles.scroll_front]
+fg = "black"
+bg = "yellow"
+bold = true
+
+[tabs.styles.scroll_front_prefix]
+fg = "yellow"
+bg = "reset"
+
+[tabs.styles.scroll_front_postfix]
+invert = true
+
+[tabs.styles.scroll_back]
+fg = "black"
+bg = "yellow"
+bold = true
+
+[tabs.styles.scroll_back_prefix]
+fg = "yellow"
+bg = "reset"
+invert = true
+
+[tabs.styles.scroll_back_postfix]
+invert = false
+```
diff --git a/docs/configuration/tabbar/nerdfont_bar_1.png b/docs/configuration/tabbar/nerdfont_bar_1.png
new file mode 100644
index 0000000..8c7fb77
--- /dev/null
+++ b/docs/configuration/tabbar/nerdfont_bar_1.png
Binary files differ
diff --git a/docs/configuration/theme.toml.md b/docs/configuration/theme.toml.md
index e946be6..f428034 100644
--- a/docs/configuration/theme.toml.md
+++ b/docs/configuration/theme.toml.md
@@ -61,3 +61,5 @@ a specific style that overrides the former file-type-styles.
Last but not least, there are styles for _selected_ files which override all the former
styles.
+## Theming the Tab-Bar
+Theming of the tab-bar is described [here](tabbar/README.md).
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index fb45e79..8b56f5a 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -40,7 +40,6 @@ pub mod show_tasks;
pub mod sort;
pub mod sub_process;
pub mod subdir_fzf;
-pub mod tab_bar_mode;
pub mod tab_ops;
pub mod touch_file;
pub mod uimodes;
diff --git a/src/commands/tab_bar_mode.rs b/src/commands/tab_bar_mode.rs
deleted file mode 100644
index e292aac..0000000
--- a/src/commands/tab_bar_mode.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use crate::config::clean::app::tab::TabBarDisplayMode;
-use crate::context::AppContext;
-use crate::error::AppResult;
-
-pub fn set_tab_bar_display_mode(
- context: &mut AppContext,
- mode: &TabBarDisplayMode,
-) -> AppResult<()> {
- context.tab_context_mut().display.mode = *mode;
- Ok(())
-}
diff --git a/src/config/clean/app/display/config.rs b/src/config/clean/app/display/config.rs
index 4bf64de..1f8e51f 100644
--- a/src/config/clean/app/display/config.rs
+++ b/src/config/clean/app/display/config.rs
@@ -26,7 +26,6 @@ pub struct DisplayOption {
pub _show_borders: bool,
pub _show_hidden: bool,
pub _show_icons: bool,
- pub _tilde_in_titlebar: bool,
pub _line_nums: LineNumberStyle,
pub column_ratio: (usize, usize, usize),
pub default_layout: [Constraint; 3],
@@ -71,7 +70,6 @@ impl From<DisplayOptionRaw> for DisplayOption {
_show_borders: raw.show_borders,
_show_hidden: raw.show_hidden,
_show_icons: raw.show_icons,
- _tilde_in_titlebar: raw.tilde_in_titlebar,
_line_nums,
column_ratio,
@@ -120,10 +118,6 @@ impl DisplayOption {
self._show_hidden = show_hidden;
}
- pub fn tilde_in_titlebar(&self) -> bool {
- self._tilde_in_titlebar
- }
-
pub fn line_nums(&self) -> LineNumberStyle {
self._line_nums
}
@@ -164,7 +158,6 @@ impl std::default::Default for DisplayOption {
_show_borders: true,
_show_hidden: false,
_show_icons: false,
- _tilde_in_titlebar: true,
_line_nums: LineNumberStyle::None,
default_layout,
no_preview_layout,
diff --git a/src/config/clean/app/tab/config.rs b/src/config/clean/app/tab/config.rs
index 86e156f..d724e9a 100644
--- a/src/config/clean/app/tab/config.rs
+++ b/src/config/clean/app/tab/config.rs
@@ -1,28 +1,13 @@
-use std::str::FromStr;
-
-use serde::Deserialize;
-
-use crate::{
- config::raw::app::display::tab::TabOptionRaw,
- error::{AppError, AppErrorKind},
- tab::TabHomePage,
-};
+use crate::{config::raw::app::display::tab::TabOptionRaw, tab::TabHomePage};
#[derive(Clone, Debug)]
pub struct TabOption {
pub _home_page: TabHomePage,
- pub display: TabBarDisplayOption,
}
impl TabOption {
- pub fn new(_home_page: TabHomePage, display_mode: TabBarDisplayMode, max_len: usize) -> Self {
- Self {
- _home_page,
- display: TabBarDisplayOption {
- mode: display_mode,
- max_len,
- },
- }
+ pub fn new(_home_page: TabHomePage) -> Self {
+ Self { _home_page }
}
pub fn home_page(&self) -> TabHomePage {
self._home_page
@@ -33,7 +18,6 @@ impl std::default::Default for TabOption {
fn default() -> Self {
Self {
_home_page: TabHomePage::Home,
- display: TabBarDisplayOption::default(),
}
}
}
@@ -42,48 +26,6 @@ impl From<TabOptionRaw> for TabOption {
fn from(raw: TabOptionRaw) -> Self {
let home_page = TabHomePage::from_str(raw.home_page.as_str()).unwrap_or(TabHomePage::Home);
- Self::new(home_page, raw.display_mode, raw.max_len)
- }
-}
-
-#[derive(Clone, Copy, Debug)]
-pub struct TabBarDisplayOption {
- pub mode: TabBarDisplayMode,
- pub max_len: usize,
-}
-
-impl Default for TabBarDisplayOption {
- fn default() -> Self {
- Self {
- mode: Default::default(),
- max_len: 16,
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, Deserialize, Default)]
-pub enum TabBarDisplayMode {
- #[serde(rename = "num")]
- Number,
- #[default]
- #[serde(rename = "dir")]
- Directory,
- #[serde(rename = "all")]
- All,
-}
-
-impl FromStr for TabBarDisplayMode {
- type Err = AppError;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "num" => Ok(Self::Number),
- "dir" => Ok(Self::Directory),
- "all" => Ok(Self::All),
- s => Err(AppError::new(
- AppErrorKind::UnrecognizedArgument,
- format!("tab_bar_mode: `{}` unknown argument.", s),
- )),
- }
+ Self::new(home_page)
}
}
diff --git a/src/config/clean/theme/tab.rs b/src/config/clean/theme/tab.rs
index 6a4a901..f8cf256 100644
--- a/src/config/clean/theme/tab.rs
+++ b/src/config/clean/theme/tab.rs
@@ -1,17 +1,198 @@
-use crate::config::raw::theme::tab::TabThemeRaw;
-
-use super::style::AppStyle;
+use crate::config::raw::theme::tab::{TabThemeCharsRaw, TabThemeColorRaw, TabThemeRaw};
+use crate::util::style::PathStyleIfSome;
+use ratatui::style::{Color, Modifier, Style};
+use unicode_width::UnicodeWidthStr;
#[derive(Clone, Debug)]
pub struct TabTheme {
- pub inactive: AppStyle,
- pub active: AppStyle,
+ pub styles: TabThemeColors,
+ pub chars: TabThemeChars,
+ pub inference: TabThemeCharsInference,
}
impl From<TabThemeRaw> for TabTheme {
fn from(crude: TabThemeRaw) -> Self {
- let inactive = crude.inactive.to_style_theme();
- let active = crude.active.to_style_theme();
- Self { inactive, active }
+ let chars = TabThemeChars::from(crude.chars);
+ Self {
+ styles: TabThemeColors::from(crude.styles),
+ inference: TabThemeCharsInference::from_chars(&chars),
+ chars,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct TabThemeChars {
+ pub divider: String,
+ pub prefix_i: String,
+ pub postfix_i: String,
+ pub prefix_a: String,
+ pub postfix_a: String,
+ pub scroll_front_prefix: String,
+ pub scroll_front_postfix: String,
+ pub scroll_front_prestring: String,
+ pub scroll_front_poststring: String,
+ pub scroll_back_prefix: String,
+ pub scroll_back_postfix: String,
+ pub scroll_back_prestring: String,
+ pub scroll_back_poststring: String,
+ pub padding_prefix: char,
+ pub padding_postfix: char,
+ pub padding_fill: char,
+}
+
+impl From<TabThemeCharsRaw> for TabThemeChars {
+ fn from(crude: TabThemeCharsRaw) -> Self {
+ Self {
+ divider: crude.divider.unwrap_or(" ".to_string()),
+ prefix_i: crude.inactive_prefix.unwrap_or("[".to_string()),
+ postfix_i: crude.inactive_postfix.unwrap_or("]".to_string()),
+ prefix_a: crude.active_prefix.unwrap_or(" ".to_string()),
+ postfix_a: crude.active_postfix.unwrap_or(" ".to_string()),
+ scroll_front_prefix: crude.scroll_front_prefix.unwrap_or("".to_string()),
+ scroll_front_postfix: crude.scroll_front_postfix.unwrap_or("".to_string()),
+ scroll_front_prestring: crude.scroll_front_prestring.unwrap_or("«".to_string()),
+ scroll_front_poststring: crude.scroll_front_poststring.unwrap_or(" ".to_string()),
+ scroll_back_prefix: crude.scroll_back_prefix.unwrap_or("".to_string()),
+ scroll_back_postfix: crude.scroll_back_postfix.unwrap_or("".to_string()),
+ scroll_back_prestring: crude.scroll_back_prestring.unwrap_or(" ".to_string()),
+ scroll_back_poststring: crude.scroll_back_poststring.unwrap_or("»".to_string()),
+ padding_prefix: crude.padding_prefix.unwrap_or(' '),
+ padding_postfix: crude.padding_postfix.unwrap_or(' '),
+ padding_fill: crude.padding_fill.unwrap_or(' '),
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct TabThemeCharsInference {
+ pub tab_divider_length: usize,
+ pub tab_prefix_i_length: usize,
+ pub tab_postfix_i_length: usize,
+ pub tab_prefix_a_length: usize,
+ pub tab_postfix_a_length: usize,
+ pub scroll_front_static_length: usize,
+ pub scroll_back_static_length: usize,
+ pub active_tab_extra_width: usize,
+ pub inactive_tab_extra_width: usize,
+}
+
+impl TabThemeCharsInference {
+ fn from_chars(chars: &TabThemeChars) -> Self {
+ Self {
+ tab_divider_length: chars.divider.width(),
+ tab_prefix_i_length: chars.prefix_i.width(),
+ tab_prefix_a_length: chars.prefix_a.width(),
+ tab_postfix_i_length: chars.postfix_i.width(),
+ tab_postfix_a_length: chars.postfix_a.width(),
+ scroll_front_static_length: chars.scroll_front_prefix.width()
+ + chars.scroll_front_postfix.width()
+ + chars.scroll_front_prestring.width()
+ + chars.scroll_front_poststring.width(),
+ scroll_back_static_length: chars.scroll_back_prefix.width()
+ + chars.scroll_back_postfix.width()
+ + chars.scroll_back_prestring.width()
+ + chars.scroll_back_poststring.width(),
+ active_tab_extra_width: chars.prefix_a.width() + chars.postfix_a.width(),
+ inactive_tab_extra_width: chars.prefix_i.width() + chars.postfix_i.width(),
+ }
+ }
+
+ pub fn calc_scroll_tags_width(&self, num_tabs: usize) -> usize {
+ let max_num_width = num_tabs.checked_ilog10().unwrap_or(0) as usize + 1;
+ 2 * max_num_width + self.scroll_front_static_length + self.scroll_back_static_length
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct TabThemeColors {
+ pub prefix_a: Style,
+ pub postfix_a: Style,
+ pub tab_a: Style,
+ pub prefix_i: Style,
+ pub postfix_i: Style,
+ pub tab_i: Style,
+ pub divider_ii: Style,
+ pub divider_ia: Style,
+ pub divider_ai: Style,
+ pub scroll_front_prefix: Style,
+ pub scroll_front_postfix: Style,
+ pub scroll_front: Style,
+ pub scroll_back_prefix: Style,
+ pub scroll_back_postfix: Style,
+ pub scroll_back: Style,
+ pub padding_prefix: Style,
+ pub padding_postfix: Style,
+ pub padding_fill: Style,
+}
+
+impl From<TabThemeColorRaw> for TabThemeColors {
+ fn from(crude: TabThemeColorRaw) -> Self {
+ let tab_a = crude.active.map(|s| s.as_style()).unwrap_or(
+ Style::new()
+ .bg(Color::LightBlue)
+ .fg(Color::Black)
+ .add_modifier(Modifier::BOLD),
+ );
+ let prefix_a = tab_a.patch_optionally(crude.active_prefix.map(|s| s.as_style()));
+ let postfix_a = prefix_a.patch_optionally(crude.active_postfix.map(|s| s.as_style()));
+
+ let tab_i = crude.inactive.map(|s| s.as_style()).unwrap_or(Style::new());
+ let prefix_i = tab_i.patch_optionally(crude.inactive_prefix.map(|s| s.as_style()));
+ let postfix_i = prefix_i.patch_optionally(crude.inactive_postfix.map(|s| s.as_style()));
+
+ let divider_ii = crude
+ .divider_ii
+ .map(|s| s.as_style())
+ .unwrap_or(Style::new());
+ let divider_ia = divider_ii.patch_optionally(crude.divider_ia.map(|s| s.as_style()));
+ let divider_ai = divider_ia.patch_optionally(crude.divider_ai.map(|s| s.as_style()));
+
+ let scroll_front = crude
+ .scroll_front
+ .map(|s| s.as_style())
+ .unwrap_or(Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD));
+ let scroll_front_prefix =
+ scroll_front.patch_optionally(crude.scroll_front_prefix.map(|s| s.as_style()));
+ let scroll_front_postfix =
+ scroll_front_prefix.patch_optionally(crude.scroll_front_postfix.map(|s| s.as_style()));
+
+ let scroll_back = crude
+ .scroll_back
+ .map(|s| s.as_style())
+ .unwrap_or(Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD));
+ let scroll_back_prefix =
+ scroll_back.patch_optionally(crude.scroll_back_prefix.map(|s| s.as_style()));
+ let scroll_back_postfix =
+ scroll_back_prefix.patch_optionally(crude.scroll_back_postfix.map(|s| s.as_style()));
+
+ let padding_fill = crude
+ .padding_fill
+ .map(|s| s.as_style())
+ .unwrap_or(Style::new());
+ let padding_prefix =
+ padding_fill.patch_optionally(crude.padding_prefix.map(|s| s.as_style()));
+ let padding_postfix =
+ padding_prefix.patch_optionally(crude.padding_postfix.map(|s| s.as_style()));
+ Self {
+ prefix_a,
+ postfix_a,
+ tab_a,
+ pr