Skip to content

Commit

Permalink
Recurse find file picker
Browse files Browse the repository at this point in the history
  • Loading branch information
pickfire committed May 13, 2022
1 parent 6ffe397 commit 007f247
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 101 deletions.
67 changes: 38 additions & 29 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use movement::Movement;
use crate::{
args,
compositor::{self, Component, Compositor},
ui::{self, overlay::overlayed, FilePicker, Picker, Popup, Prompt, PromptEvent},
ui::{self, overlay::overlayed, picker, FilePicker, Picker, Popup, Prompt, PromptEvent},
};

use crate::job::{self, Job, Jobs};
Expand Down Expand Up @@ -1843,27 +1843,30 @@ fn global_search(cx: &mut Context) {
relative_path.into()
}
},
move |cx, (line_num, path), action| {
match cx.editor.open(path.into(), action) {
Ok(_) => {}
Err(e) => {
cx.editor.set_error(format!(
"Failed to open file '{}': {}",
path.display(),
e
));
return;
move |cx, result, action| {
if let Some((line_num, path)) = result {
match cx.editor.open(path.into(), action) {
Ok(_) => {}
Err(e) => {
cx.editor.set_error(format!(
"Failed to open file '{}': {}",
path.display(),
e
));
return picker::close_picker();
}
}
}

let line_num = *line_num;
let (view, doc) = current!(cx.editor);
let text = doc.text();
let start = text.line_to_char(line_num);
let end = text.line_to_char((line_num + 1).min(text.len_lines()));
let line_num = *line_num;
let (view, doc) = current!(cx.editor);
let text = doc.text();
let start = text.line_to_char(line_num);
let end = text.line_to_char((line_num + 1).min(text.len_lines()));

doc.set_selection(view.id, Selection::single(start, end));
align_view(doc, view, Align::Center);
doc.set_selection(view.id, Selection::single(start, end));
align_view(doc, view, Align::Center);
}
picker::close_picker()
},
|_editor, (line_num, path)| Some((path.clone(), Some((*line_num, *line_num)))),
);
Expand Down Expand Up @@ -2159,7 +2162,10 @@ fn buffer_picker(cx: &mut Context) {
.collect(),
BufferMeta::format,
|cx, meta, action| {
cx.editor.switch(meta.id, action);
if let Some(meta) = meta {
cx.editor.switch(meta.id, action);
}
picker::close_picker()
},
|editor, meta| {
let doc = &editor.documents.get(&meta.id)?;
Expand Down Expand Up @@ -2219,15 +2225,18 @@ pub fn command_palette(cx: &mut Context) {
},
},
move |cx, command, _action| {
let mut ctx = Context {
register: None,
count: std::num::NonZeroUsize::new(1),
editor: cx.editor,
callback: None,
on_next_key_callback: None,
jobs: cx.jobs,
};
command.execute(&mut ctx);
if let Some(command) = command {
let mut ctx = Context {
register: None,
count: std::num::NonZeroUsize::new(1),
editor: cx.editor,
callback: None,
on_next_key_callback: None,
jobs: cx.jobs,
};
command.execute(&mut ctx);
}
picker::close_picker()
},
);
compositor.push(Box::new(overlayed(picker)));
Expand Down
60 changes: 37 additions & 23 deletions helix-term/src/commands/dap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{Context, Editor};
use crate::{
compositor::{self, Compositor},
job::{Callback, Jobs},
ui::{self, overlay::overlayed, FilePicker, Picker, Popup, Prompt, PromptEvent, Text},
ui::{self, overlay::overlayed, picker, FilePicker, Picker, Popup, Prompt, PromptEvent, Text},
};
use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion};
use helix_dap::{self as dap, Client};
Expand Down Expand Up @@ -52,7 +52,12 @@ fn thread_picker(
)
.into()
},
move |cx, thread, _action| callback_fn(cx.editor, thread),
move |cx, thread, _action| {
if let Some(thread) = thread {
callback_fn(cx.editor, thread)
}
picker::close_picker()
},
move |editor, thread| {
let frames = editor.debugger.as_ref()?.stack_frames.get(&thread.id)?;
let frame = frames.get(0)?;
Expand Down Expand Up @@ -245,16 +250,19 @@ pub fn dap_launch(cx: &mut Context) {
templates,
|template| template.name.as_str().into(),
|cx, template, _action| {
let completions = template.completion.clone();
let name = template.name.clone();
let callback = Box::pin(async move {
let call: Callback = Box::new(move |_editor, compositor| {
let prompt = debug_parameter_prompt(completions, name, Vec::new());
compositor.push(Box::new(prompt));
if let Some(template) = template {
let completions = template.completion.clone();
let name = template.name.clone();
let callback = Box::pin(async move {
let call: Callback = Box::new(move |_editor, compositor| {
let prompt = debug_parameter_prompt(completions, name, Vec::new());
compositor.push(Box::new(prompt));
});
Ok(call)
});
Ok(call)
});
cx.jobs.callback(callback);
cx.jobs.callback(callback);
}
picker::close_picker()
},
))));
}
Expand Down Expand Up @@ -654,19 +662,25 @@ pub fn dap_switch_stack_frame(cx: &mut Context) {
frames,
|frame| frame.name.as_str().into(), // TODO: include thread_states in the label
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);
if let Some(frame) = frame {
let debugger = match &mut cx.editor.debugger {
Some(debugger) => debugger,
None => return picker::close_picker(),
};
// 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);
}
}
picker::close_picker()
},
move |_editor, frame| {
frame
Expand Down
38 changes: 22 additions & 16 deletions helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use helix_view::editor::Action;

use crate::{
compositor::{self, Compositor},
ui::{self, overlay::overlayed, FileLocation, FilePicker, Popup, PromptEvent},
ui::{self, overlay::overlayed, picker, FileLocation, FilePicker, Popup, PromptEvent},
};

use std::borrow::Cow;
Expand Down Expand Up @@ -85,23 +85,26 @@ fn sym_picker(
}
},
move |cx, symbol, action| {
if current_path2.as_ref() == Some(&symbol.location.uri) {
push_jump(cx.editor);
} else {
let path = symbol.location.uri.to_file_path().unwrap();
cx.editor.open(path, action).expect("editor.open failed");
}
if let Some(symbol) = symbol {
if current_path2.as_ref() == Some(&symbol.location.uri) {
push_jump(cx.editor);
} else {
let path = symbol.location.uri.to_file_path().unwrap();
cx.editor.open(path, action).expect("editor.open failed");
}

let (view, doc) = current!(cx.editor);
let (view, doc) = current!(cx.editor);

if let Some(range) =
lsp_range_to_range(doc.text(), symbol.location.range, 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);
if let Some(range) =
lsp_range_to_range(doc.text(), symbol.location.range, 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);
}
}
picker::close_picker()
},
move |_editor, symbol| Some(location_to_file_location(&symbol.location)),
)
Expand Down Expand Up @@ -483,7 +486,10 @@ fn goto_impl(
format!("{}:{}", file, line).into()
},
move |cx, location, action| {
jump_to_location(cx.editor, location, offset_encoding, action)
if let Some(location) = location {
jump_to_location(cx.editor, location, offset_encoding, action);
}
picker::close_picker()
},
move |_editor, location| Some(location_to_file_location(location)),
);
Expand Down
37 changes: 25 additions & 12 deletions helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod info;
mod markdown;
pub mod menu;
pub mod overlay;
mod picker;
pub mod picker;
mod popup;
mod prompt;
mod spinner;
Expand All @@ -20,6 +20,7 @@ pub use prompt::{Prompt, PromptEvent};
pub use spinner::{ProgressSpinners, Spinner};
pub use text::Text;

