Make file preview callback optional

When Picker and FilePicker are merged, not all Pickers will be able to
show a preview.

Co-authored-by: Gokul Soumya <gokulps15@gmail.com>
pull/7264/head
Michael Davis 1 year ago
parent fc111213b5
commit 545acfda88
No known key found for this signature in database

@ -2184,11 +2184,9 @@ fn global_search(cx: &mut Context) {
doc.set_selection(view.id, Selection::single(start, end)); doc.set_selection(view.id, Selection::single(start, end));
align_view(doc, view, Align::Center); align_view(doc, view, Align::Center);
}, }).with_preview(|_editor, FileResult { path, line_num }| {
|_editor, FileResult { path, line_num }| {
Some((path.clone().into(), Some((*line_num, *line_num)))) Some((path.clone().into(), Some((*line_num, *line_num))))
}, });
);
compositor.push(Box::new(overlaid(picker))); compositor.push(Box::new(overlaid(picker)));
}, },
)); ));
@ -2579,22 +2577,18 @@ fn buffer_picker(cx: &mut Context) {
// mru // mru
items.sort_unstable_by_key(|item| std::cmp::Reverse(item.focused_at)); items.sort_unstable_by_key(|item| std::cmp::Reverse(item.focused_at));
let picker = FilePicker::new( let picker = FilePicker::new(items, (), |cx, meta, action| {
items, cx.editor.switch(meta.id, action);
(), })
|cx, meta, action| { .with_preview(|editor, meta| {
cx.editor.switch(meta.id, action); let doc = &editor.documents.get(&meta.id)?;
}, let &view_id = doc.selections().keys().next()?;
|editor, meta| { let line = doc
let doc = &editor.documents.get(&meta.id)?; .selection(view_id)
let &view_id = doc.selections().keys().next()?; .primary()
let line = doc .cursor_line(doc.text().slice(..));
.selection(view_id) Some((meta.id.into(), Some((line, line))))
.primary() });
.cursor_line(doc.text().slice(..));
Some((meta.id.into(), Some((line, line))))
},
);
cx.push_layer(Box::new(overlaid(picker))); cx.push_layer(Box::new(overlaid(picker)));
} }
@ -2678,12 +2672,12 @@ fn jumplist_picker(cx: &mut Context) {
doc.set_selection(view.id, meta.selection.clone()); doc.set_selection(view.id, meta.selection.clone());
view.ensure_cursor_in_view_center(doc, config.scrolloff); view.ensure_cursor_in_view_center(doc, config.scrolloff);
}, },
|editor, meta| { )
let doc = &editor.documents.get(&meta.id)?; .with_preview(|editor, meta| {
let line = meta.selection.primary().cursor_line(doc.text().slice(..)); let doc = &editor.documents.get(&meta.id)?;
Some((meta.id.into(), Some((line, line)))) let line = meta.selection.primary().cursor_line(doc.text().slice(..));
}, Some((meta.id.into(), Some((line, line))))
); });
cx.push_layer(Box::new(overlaid(picker))); cx.push_layer(Box::new(overlaid(picker)));
} }

