@@ -17,16 +17,15 @@ use std::{borrow::Cow, collections::HashMap, path::PathBuf};
1717use crate::ui::{Prompt, PromptEvent};
1818use helix_core::Position;
1919use helix_view::{
20− document::canonicalize_path,
2120 editor::Action,
22− graphics::{Color, CursorKind, Rect, Style},
21+ graphics::{Color, CursorKind, Margin, Rect, Style},
2322 Document, Editor,
2423};
2524
2625pub const MIN_SCREEN_WIDTH_FOR_PREVIEW: u16 = 80;
2726
2827/// 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)>);
3029
3130pub struct FilePicker<T> {
3231 picker: Picker<T>,
@@ -54,7 +53,11 @@ impl<T> FilePicker<T> {
5453 self.picker
5554 .selection()
5655 .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)
58+ .ok()
59+ .zip(Some(line))
60+ })
5861 }
5962
6063 fn calculate_preview(&mut self, editor: &Editor) {
@@ -90,34 +93,40 @@ impl<T: 'static> Component for FilePicker<T> {
9093 area.width
9194 };
9295
93− let picker_area = Rect::new(area.x, area.y, picker_width, area.height);
96+ let picker_area = area.with_width(picker_width);
9497 self.picker.render(picker_area, surface, cx);
9598
9699 if !render_preview {
97100 return;
98101 }
99102
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);
101104
102105 // don't like this but the lifetime sucks
103106 let block = Block::default().borders(Borders::ALL);
104107
105108 // calculate the inner area inside the box
106− let mut inner = block.inner(preview_area);
109+ let inner = block.inner(preview_area);
107110 // 1 column gap on either side
108− inner.x += 1;
109− inner.width = inner.width.saturating_sub(2);
111+ let margin = Margin {
112+ vertical: 0,
113+ horizontal: 1,
114+ };
115+ let inner = inner.inner(&margin);
110116
111117 block.render(preview_area, surface);
112118
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)| {
114120 cx.editor
115121 .document_by_path(&path)
116122 .or_else(|| self.preview_cache.get(&path))
117− .zip(Some(line))
123+ .zip(Some(range))
118124 }) {
119125 // align to middle
120− let first_line = line.unwrap_or(0).saturating_sub(inner.height as usize / 2);
126+ let first_line = line
127+ .map(|(start, _)| start)
128+ .unwrap_or(0)
129+ .saturating_sub(inner.height as usize / 2);
121130 let offset = Position::new(first_line, 0);
122131
123132 let highlights = EditorView::doc_syntax_highlights(
@@ -137,12 +146,21 @@ impl<T: 'static> Component for FilePicker<T> {
137146 );
138147
139148 // highlight the line
140− if let Some(line) = line {
141− for x in inner.left()..inner.right() {
142− surface
143− .get_mut(x, inner.y + line.saturating_sub(first_line) as u16)
144− .set_style(cx.editor.theme.get("ui.selection"));
145− }
149+ if let Some((start, end)) = line {
150+ let offset = start.saturating_sub(first_line) as u16;
151+ surface.set_style(
152+ Rect::new(
153+ inner.x,
154+ inner.y + offset,
155+ inner.width,
156+ (end.saturating_sub(start) as u16 + 1)
157+ .min(inner.height.saturating_sub(offset)),
158+ ),
159+ cx.editor
160+ .theme
161+ .try_get("ui.highlight")
162+ .unwrap_or_else(|| cx.editor.theme.get("ui.selection")),
163+ );
146164 }
147165 }
148166 }
@@ -282,15 +300,11 @@ impl<T> Picker<T> {
282300// - score all the names in relation to input
283301
284302fn inner_rect(area: Rect) -> Rect {
285− let padding_vertical = area.height * 10 / 100;
286− let padding_horizontal = area.width * 10 / 100;
287−
288− Rect::new(
289− area.x + padding_horizontal,
290− area.y + padding_vertical,
291− area.width - padding_horizontal * 2,
292− area.height - padding_vertical * 2,
293− )
303+ let margin = Margin {
304+ vertical: area.height * 10 / 100,
305+ horizontal: area.width * 10 / 100,
306+ };
307+ area.inner(&margin)
294308}
295309
296310impl<T: 'static> Component for Picker<T> {
@@ -410,7 +424,7 @@ impl<T: 'static> Component for Picker<T> {
410424
411425 // -- Render the input bar:
412426
413− let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
427+ let area = inner.clip_left(1).with_height(1);
414428
415429 let count = format!("{}/{}", self.matches.len(), self.options.len());
416430 surface.set_stringn(
@@ -434,8 +448,8 @@ impl<T: 'static> Component for Picker<T> {
434448 }
435449
436450 // -- Render the contents:
437− // subtract the area of the prompt (-2) and current item marker " > " (-3)
438− let inner = Rect::new(inner.x + 3, inner.y + 2, inner.width - 3, inner.height - 2);
451+ // subtract area of prompt from top and current item marker " > " from left
452+ let inner = inner.clip_top(2).clip_left(3);
439453
440454 let selected = cx.editor.theme.get("ui.text.focus");
441455
@@ -474,7 +488,7 @@ impl<T: 'static> Component for Picker<T> {
474488 let inner = block.inner(area);
475489
476490 // 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);
478492
479493 self.prompt.cursor(area, editor)
480494 }