mirror of https://github.com/helix-editor/helix
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
parent
fc111213b5
commit
545acfda88
|
@ -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);
|
|
||||||
debugger.active_frame = pos;
|
|
||||||
|
|
||||||
let frame = debugger.stack_frames[&thread_id]
|
let frame = debugger.stack_frames[&thread_id]
|
||||||
.get(pos.unwrap_or(0))
|
.get(pos.unwrap_or(0))
|
||||||
.cloned();
|
.cloned();
|
||||||
if let Some(frame) = &frame {
|
if let Some(frame) = &frame {
|
||||||
jump_to_stack_frame(cx.editor, frame);
|
jump_to_stack_frame(cx.editor, frame);
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
move |_editor, frame| {
|
.with_preview(move |_editor, frame| {
|
||||||
frame
|
frame
|
||||||
.source
|
.source
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|source| source.path.clone())
|
.and_then(|source| source.path.clone())
|
||||||
.map(|path| {
|
.map(|path| {
|
||||||
(
|
(
|
||||||
path.into(),
|
path.into(),
|
||||||
Some((
|
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),
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
},
|
});
|
||||||
);
|
|
||||||
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);
|
|
||||||
push_jump(view, doc);
|
|
||||||
|
|
||||||
if current_path.as_ref() != Some(&item.symbol.location.uri) {
|
if current_path.as_ref() != Some(&item.symbol.location.uri) {
|
||||||
let uri = &item.symbol.location.uri;
|
let uri = &item.symbol.location.uri;
|
||||||
let path = match uri.to_file_path() {
|
let path = match uri.to_file_path() {
|
||||||
Ok(path) => path,
|
Ok(path) => path,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let err = format!("unable to convert URI to filepath: {}", uri);
|
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…
Reference in New Issue