@ -73,21 +73,19 @@ fn thread_picker(
let debugger = debugger!(editor); let debugger = debugger!(editor);
let thread_states = debugger.thread_states.clone(); let thread_states = debugger.thread_states.clone();
let picker = FilePicker::new( let picker = FilePicker::new(threads, thread_states, move |cx, thread, _action| {
threads, callback_fn(cx.editor, thread)
thread_states, })
move |cx, thread, _action| callback_fn(cx.editor, thread), .with_preview(move |editor, thread| {
move |editor, thread| { let frames = editor.debugger.as_ref()?.stack_frames.get(&thread.id)?;
let frames = editor.debugger.as_ref()?.stack_frames.get(&thread.id)?; let frame = frames.get(0)?;
let frame = frames.get(0)?; let path = frame.source.as_ref()?.path.clone()?;
let path = frame.source.as_ref()?.path.clone()?; let pos = Some((
let pos = Some(( frame.line.saturating_sub(1),
frame.line.saturating_sub(1), frame.end_line.unwrap_or(frame.line).saturating_sub(1),
frame.end_line.unwrap_or(frame.line).saturating_sub(1), ));
)); Some((path.into(), pos))
Some((path.into(), pos)) });
},
);
compositor.push(Box::new(picker)); compositor.push(Box::new(picker));
}, },
); );
@ -728,39 +726,35 @@ pub fn dap_switch_stack_frame(cx: &mut Context) {
let frames = debugger.stack_frames[&thread_id].clone(); let frames = debugger.stack_frames[&thread_id].clone();
let picker = FilePicker::new( let picker = FilePicker::new(frames, (), move |cx, frame, _action| {
frames, let debugger = debugger!(cx.editor);
(), // TODO: this should be simpler to find
move |cx, frame, _action| { let pos = debugger.stack_frames[&thread_id]
let debugger = debugger!(cx.editor); .iter()
// TODO: this should be simpler to find .position(|f| f.id == frame.id);
let pos = debugger.stack_frames[&thread_id] debugger.active_frame = pos;
.iter()
.position(|f| f.id == frame.id); let frame = debugger.stack_frames[&thread_id]
debugger.active_frame = pos; .get(pos.unwrap_or(0))
.cloned();
let frame = debugger.stack_frames[&thread_id] if let Some(frame) = &frame {
.get(pos.unwrap_or(0)) jump_to_stack_frame(cx.editor, frame);
.cloned(); }
if let Some(frame) = &frame { })
jump_to_stack_frame(cx.editor, frame); .with_preview(move |_editor, frame| {
} frame
}, .source
move |_editor, frame| { .as_ref()
frame .and_then(|source| source.path.clone())
.source .map(|path| {
.as_ref() (
.and_then(|source| source.path.clone()) path.into(),
.map(|path| { Some((
( frame.line.saturating_sub(1),
path.into(), frame.end_line.unwrap_or(frame.line).saturating_sub(1),
Some(( )),
frame.line.saturating_sub(1), )
frame.end_line.unwrap_or(frame.line).saturating_sub(1), })
)), });
)
})
},
);
cx.push_layer(Box::new(picker)) cx.push_layer(Box::new(picker))
} }

@ -240,44 +240,40 @@ type SymbolPicker = FilePicker<SymbolInformationItem>;
fn sym_picker(symbols: Vec<SymbolInformationItem>, current_path: Option<lsp::Url>) -> SymbolPicker { fn sym_picker(symbols: Vec<SymbolInformationItem>, current_path: Option<lsp::Url>) -> SymbolPicker {
// TODO: drop current_path comparison and instead use workspace: bool flag? // TODO: drop current_path comparison and instead use workspace: bool flag?
FilePicker::new( FilePicker::new(symbols, current_path.clone(), move |cx, item, action| {
symbols, let (view, doc) = current!(cx.editor);
current_path.clone(), push_jump(view, doc);
move |cx, item, action| {
let (view, doc) = current!(cx.editor); if current_path.as_ref() != Some(&item.symbol.location.uri) {
push_jump(view, doc); let uri = &item.symbol.location.uri;
let path = match uri.to_file_path() {
if current_path.as_ref() != Some(&item.symbol.location.uri) { Ok(path) => path,
let uri = &item.symbol.location.uri; Err(_) => {
let path = match uri.to_file_path() { let err = format!("unable to convert URI to filepath: {}", uri);
Ok(path) => path,
Err(_) => {
let err = format!("unable to convert URI to filepath: {}", uri);
cx.editor.set_error(err);
return;
}
};
if let Err(err) = cx.editor.open(&path, action) {
let err = format!("failed to open document: {}: {}", uri, err);
log::error!("{}", err);
cx.editor.set_error(err); cx.editor.set_error(err);
return; return;
} }
};
if let Err(err) = cx.editor.open(&path, action) {
let err = format!("failed to open document: {}: {}", uri, err);
log::error!("{}", err);
cx.editor.set_error(err);
return;
} }
}
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
if let Some(range) = if let Some(range) =
lsp_range_to_range(doc.text(), item.symbol.location.range, item.offset_encoding) lsp_range_to_range(doc.text(), item.symbol.location.range, item.offset_encoding)
{ {
// we flip the range so that the cursor sits on the start of the symbol // we flip the range so that the cursor sits on the start of the symbol
// (for example start of the function). // (for example start of the function).
doc.set_selection(view.id, Selection::single(range.head, range.anchor)); doc.set_selection(view.id, Selection::single(range.head, range.anchor));
align_view(doc, view, Align::Center); align_view(doc, view, Align::Center);
} }
}, })
move |_editor, item| Some(location_to_file_location(&item.symbol.location)), .with_preview(move |_editor, item| Some(location_to_file_location(&item.symbol.location)))
)
.truncate_start(false) .truncate_start(false)
} }
@ -345,11 +341,11 @@ fn diag_picker(
align_view(doc, view, Align::Center); align_view(doc, view, Align::Center);
} }
}, },
move |_editor, PickerDiagnostic { url, diag, .. }| {
let location = lsp::Location::new(url.clone(), diag.range);
Some(location_to_file_location(&location))
},
) )
.with_preview(move |_editor, PickerDiagnostic { url, diag, .. }| {
let location = lsp::Location::new(url.clone(), diag.range);
Some(location_to_file_location(&location))
})
.truncate_start(false) .truncate_start(false)
} }
@ -1047,14 +1043,10 @@ fn goto_impl(
editor.set_error("No definition found."); editor.set_error("No definition found.");
} }
_locations => { _locations => {
let picker = FilePicker::new( let picker = FilePicker::new(locations, cwdir, move |cx, location, action| {
locations, jump_to_location(cx.editor, location, offset_encoding, action)
cwdir, })
move |cx, location, action| { .with_preview(move |_editor, location| Some(location_to_file_location(location)));
jump_to_location(cx.editor, location, offset_encoding, action)
},
move |_editor, location| Some(location_to_file_location(location)),
);
compositor.push(Box::new(overlaid(picker))); compositor.push(Box::new(overlaid(picker)));
} }
} }

