@@ -17,16 +17,15 @@ use std::{borrow::Cow, collections::HashMap, path::PathBuf};
17use crate::ui::{Prompt, PromptEvent};
17use crate::ui::{Prompt, PromptEvent};
18use helix_core::Position;
18use helix_core::Position;
19use helix_view::{
19use helix_view::{
20− document::canonicalize_path,
21 editor::Action,
20 editor::Action,
22− graphics::{Color, CursorKind, Rect, Style},
21+ graphics::{Color, CursorKind, Margin, Rect, Style},
23 Document, Editor,
22 Document, Editor,
26pub const MIN_SCREEN_WIDTH_FOR_PREVIEW: u16 = 80;
25pub const MIN_SCREEN_WIDTH_FOR_PREVIEW: u16 = 80;
28/// File path and line number (used to align and highlight a line)
27/// File path and line number (used to align and highlight a line)
29−type FileLocation = (PathBuf, Option<usize>);
28+type FileLocation = (PathBuf, Option<(usize, usize)>);
31pub struct FilePicker<T> {
30pub struct FilePicker<T> {
32 picker: Picker<T>,
31 picker: Picker<T>,
@@ -54,7 +53,11 @@ impl<T> FilePicker<T> {
54 self.picker
53 self.picker
55 .selection()
54 .selection()
56 .and_then(|current| (self.file_fn)(editor, current))
55 .and_then(|current| (self.file_fn)(editor, current))
57− .and_then(|(path, line)| canonicalize_path(&path).ok().zip(Some(line)))
56+ .and_then(|(path, line)| {
57+ helix_core::path::get_canonicalized_path(&path)
60 fn calculate_preview(&mut self, editor: &Editor) {
63 fn calculate_preview(&mut self, editor: &Editor) {
@@ -90,34 +93,40 @@ impl<T: 'static> Component for FilePicker<T> {
90 area.width
93 area.width
93− let picker_area = Rect::new(area.x, area.y, picker_width, area.height);
96+ let picker_area = area.with_width(picker_width);
94 self.picker.render(picker_area, surface, cx);
97 self.picker.render(picker_area, surface, cx);
96 if !render_preview {
99 if !render_preview {
100− let preview_area = Rect::new(area.x + picker_width, area.y, area.width / 2, area.height);
103+ let preview_area = area.clip_left(picker_width);
102 // don't like this but the lifetime sucks
105 // don't like this but the lifetime sucks
103 let block = Block::default().borders(Borders::ALL);
106 let block = Block::default().borders(Borders::ALL);
105 // calculate the inner area inside the box
108 // calculate the inner area inside the box
106− let mut inner = block.inner(preview_area);
109+ let inner = block.inner(preview_area);
107 // 1 column gap on either side
110 // 1 column gap on either side
108− inner.x += 1;
111+ let margin = Margin {
109− inner.width = inner.width.saturating_sub(2);
112+ vertical: 0,
115+ let inner = inner.inner(&margin);
111 block.render(preview_area, surface);
117 block.render(preview_area, surface);
113− if let Some((doc, line)) = self.current_file(cx.editor).and_then(|(path, line)| {
119+ if let Some((doc, line)) = self.current_file(cx.editor).and_then(|(path, range)| {
114 cx.editor
120 cx.editor
115 .document_by_path(&path)
121 .document_by_path(&path)
116 .or_else(|| self.preview_cache.get(&path))
122 .or_else(|| self.preview_cache.get(&path))
117− .zip(Some(line))
123+ .zip(Some(range))
119 // align to middle
125 // align to middle
126+ let first_line = line
127+ .map(|(start, _)| start)
120− let first_line = line.unwrap_or(0).saturating_sub(inner.height as usize / 2);
129+ .saturating_sub(inner.height as usize / 2);
121 let offset = Position::new(first_line, 0);
130 let offset = Position::new(first_line, 0);
123 let highlights = EditorView::doc_syntax_highlights(
132 let highlights = EditorView::doc_syntax_highlights(
@@ -137,12 +146,21 @@ impl<T: 'static> Component for FilePicker<T> {
139 // highlight the line
148 // highlight the line
140− if let Some(line) = line {
149+ if let Some((start, end)) = line {
141− for x in inner.left()..inner.right() {
150+ let offset = start.saturating_sub(first_line) as u16;
142− surface
151+ surface.set_style(
143− .get_mut(x, inner.y + line.saturating_sub(first_line) as u16)
156+ (end.saturating_sub(start) as u16 + 1)
157+ .min(inner.height.saturating_sub(offset)),
161+ .try_get("ui.highlight")
144− .set_style(cx.editor.theme.get("ui.selection"));
162+ .unwrap_or_else(|| cx.editor.theme.get("ui.selection")),
@@ -282,15 +300,11 @@ impl<T> Picker<T> {
282// - score all the names in relation to input
300// - score all the names in relation to input
284fn inner_rect(area: Rect) -> Rect {
302fn inner_rect(area: Rect) -> Rect {
303+ let margin = Margin {
285− let padding_vertical = area.height * 10 / 100;
304+ vertical: area.height * 10 / 100,
286− let padding_horizontal = area.width * 10 / 100;
305+ horizontal: area.width * 10 / 100,
288− Rect::new(
307+ area.inner(&margin)
289− area.x + padding_horizontal,
290− area.y + padding_vertical,
291− area.width - padding_horizontal * 2,
292− area.height - padding_vertical * 2,
296impl<T: 'static> Component for Picker<T> {
310impl<T: 'static> Component for Picker<T> {
@@ -410,7 +424,7 @@ impl<T: 'static> Component for Picker<T> {
411 // -- Render the input bar:
425 // -- Render the input bar:
413− let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
427+ let area = inner.clip_left(1).with_height(1);
415 let count = format!("{}/{}", self.matches.len(), self.options.len());
429 let count = format!("{}/{}", self.matches.len(), self.options.len());
416 surface.set_stringn(
430 surface.set_stringn(
@@ -434,8 +448,8 @@ impl<T: 'static> Component for Picker<T> {
436 // -- Render the contents:
450 // -- Render the contents:
437− // subtract the area of the prompt (-2) and current item marker " > " (-3)
451+ // subtract area of prompt from top and current item marker " > " from left
438− let inner = Rect::new(inner.x + 3, inner.y + 2, inner.width - 3, inner.height - 2);
452+ let inner = inner.clip_top(2).clip_left(3);
440 let selected = cx.editor.theme.get("ui.text.focus");
454 let selected = cx.editor.theme.get("ui.text.focus");
@@ -474,7 +488,7 @@ impl<T: 'static> Component for Picker<T> {
474 let inner = block.inner(area);
488 let inner = block.inner(area);
476 // prompt area
490 // prompt area
477− let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
491+ let area = inner.clip_left(1).with_height(1);
479 self.prompt.cursor(area, editor)
493 self.prompt.cursor(area, editor)