Skip to content

Commit

Permalink
Redone #4189 on top of master, now everyting works
Browse files Browse the repository at this point in the history
  • Loading branch information
GNUSheep committed Aug 19, 2024
1 parent b90ec5c commit 3e84a20
Showing 1 changed file with 136 additions and 1 deletion.
137 changes: 136 additions & 1 deletion helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,10 @@ pub struct Picker<T: 'static + Send + Sync, D: 'static> {
/// An event handler for syntax highlighting the currently previewed file.
preview_highlight_handler: Sender<Arc<Path>>,
dynamic_query_handler: Option<Sender<DynamicQueryChange>>,

preview_scroll_offset: (Direction, usize),
preview_height: u16,
cursor_picker: u32,
}

impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
Expand Down Expand Up @@ -394,6 +398,9 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
file_fn: None,
preview_highlight_handler: PreviewHighlightHandler::<T, D>::default().spawn(),
dynamic_query_handler: None,
preview_scroll_offset: (Direction::Forward, 0),
preview_height: 0,
cursor_picker: 0,
}
}

Expand Down Expand Up @@ -445,6 +452,44 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
self
}

/// Moves the picker file preview by a number of lines, either down (`Forward`) or up (`Backward`)
fn move_preview_by(&mut self, amount: usize, move_direction: Direction) {
let (current_scroll_direction, current_scroll_offset) = self.preview_scroll_offset;

match move_direction {
Direction::Backward => match current_scroll_direction {
Direction::Backward => {
self.preview_scroll_offset.1 = current_scroll_offset.saturating_add(amount);
}
Direction::Forward => {
if let Some(change) = current_scroll_offset.checked_sub(amount) {
self.preview_scroll_offset.1 = change;
} else {
self.preview_scroll_offset = (
Direction::Backward,
amount.saturating_sub(current_scroll_offset),
);
}
}
},
Direction::Forward => match current_scroll_direction {
Direction::Backward => {
if let Some(change) = current_scroll_offset.checked_sub(amount) {
self.preview_scroll_offset.1 = change;
} else {
self.preview_scroll_offset = (
Direction::Forward,
amount.saturating_sub(current_scroll_offset),
);
}
}
Direction::Forward => {
self.preview_scroll_offset.1 = current_scroll_offset.saturating_add(amount);
}
},
};
}

/// Move the cursor by a number of lines, either down (`Forward`) or up (`Backward`)
pub fn move_by(&mut self, amount: u32, direction: Direction) {
let len = self.matcher.snapshot().matched_item_count();
Expand Down Expand Up @@ -849,6 +894,15 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
let inner = inner.inner(margin);
BLOCK.render(area, surface);

let mut preview_scroll_offset = self.preview_scroll_offset;

// Reset preview scroll if cursor moved
let cursor_position = self.cursor_picker;
if self.cursor != cursor_position {
preview_scroll_offset = (Direction::Forward, 0);
self.cursor_picker = self.cursor;
}

if let Some((preview, range)) = self.get_preview(cx.editor) {
let doc = match preview.document() {
Some(doc)
Expand All @@ -866,7 +920,8 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
return;
}
};

let doc_height = doc.text().len_lines();

let mut offset = ViewPosition::default();
if let Some((start_line, end_line)) = range {
let height = end_line - start_line;
Expand Down Expand Up @@ -894,6 +949,21 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
}
}

// limit scroll offset between [-offset.anchor, doc.text().len_lines() - offset.anchor - preview height]
preview_scroll_offset.1 = match preview_scroll_offset.0 {
Direction::Backward => preview_scroll_offset.1.min(offset.anchor),
Direction::Forward => preview_scroll_offset.1.min(
doc_height
.saturating_sub(offset.anchor)
.saturating_sub(inner.height as usize),
),
};

offset.vertical_offset = match preview_scroll_offset.0 {
Direction::Backward => offset.anchor.saturating_sub(preview_scroll_offset.1),
Direction::Forward => offset.anchor.saturating_add(preview_scroll_offset.1),
};

let syntax_highlights = EditorView::doc_syntax_highlights(
doc,
offset.anchor,
Expand Down Expand Up @@ -943,6 +1013,39 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
&cx.editor.theme,
decorations,
);

self.preview_scroll_offset = preview_scroll_offset;

let win_height = inner.height as usize;
let len = doc_height;
let fits = len <= win_height;
let scroll = offset.vertical_offset;
let scroll_style = cx.editor.theme.get("ui.menu.scroll");

const fn div_ceil(a: usize, b: usize) -> usize {
(a + b - 1) / b
}

if !fits {
let scroll_height = div_ceil(win_height.pow(2), len).min(win_height);
let scroll_line = (win_height - scroll_height) * scroll
/ std::cmp::max(1, len.saturating_sub(win_height));

let mut cell;
for i in 0..win_height {
cell = &mut surface[(inner.right() - 1, inner.top() + i as u16)];

cell.set_symbol("▐"); // right half block

if scroll_line <= i && i < scroll_line + scroll_height {
// Draw scroll thumb
cell.set_fg(scroll_style.fg.unwrap_or(helix_view::theme::Color::Reset));
} else {
// Draw scroll track
cell.set_fg(scroll_style.bg.unwrap_or(helix_view::theme::Color::Reset));
}
}
}
}
}
}
Expand Down Expand Up @@ -1074,6 +1177,36 @@ impl<I: 'static + Send + Sync, D: 'static + Send + Sync> Component for Picker<I,
ctrl!('t') => {
self.toggle_preview();
}
alt!('k') | shift!(Up) if self.show_preview => {
self.move_preview_by(
ctx.editor.config().scroll_lines.unsigned_abs(),
Direction::Backward,
);
}
alt!('j') | shift!(Down) if self.show_preview => {
self.move_preview_by(
ctx.editor.config().scroll_lines.unsigned_abs(),
Direction::Forward,
);
}
alt!('u') if self.show_preview => {
self.move_preview_by(
self.preview_height.saturating_div(2) as usize,
Direction::Backward,
);
}
alt!('d') if self.show_preview => {
self.move_preview_by(
self.preview_height.saturating_div(2) as usize,
Direction::Forward,
);
}
alt!('b') if self.show_preview => {
self.move_preview_by(self.preview_height as usize, Direction::Backward);
}
alt!('f') if self.show_preview => {
self.move_preview_by(self.preview_height as usize, Direction::Forward);
}
_ => {
self.prompt_handle_event(event, ctx);
}
Expand All @@ -1095,6 +1228,8 @@ impl<I: 'static + Send + Sync, D: 'static + Send + Sync> Component for Picker<I,

fn required_size(&mut self, (width, height): (u16, u16)) -> Option<(u16, u16)> {
self.completion_height = height.saturating_sub(4 + self.header_height());
self.preview_height = height.saturating_sub(2);

Some((width, height))
}

Expand Down

0 comments on commit 3e84a20

Please sign in to comment.