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>
This commit is contained in:
Michael Davis 2023-06-18 12:23:15 -05:00
parent fc111213b5
commit 545acfda88
No known key found for this signature in database
5 changed files with 119 additions and 136 deletions

View file

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

View file

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

View file

@ -240,44 +240,40 @@ type SymbolPicker = FilePicker<SymbolInformationItem>;
fn sym_picker(symbols: Vec<SymbolInformationItem>, current_path: Option<lsp::Url>) -> SymbolPicker {
// TODO: drop current_path comparison and instead use workspace: bool flag?
FilePicker::new(
symbols,
current_path.clone(),
move |cx, item, action| {
let (view, doc) = current!(cx.editor);
push_jump(view, doc);
FilePicker::new(symbols, current_path.clone(), move |cx, item, action| {
let (view, doc) = current!(cx.editor);
push_jump(view, doc);
if current_path.as_ref() != Some(&item.symbol.location.uri) {
let uri = &item.symbol.location.uri;
let path = match uri.to_file_path() {
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);
if current_path.as_ref() != Some(&item.symbol.location.uri) {
let uri = &item.symbol.location.uri;
let path = match uri.to_file_path() {
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);
return;
}
}
let (view, doc) = current!(cx.editor);
let (view, doc) = current!(cx.editor);
if let Some(range) =
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
// (for example start of the function).
doc.set_selection(view.id, Selection::single(range.head, range.anchor));
align_view(doc, view, Align::Center);
}
},
move |_editor, item| Some(location_to_file_location(&item.symbol.location)),
)
if let Some(range) =
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
// (for example start of the function).
doc.set_selection(view.id, Selection::single(range.head, range.anchor));
align_view(doc, view, Align::Center);
}
})
.with_preview(move |_editor, item| Some(location_to_file_location(&item.symbol.location)))
.truncate_start(false)
}
@ -345,11 +341,11 @@ fn diag_picker(
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)
}
@ -1047,14 +1043,10 @@ fn goto_impl(
editor.set_error("No definition found.");
}
_locations => {
let picker = FilePicker::new(
locations,
cwdir,
move |cx, location, action| {
jump_to_location(cx.editor, location, offset_encoding, action)
},
move |_editor, location| Some(location_to_file_location(location)),
);
let picker = FilePicker::new(locations, cwdir, move |cx, location, action| {
jump_to_location(cx.editor, location, offset_encoding, action)
})
.with_preview(move |_editor, location| Some(location_to_file_location(location)));
compositor.push(Box::new(overlaid(picker)));
}
}

View file

@ -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));
FilePicker::new(
files,
root,
move |cx, path: &PathBuf, action| {
if let Err(e) = cx.editor.open(path, action) {
let err = if let Some(err) = e.source() {
format!("{}", err)
} else {
format!("unable to open \"{}\"", path.display())
};
cx.editor.set_error(err);
}
},
|_editor, path| Some((path.clone().into(), None)),
)
FilePicker::new(files, root, move |cx, path: &PathBuf, action| {
if let Err(e) = cx.editor.open(path, action) {
let err = if let Some(err) = e.source() {
format!("{}", err)
} else {
format!("unable to open \"{}\"", path.display())
};
cx.editor.set_error(err);
}
})
.with_preview(|_editor, path| Some((path.clone().into(), None)))
}
pub mod completers {

View file

@ -141,7 +141,7 @@ pub struct FilePicker<T: Item> {
preview_cache: HashMap<PathBuf, CachedPreview>,
read_buffer: Vec<u8>,
/// 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> {
@ -149,7 +149,6 @@ impl<T: Item + 'static> FilePicker<T> {
options: Vec<T>,
editor_data: T::Data,
callback_fn: impl Fn(&mut Context, &T, Action) + 'static,
preview_fn: impl Fn(&Editor, &T) -> Option<FileLocation> + 'static,
) -> Self {
let prompt = Prompt::new(
"".into(),
@ -173,7 +172,7 @@ impl<T: Item + 'static> FilePicker<T> {
widths: Vec::new(),
preview_cache: HashMap::new(),
read_buffer: Vec::with_capacity(1024),
file_fn: Box::new(preview_fn),
file_fn: None,
picker: unimplemented!(),
};
@ -202,6 +201,14 @@ impl<T: Item + 'static> FilePicker<T> {
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>) {
self.options = new_options;
self.cursor = 0;
@ -372,7 +379,7 @@ impl<T: Item + 'static> FilePicker<T> {
fn current_file(&self, editor: &Editor) -> Option<FileLocation> {
self.picker
.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)))
}