use crate::compositor::{Compositor, EventResult};
use helix_core::regex::Regex;
use helix_core::regex::RegexBuilder;
use helix_view::{Document, Editor, View};
Expand Down Expand Up @@ -180,10 +181,13 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
// format_fn
path.strip_prefix(&root).unwrap_or(path).to_string_lossy()
},
move |cx, path: &PathBuf, action| {
cx.editor
.open(path.into(), action)
.expect("editor.open failed");
move |cx, path, action| {
if let Some(path) = path {
cx.editor
.open(path.into(), action)
.expect("editor.open failed");
}
picker::close_picker()
},
|_editor, path| Some((path.clone(), None)),
)
Expand All @@ -206,14 +210,23 @@ pub fn find_file_picker(dir: PathBuf, config: &helix_view::editor::Config) -> Fi
path.strip_prefix(&dir).unwrap_or(path).to_string_lossy() + suffix
},
move |cx, path, action| {
if path.is_dir() {
let _picker = find_file_picker(path.to_path_buf(), &config);
todo!("recurse picker, probably need to change how handle_event close_fn works");
} else {
cx.editor
.open(path.into(), action)
.expect("editor.open failed");
if let Some(path) = path {
if path.is_dir() {
let picker = find_file_picker(path.to_path_buf(), &config);
return EventResult::Consumed(Some(Box::new(
|compositor: &mut Compositor, _| {
// remove the layer
compositor.last_picker = compositor.pop();
compositor.push(Box::new(overlay::overlayed(picker)));
},
)));
} else {
cx.editor
.open(path.into(), action)
.expect("editor.open failed");
}
}
picker::close_picker()
},
|_editor, path| Some((path.clone(), None)),
)
Expand Down
36 changes: 15 additions & 21 deletions helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ pub const MIN_AREA_WIDTH_FOR_PREVIEW: u16 = 72;
/// Biggest file size to preview in bytes
pub const MAX_FILE_SIZE_FOR_PREVIEW: u64 = 10 * 1024 * 1024;

