diff --git a/Cargo.lock b/Cargo.lock index 391d84bc..9d52a86b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,7 +575,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -706,6 +706,7 @@ dependencies = [ "skim", "strum", "termina", + "tui-scrollbar", "unicode-segmentation", "unicode-width", ] @@ -887,7 +888,7 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82cb6a9f675da968c63b6208c641b9dca58fc0133ae53375736b1767b0cab8bd" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1145,7 +1146,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1696,7 +1697,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1949,7 +1950,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2109,6 +2110,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" +[[package]] +name = "tui-scrollbar" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a495ec7eb64f1505a94d56bbb337792b15448394879552b09be2a1460846d99b" +dependencies = [ + "document-features", + "ratatui-core", +] + [[package]] name = "typenum" version = "1.20.1" diff --git a/Cargo.toml b/Cargo.toml index 2d75947a..7ae34f55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ easing-function = "0.1.1" strum = { version = "0.28.0", features = ["derive"] } ctor = "1.0.7" flycomp = { git = "https://github.com/HalFrgrd/flycomp.git", rev = "754be16d7a2130ad12b6d038d42a8933c92c103f" } +tui-scrollbar = "0.2" [features] pre_bash_4_4 = [] @@ -71,3 +72,4 @@ dockerfile = "docker/cross/i686-linux-android.Dockerfile" [patch.crates-io] termina = { git = "https://github.com/HalFrgrd/termina.git", rev = "529aeb6b65660d642af221f4f6a09b7e4fc51213" } +ratatui-core = { git = "https://github.com/HalFrgrd/ratatui.git", rev = "c1303b38d3fce8542d960d3f06c490df36567b22" } diff --git a/src/active_suggestions.rs b/src/active_suggestions.rs index ed147c78..0e0b6a60 100644 --- a/src/active_suggestions.rs +++ b/src/active_suggestions.rs @@ -1787,18 +1787,17 @@ impl ActiveSuggestions { return; } - let relative_pos = if max_cell_height == 0 { - 0.0 - } else { - cell_height as f64 / max_cell_height as f64 + let page_size = self.row_window_to_show.window_size(); + let lengths = tui_scrollbar::ScrollLengths { + content_len: n, + viewport_len: page_size, }; - let target_idx = (relative_pos * (n.saturating_sub(1) as f64)).round() as usize; - self.set_selected_by_idx(target_idx); + let metrics = tui_scrollbar::ScrollMetrics::new(lengths, 0, (max_cell_height + 1) as u16); + let target_start = metrics.offset_for_thumb_start(cell_height * tui_scrollbar::SUBCELL); + let target_idx = target_start.min(n.saturating_sub(1)); - let page_size = self.row_window_to_show.window_size(); - let max_start = n.saturating_sub(page_size); - let target_start = (relative_pos * (max_start as f64)).round() as usize; + self.set_selected_by_idx(target_idx); self.row_window_to_show .force_window_and_index(target_start, target_idx); } diff --git a/src/content_builder.rs b/src/content_builder.rs index 32120123..70bfee26 100644 --- a/src/content_builder.rs +++ b/src/content_builder.rs @@ -1159,32 +1159,42 @@ impl Contents { return; } - let l = length as f64; - let t = total as f64; - let v = visible as f64; - let s = start as f64; - - // Size of the thumb (at least 1 cell) - let thumb_size = ((v / t) * l).round().max(1.0) as usize; - // Position of the thumb - let max_start = t - v; - let thumb_pos = if max_start > 0.0 { - ((s / max_start) * (l - thumb_size as f64)).round() as usize - } else { - 0 + use ratatui::layout::Rect; + use ratatui::widgets::Widget; + use tui_scrollbar::{GlyphSet, ScrollBar, ScrollBarArrows, ScrollLengths}; + + let mut glyph_set = GlyphSet::unicode(); + glyph_set.track_vertical = '█'; + + let lengths = ScrollLengths { + content_len: total, + viewport_len: visible, }; + use ratatui::style::{Color, Style}; + + let track_style = Style::default().fg(Color::Red); + let effective_thumb_style = Style::default().fg(Color::Blue).bg(Color::Red); + + let scrollbar = ScrollBar::vertical(lengths) + .offset(start) + .glyph_set(glyph_set) + .arrows(ScrollBarArrows::None) + .thumb_style(effective_thumb_style) + .track_style(track_style); + + let area = Rect::new(0, 0, 1, length); + let mut tmp_buf = ratatui::buffer::Buffer::empty(area); + Widget::render(&scrollbar, area, &mut tmp_buf); + for i in 0..length as usize { let row_y = y_start + i as u16; - let is_thumb = i >= thumb_pos && i < thumb_pos + thumb_size; - let symbol = if is_thumb { "█" } else { "░" }; - let cell_style = if is_thumb { thumb_style } else { gutter_style }; + let rendered_cell = &tmp_buf[(0, i as u16)]; if let Some(row) = self.buf.get_mut(row_y as usize) && let Some(tagged_cell) = row.get_mut(x as usize) { - tagged_cell.cell.reset(); - tagged_cell.cell.set_symbol(symbol).set_style(cell_style); + tagged_cell.cell = rendered_cell.clone(); tagged_cell.tag = Tag::TabCompletionScrollBar { cell_height: i, max_cell_height: length.saturating_sub(1) as usize,