@ -217,21 +217,17 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
log::debug!("file_picker init {:?}", Instant::now().duration_since(now)); log::debug!("file_picker init {:?}", Instant::now().duration_since(now));
FilePicker::new( FilePicker::new(files, root, move |cx, path: &PathBuf, action| {
files, if let Err(e) = cx.editor.open(path, action) {
root, let err = if let Some(err) = e.source() {
move |cx, path: &PathBuf, action| { format!("{}", err)
if let Err(e) = cx.editor.open(path, action) { } else {
let err = if let Some(err) = e.source() { format!("unable to open \"{}\"", path.display())
format!("{}", err) };
} else { cx.editor.set_error(err);
format!("unable to open \"{}\"", path.display()) }
}; })
cx.editor.set_error(err); .with_preview(|_editor, path| Some((path.clone().into(), None)))
}
},
|_editor, path| Some((path.clone().into(), None)),
)
} }
pub mod completers { pub mod completers {

@ -141,7 +141,7 @@ pub struct FilePicker<T: Item> {
preview_cache: HashMap<PathBuf, CachedPreview>, preview_cache: HashMap<PathBuf, CachedPreview>,
read_buffer: Vec<u8>, read_buffer: Vec<u8>,
/// Given an item in the picker, return the file path and line number to display. /// Given an item in the picker, return the file path and line number to display.
file_fn: FileCallback<T>, file_fn: Option<FileCallback<T>>,
} }
impl<T: Item + 'static> FilePicker<T> { impl<T: Item + 'static> FilePicker<T> {
@ -149,7 +149,6 @@ impl<T: Item + 'static> FilePicker<T> {
options: Vec<T>, options: Vec<T>,
editor_data: T::Data, editor_data: T::Data,
callback_fn: impl Fn(&mut Context, &T, Action) + 'static, callback_fn: impl Fn(&mut Context, &T, Action) + 'static,
preview_fn: impl Fn(&Editor, &T) -> Option<FileLocation> + 'static,
) -> Self { ) -> Self {
let prompt = Prompt::new( let prompt = Prompt::new(
"".into(), "".into(),
@ -173,7 +172,7 @@ impl<T: Item + 'static> FilePicker<T> {
widths: Vec::new(), widths: Vec::new(),
preview_cache: HashMap::new(), preview_cache: HashMap::new(),
read_buffer: Vec::with_capacity(1024), read_buffer: Vec::with_capacity(1024),
file_fn: Box::new(preview_fn), file_fn: None,
picker: unimplemented!(), picker: unimplemented!(),
}; };
@ -202,6 +201,14 @@ impl<T: Item + 'static> FilePicker<T> {
self self
} }
pub fn with_preview(
mut self,
preview_fn: impl Fn(&Editor, &T) -> Option<FileLocation> + 'static,
) -> Self {
self.file_fn = Some(Box::new(preview_fn));
self
}
pub fn set_options(&mut self, new_options: Vec<T>) { pub fn set_options(&mut self, new_options: Vec<T>) {
self.options = new_options; self.options = new_options;
self.cursor = 0; self.cursor = 0;
@ -372,7 +379,7 @@ impl<T: Item + 'static> FilePicker<T> {
fn current_file(&self, editor: &Editor) -> Option<FileLocation> { fn current_file(&self, editor: &Editor) -> Option<FileLocation> {
self.picker self.picker
.selection() .selection()
.and_then(|current| (self.file_fn)(editor, current)) .and_then(|current| (self.file_fn.as_ref()?)(editor, current))
.and_then(|(path_or_id, line)| path_or_id.get_canonicalized().ok().zip(Some(line))) .and_then(|(path_or_id, line)| path_or_id.get_canonicalized().ok().zip(Some(line)))
} }

Loading…
Cancel
Save