/// Helper function to close compositor for [`Picker`] `callback_fn`.
pub fn close_picker() -> EventResult {
EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| {
// remove the layer
compositor.last_picker = compositor.pop();
})))
}

pub enum CachedPreview {
Document(Box<Document>),
Binary,
Expand Down Expand Up @@ -88,7 +96,7 @@ impl<T> FilePicker<T> {
pub fn new(
options: Vec<T>,
format_fn: impl Fn(&T) -> Cow<str> + 'static,
callback_fn: impl Fn(&mut Context, &T, Action) + 'static,
callback_fn: impl Fn(&mut Context, Option<&T>, Action) -> EventResult + 'static,
preview_fn: impl Fn(&Editor, &T) -> Option<FileLocation> + 'static,
) -> Self {
let truncate_start = true;
Expand Down Expand Up @@ -303,14 +311,14 @@ pub struct Picker<T> {
pub truncate_start: bool,

format_fn: Box<dyn Fn(&T) -> Cow<str>>,
callback_fn: Box<dyn Fn(&mut Context, &T, Action)>,
callback_fn: Box<dyn Fn(&mut Context, Option<&T>, Action) -> EventResult>,
}

impl<T> Picker<T> {
pub fn new(
options: Vec<T>,
format_fn: impl Fn(&T) -> Cow<str> + 'static,
callback_fn: impl Fn(&mut Context, &T, Action) + 'static,
callback_fn: impl Fn(&mut Context, Option<&T>, Action) -> EventResult + 'static,
) -> Self {
let prompt = Prompt::new(
"".into(),
Expand Down Expand Up @@ -493,11 +501,6 @@ impl<T: 'static> Component for Picker<T> {
_ => return EventResult::Ignored(None),
};

let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| {
// remove the layer
compositor.last_picker = compositor.pop();
})));

match key_event.into() {
shift!(Tab) | key!(Up) | ctrl!('p') => {
self.move_by(1, Direction::Backward);
Expand All @@ -518,25 +521,16 @@ impl<T: 'static> Component for Picker<T> {
self.to_end();
}
key!(Esc) | ctrl!('c') => {
return close_fn;
return close_picker();
}
key!(Enter) => {
if let Some(option) = self.selection() {
(self.callback_fn)(cx, option, Action::Replace);
}
return close_fn;
return (self.callback_fn)(cx, self.selection(), Action::Replace);
}
ctrl!('s') => {
if let Some(option) = self.selection() {
(self.callback_fn)(cx, option, Action::HorizontalSplit);
}
return close_fn;
return (self.callback_fn)(cx, self.selection(), Action::HorizontalSplit);
}
ctrl!('v') => {
if let Some(option) = self.selection() {
(self.callback_fn)(cx, option, Action::VerticalSplit);
}
return close_fn;
return (self.callback_fn)(cx, self.selection(), Action::VerticalSplit);
}
ctrl!(' ') => {
self.save_filter(cx);
Expand Down

0 comments on commit 007f247

Please sign in to comment.