listing: add relative_list_indices setting for thread listing

pull/260/head
Manos Pitsidianakis 2023-07-16 14:13:55 +03:00
parent 8abc9358a7
commit 561ba9c87b
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
5 changed files with 102 additions and 14 deletions

View File

@ -48,6 +48,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Warn if draft has no subject and no body.
They can be disabled with `[composing.disabled_compose_hooks]` setting.
- `e9cd800f` Added support for storing flags locally for NNTP accounts.
- Added options to show relative row numbers in menus and listings to make jumping easier.
`[listing.relative_menu_indices]` and `[listing.relative_list_indices]`.
### Changed

View File

@ -1145,6 +1145,12 @@ Should threads with differentiating Subjects show a list of those subjects on th
In threaded listing style, repeat identical From column values within a thread.
Not repeating adds empty space in the From column which might result in less visual clutter.
.Pq Em "false" \" default value
.It Ic relative_menu_indices Ar bool
Show relative indices in menu mailboxes to quickly help with jumping to them.
.Pq Em true \" default value
.It Ic relative_list_indices Ar bool
Show relative indices in listings to quickly help with jumping to them.
.Pq Em true \" default value
.El
.Ss Examples of sidebar mailbox tree customization
The default values

View File

@ -529,6 +529,9 @@ impl ListingTrait for ThreadListing {
if self.cursor_pos.2 != self.new_cursor_pos.2 && prev_page_no == page_no {
let old_cursor_pos = self.cursor_pos;
self.cursor_pos = self.new_cursor_pos;
if *account_settings!(context[self.cursor_pos.0].listing.relative_list_indices) {
self.draw_relative_numbers(grid, area, top_idx);
}
for &(idx, highlight) in &[(old_cursor_pos.2, false), (self.new_cursor_pos.2, true)] {
if idx >= self.length {
continue; //bounds check
@ -544,6 +547,9 @@ impl ListingTrait for ThreadListing {
}
context.dirty_areas.push_back(new_area);
}
if *account_settings!(context[self.cursor_pos.0].listing.relative_list_indices) {
context.dirty_areas.push_back(area);
}
if !self.force_draw {
return;
}
@ -569,6 +575,9 @@ impl ListingTrait for ThreadListing {
/* copy table columns */
self.data_columns
.draw(grid, top_idx, self.cursor_pos.2, grid.bounds_iter(area));
if *account_settings!(context[self.cursor_pos.0].listing.relative_list_indices) {
self.draw_relative_numbers(grid, area, top_idx);
}
/* apply each row colors separately */
for i in top_idx..(top_idx + height!(area)) {
if let Some(row_attr) = self.rows.row_attr_cache.get(&i) {
@ -907,19 +916,21 @@ impl ThreadListing {
panic!();
}
let row_attr = self.rows.row_attr_cache[&idx];
let (x, _) = write_string_to_grid(
&idx.to_string(),
&mut self.data_columns.columns[0],
row_attr.fg,
row_attr.bg,
row_attr.attrs,
((0, idx), (min_width.0, idx)),
None,
);
for x in x..min_width.0 {
self.data_columns.columns[0][(x, idx)]
.set_bg(row_attr.bg)
.set_attrs(row_attr.attrs);
if !*account_settings!(context[self.cursor_pos.0].listing.relative_list_indices) {
let (x, _) = write_string_to_grid(
&idx.to_string(),
&mut self.data_columns.columns[0],
row_attr.fg,
row_attr.bg,
row_attr.attrs,
((0, idx), (min_width.0, idx)),
None,
);
for x in x..min_width.0 {
self.data_columns.columns[0][(x, idx)]
.set_bg(row_attr.bg)
.set_attrs(row_attr.attrs);
}
}
let (x, _) = write_string_to_grid(
&strings.date,
@ -1072,6 +1083,67 @@ impl ThreadListing {
*self.rows.entries.get_mut(idx).unwrap() = ((thread_hash, env_hash), strings);
}
fn draw_relative_numbers(&mut self, grid: &mut CellBuffer, area: Area, top_idx: usize) {
let width = self.data_columns.columns[0].size().0;
let upper_left = upper_left!(area);
for i in 0..height!(area) {
let row_attr = row_attr!(self.color_cache, (top_idx + i) % 2 == 0, false, true, false);
clear_area(
&mut self.data_columns.columns[0],
((0, i), (width - 1, i + 1)),
row_attr,
);
clear_area(
grid,
(
pos_inc(upper_left, (0, i)),
pos_inc(upper_left, (width - 1, i + 1)),
),
row_attr,
);
let (x, _) = write_string_to_grid(
&if self.new_cursor_pos.2.saturating_sub(top_idx) == i {
self.new_cursor_pos.2.to_string()
} else {
(i as isize - (self.new_cursor_pos.2 - top_idx) as isize)
.abs()
.to_string()
},
&mut self.data_columns.columns[0],
row_attr.fg,
row_attr.bg,
row_attr.attrs,
((0, i), (width, i + 1)),
None,
);
for x in x..width {
self.data_columns.columns[0][(x, i)]
.set_ch(' ')
.set_bg(row_attr.bg)
.set_attrs(row_attr.attrs);
}
_ = write_string_to_grid(
&if self.new_cursor_pos.2.saturating_sub(top_idx) == i {
self.new_cursor_pos.2.to_string()
} else {
(i as isize - (self.new_cursor_pos.2 - top_idx) as isize)
.abs()
.to_string()
},
grid,
row_attr.fg,
row_attr.bg,
row_attr.attrs,
(
pos_inc(upper_left, (0, i)),
pos_inc(upper_left, (width, i + 1)),
),
None,
);
}
}
}
impl Component for ThreadListing {

View File

@ -147,6 +147,11 @@ pub struct ListingSettings {
/// them. Default: "true"
#[serde(default = "true_val", alias = "relative-menu-indices")]
pub relative_menu_indices: bool,
/// Show relative indices in listings to quickly help with jumping to
/// them. Default: "true"
#[serde(default = "true_val", alias = "relative-list-indices")]
pub relative_list_indices: bool,
}
const fn default_divider() -> char {
@ -179,6 +184,7 @@ impl Default for ListingSettings {
thread_subject_pack: true,
threaded_repeat_identical_from_values: false,
relative_menu_indices: true,
relative_list_indices: true,
}
}
}
@ -218,6 +224,7 @@ impl DotAddressable for ListingSettings {
.threaded_repeat_identical_from_values
.lookup(field, tail),
"relative_menu_indices" => self.relative_menu_indices.lookup(field, tail),
"relative_list_indices" => self.relative_list_indices.lookup(field, tail),
other => Err(Error::new(format!(
"{} has no field named {}",
parent_field, other

View File

@ -29,7 +29,7 @@ use melib::HeaderName;
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct PagerSettingsOverride { # [doc = " Number of context lines when going to next page."] # [doc = " Default: 0"] # [serde (alias = "pager-context")] # [serde (default)] pub pager_context : Option < usize > , # [doc = " Stop at the end instead of displaying next mail."] # [doc = " Default: false"] # [serde (alias = "pager-stop")] # [serde (default)] pub pager_stop : Option < bool > , # [doc = " Always show headers when scrolling."] # [doc = " Default: true"] # [serde (alias = "sticky-headers" , alias = "headers-sticky" , alias = "headers_sticky")] # [serde (default)] pub sticky_headers : Option < bool > , # [doc = " The height of the pager in mail view, in percent."] # [doc = " Default: 80"] # [serde (alias = "pager-ratio")] # [serde (default)] pub pager_ratio : Option < usize > , # [doc = " A command to pipe mail output through for viewing in pager."] # [doc = " Default: None"] # [serde (deserialize_with = "non_empty_opt_string")] # [serde (default)] pub filter : Option < Option < String > > , # [doc = " A command to pipe html output before displaying it in a pager"] # [doc = " Default: None"] # [serde (deserialize_with = "non_empty_opt_string" , alias = "html-filter")] # [serde (default)] pub html_filter : Option < Option < String > > , # [doc = " Respect \"format=flowed\""] # [doc = " Default: true"] # [serde (alias = "format-flowed")] # [serde (default)] pub format_flowed : Option < bool > , # [doc = " Split long lines that would overflow on the x axis."] # [doc = " Default: true"] # [serde (alias = "split-long-lines")] # [serde (default)] pub split_long_lines : Option < bool > , # [doc = " Minimum text width in columns."] # [doc = " Default: 80"] # [serde (alias = "minimum-width")] # [serde (default)] pub minimum_width : Option < usize > , # [doc = " Choose `text/html` alternative if `text/plain` is empty in"] # [doc = " `multipart/alternative` attachments."] # [doc = " Default: true"] # [serde (alias = "auto-choose-multipart-alternative")] # [serde (default)] pub auto_choose_multipart_alternative : Option < ToggleFlag > , # [doc = " Show Date: in my timezone"] # [doc = " Default: true"] # [serde (alias = "show-date-in-my-timezone")] # [serde (default)] pub show_date_in_my_timezone : Option < ToggleFlag > , # [doc = " A command to launch URLs with. The URL will be given as the first"] # [doc = " argument of the command. Default: None"] # [serde (deserialize_with = "non_empty_opt_string")] # [serde (default)] pub url_launcher : Option < Option < String > > , # [doc = " A command to open html files."] # [doc = " Default: None"] # [serde (deserialize_with = "non_empty_opt_string" , alias = "html-open")] # [serde (default)] pub html_open : Option < Option < String > > , # [doc = " Extra headers to display, if present, in the default header preamble."] # [doc = " Default: []"] # [serde (alias = "show-extra-headers")] # [serde (default)] pub show_extra_headers : Option < Vec < String > > } impl Default for PagerSettingsOverride { fn default () -> Self { PagerSettingsOverride { pager_context : None , pager_stop : None , sticky_headers : None , pager_ratio : None , filter : None , html_filter : None , format_flowed : None , split_long_lines : None , minimum_width : None , auto_choose_multipart_alternative : None , show_date_in_my_timezone : None , url_launcher : None , html_open : None , show_extra_headers : None } } }
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct ListingSettingsOverride { # [doc = " Number of context lines when going to next page."] # [doc = " Default: 0"] # [serde (alias = "context-lines")] # [serde (default)] pub context_lines : Option < usize > , # [doc = " Show auto-hiding scrollbar in accounts sidebar menu."] # [doc = " Default: True"] # [serde (default)] pub show_menu_scrollbar : Option < bool > , # [doc = " Datetime formatting passed verbatim to strftime(3)."] # [doc = " Default: %Y-%m-%d %T"] # [serde (alias = "datetime-fmt")] # [serde (default)] pub datetime_fmt : Option < Option < String > > , # [doc = " Show recent dates as `X {minutes,hours,days} ago`, up to 7 days."] # [doc = " Default: true"] # [serde (alias = "recent-dates")] # [serde (default)] pub recent_dates : Option < bool > , # [doc = " Show only envelopes that match this query"] # [doc = " Default: None"] # [serde (default)] pub filter : Option < Option < Query > > , # [serde (alias = "index-style")] # [serde (default)] pub index_style : Option < IndexStyle > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_has_sibling : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_no_sibling : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_has_sibling_leaf : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_no_sibling_leaf : Option < Option < String > > , # [doc = " Default: ' '"] # [serde (default)] pub sidebar_divider : Option < char > , # [doc = " Default: 90"] # [serde (default)] pub sidebar_ratio : Option < usize > , # [doc = " Flag to show if thread entry contains unseen mail."] # [doc = " Default: \"●\""] # [serde (default)] pub unseen_flag : Option < Option < String > > , # [doc = " Flag to show if thread has been snoozed."] # [doc = " Default: \"πŸ’€\""] # [serde (default)] pub thread_snoozed_flag : Option < Option < String > > , # [doc = " Flag to show if thread entry has been selected."] # [doc = " Default: \"β˜‘\u{fe0f}\""] # [serde (default)] pub selected_flag : Option < Option < String > > , # [doc = " Flag to show if thread entry contains attachments."] # [doc = " Default: \"πŸ“Ž\""] # [serde (default)] pub attachment_flag : Option < Option < String > > , # [doc = " Should threads with different Subjects show a list of those"] # [doc = " subjects on the entry title?"] # [doc = " Default: \"true\""] # [serde (default)] pub thread_subject_pack : Option < bool > , # [doc = " In threaded listing style, repeat identical From column values within a"] # [doc = " thread. Not repeating adds empty space in the From column which"] # [doc = " might result in less visual clutter."] # [doc = " Default: \"false\""] # [serde (default)] pub threaded_repeat_identical_from_values : Option < bool > , # [doc = " Show relative indices in menu mailboxes to quickly help with jumping to"] # [doc = " them. Default: \"true\""] # [serde (alias = "relative-menu-indices")] # [serde (default)] pub relative_menu_indices : Option < bool > } impl Default for ListingSettingsOverride { fn default () -> Self { ListingSettingsOverride { context_lines : None , show_menu_scrollbar : None , datetime_fmt : None , recent_dates : None , filter : None , index_style : None , sidebar_mailbox_tree_has_sibling : None , sidebar_mailbox_tree_no_sibling : None , sidebar_mailbox_tree_has_sibling_leaf : None , sidebar_mailbox_tree_no_sibling_leaf : None , sidebar_divider : None , sidebar_ratio : None , unseen_flag : None , thread_snoozed_flag : None , selected_flag : None , attachment_flag : None , thread_subject_pack : None , threaded_repeat_identical_from_values : None , relative_menu_indices : None } } }
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct ListingSettingsOverride { # [doc = " Number of context lines when going to next page."] # [doc = " Default: 0"] # [serde (alias = "context-lines")] # [serde (default)] pub context_lines : Option < usize > , # [doc = " Show auto-hiding scrollbar in accounts sidebar menu."] # [doc = " Default: True"] # [serde (default)] pub show_menu_scrollbar : Option < bool > , # [doc = " Datetime formatting passed verbatim to strftime(3)."] # [doc = " Default: %Y-%m-%d %T"] # [serde (alias = "datetime-fmt")] # [serde (default)] pub datetime_fmt : Option < Option < String > > , # [doc = " Show recent dates as `X {minutes,hours,days} ago`, up to 7 days."] # [doc = " Default: true"] # [serde (alias = "recent-dates")] # [serde (default)] pub recent_dates : Option < bool > , # [doc = " Show only envelopes that match this query"] # [doc = " Default: None"] # [serde (default)] pub filter : Option < Option < Query > > , # [serde (alias = "index-style")] # [serde (default)] pub index_style : Option < IndexStyle > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_has_sibling : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_no_sibling : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_has_sibling_leaf : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_no_sibling_leaf : Option < Option < String > > , # [doc = " Default: ' '"] # [serde (default)] pub sidebar_divider : Option < char > , # [doc = " Default: 90"] # [serde (default)] pub sidebar_ratio : Option < usize > , # [doc = " Flag to show if thread entry contains unseen mail."] # [doc = " Default: \"●\""] # [serde (default)] pub unseen_flag : Option < Option < String > > , # [doc = " Flag to show if thread has been snoozed."] # [doc = " Default: \"πŸ’€\""] # [serde (default)] pub thread_snoozed_flag : Option < Option < String > > , # [doc = " Flag to show if thread entry has been selected."] # [doc = " Default: \"β˜‘\u{fe0f}\""] # [serde (default)] pub selected_flag : Option < Option < String > > , # [doc = " Flag to show if thread entry contains attachments."] # [doc = " Default: \"πŸ“Ž\""] # [serde (default)] pub attachment_flag : Option < Option < String > > , # [doc = " Should threads with different Subjects show a list of those"] # [doc = " subjects on the entry title?"] # [doc = " Default: \"true\""] # [serde (default)] pub thread_subject_pack : Option < bool > , # [doc = " In threaded listing style, repeat identical From column values within a"] # [doc = " thread. Not repeating adds empty space in the From column which"] # [doc = " might result in less visual clutter."] # [doc = " Default: \"false\""] # [serde (default)] pub threaded_repeat_identical_from_values : Option < bool > , # [doc = " Show relative indices in menu mailboxes to quickly help with jumping to"] # [doc = " them. Default: \"true\""] # [serde (alias = "relative-menu-indices")] # [serde (default)] pub relative_menu_indices : Option < bool > , # [doc = " Show relative indices in listings to quickly help with jumping to"] # [doc = " them. Default: \"true\""] # [serde (alias = "relative-list-indices")] # [serde (default)] pub relative_list_indices : Option < bool > } impl Default for ListingSettingsOverride { fn default () -> Self { ListingSettingsOverride { context_lines : None , show_menu_scrollbar : None , datetime_fmt : None , recent_dates : None , filter : None , index_style : None , sidebar_mailbox_tree_has_sibling : None , sidebar_mailbox_tree_no_sibling : None , sidebar_mailbox_tree_has_sibling_leaf : None , sidebar_mailbox_tree_no_sibling_leaf : None , sidebar_divider : None , sidebar_ratio : None , unseen_flag : None , thread_snoozed_flag : None , selected_flag : None , attachment_flag : None , thread_subject_pack : None , threaded_repeat_identical_from_values : None , relative_menu_indices : None , relative_list_indices : None } } }
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct NotificationsSettingsOverride { # [doc = " Enable notifications."] # [doc = " Default: True"] # [serde (default)] pub enable : Option < bool > , # [doc = " A command to pipe notifications through."] # [doc = " Default: None"] # [serde (default)] pub script : Option < Option < String > > , # [doc = " A command to pipe new mail notifications through (preferred over"] # [doc = " `script`). Default: None"] # [serde (default)] pub new_mail_script : Option < Option < String > > , # [doc = " A file location which has its size changed when new mail arrives (max"] # [doc = " 128 bytes). Can be used to trigger new mail notifications eg with"] # [doc = " `xbiff(1)`. Default: None"] # [serde (alias = "xbiff-file-path")] # [serde (default)] pub xbiff_file_path : Option < Option < String > > , # [serde (alias = "play-sound")] # [serde (default)] pub play_sound : Option < ToggleFlag > , # [serde (alias = "sound-file")] # [serde (default)] pub sound_file : Option < Option < String > > } impl Default for NotificationsSettingsOverride { fn default () -> Self { NotificationsSettingsOverride { enable : None , script : None , new_mail_script : None , xbiff_file_path : None , play_sound : None , sound_file : None } } }