on master help sign in
ui: buffer picker on ctrl-b
3d3295bBlaž Hrastnik
helix-term/src/commands.rs+50−35
@@ -297,9 +297,11 @@ pub fn split_selection(cx: &mut Context) {
297 },
297 },
298 );
298 );
299
299
300+ cx.callback = Some(Box::new(
300− cx.callback = Some(Box::new(move |compositor: &mut Compositor| {
301+ move |compositor: &mut Compositor, editor: &mut Editor| {
301− compositor.push(Box::new(prompt));
302+ compositor.push(Box::new(prompt));
303+ },
302− }));
304+ ));
303}
305}
304
306
305pub fn split_selection_on_newline(cx: &mut Context) {
307pub fn split_selection_on_newline(cx: &mut Context) {
@@ -399,12 +401,13 @@ pub fn append_mode(cx: &mut Context) {
399
401
400// TODO: I, A, o and O can share a lot of the primitives.
402// TODO: I, A, o and O can share a lot of the primitives.
401pub fn command_mode(cx: &mut Context) {
403pub fn command_mode(cx: &mut Context) {
402− cx.callback = Some(Box::new(|compositor: &mut Compositor| {
404+ cx.callback = Some(Box::new(
405+ |compositor: &mut Compositor, editor: &mut Editor| {
403− let prompt = Prompt::new(
406+ let prompt = Prompt::new(
404− ":".to_owned(),
407+ ":".to_owned(),
405− |_input: &str| {
408+ |_input: &str| {
406− // TODO: i need this duplicate list right now to avoid borrow checker issues
409+ // TODO: i need this duplicate list right now to avoid borrow checker issues
407− let command_list = vec![
410+ let command_list = vec![
408 String::from("q"),
411 String::from("q"),
409 String::from("aaa"),
412 String::from("aaa"),
410 String::from("bbb"),
413 String::from("bbb"),
@@ -437,37 +440,49 @@ pub fn command_mode(cx: &mut Context) {
437 String::from("ddd"),
440 String::from("ddd"),
438 String::from("eee"),
441 String::from("eee"),
439 ];
442 ];
440− command_list
443+ command_list
441− .into_iter()
444+ .into_iter()
442− .filter(|command| command.contains(_input))
445+ .filter(|command| command.contains(_input))
443− .collect()
446+ .collect()
444− }, // completion
447+ }, // completion
445− |editor: &mut Editor, input: &str, event: PromptEvent| {
448+ |editor: &mut Editor, input: &str, event: PromptEvent| {
446− if event != PromptEvent::Validate {
449+ if event != PromptEvent::Validate {
447− return;
450+ return;
448− }
451+ }
449
452
450− let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
453+ let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
451
454
452− match parts.as_slice() {
455+ match parts.as_slice() {
453− &["q"] => editor.should_close = true,
456+ &["q"] => editor.should_close = true,
454− &["o", path] => {
457+ &["o", path] => {
455− // TODO: make view()/view_mut() always contain a view.
458+ // TODO: make view()/view_mut() always contain a view.
456− let size = editor.view().unwrap().size;
459+ let size = editor.view().unwrap().size;
457− editor.open(path.into(), size);
460+ editor.open(path.into(), size);
461+ }
462+ _ => (),
458 }
463 }
459− _ => (),
460− }
464+ },
461− },
462− );
465+ );
463− compositor.push(Box::new(prompt));
466+ compositor.push(Box::new(prompt));
467+ },
464− }));
468+ ));
465}
469}
466pub fn file_picker(cx: &mut Context) {
470pub fn file_picker(cx: &mut Context) {
467− cx.callback = Some(Box::new(|compositor: &mut Compositor| {
471+ cx.callback = Some(Box::new(
472+ |compositor: &mut Compositor, editor: &mut Editor| {
468− let picker = ui::file_picker("./");
473+ let picker = ui::file_picker("./");
469− compositor.push(Box::new(picker));
474+ compositor.push(Box::new(picker));
475+ },
476+ ));
477+}
478+
479+pub fn buffer_picker(cx: &mut Context) {
480+ cx.callback = Some(Box::new(
481+ |compositor: &mut Compositor, editor: &mut Editor| {
482+ let picker = ui::buffer_picker(&editor.views, editor.focus);
483+ compositor.push(Box::new(picker));
484+ },
470− }));
485+ ));
471}
486}
472
487
473// calculate line numbers for each selection range
488// calculate line numbers for each selection range
helix-term/src/compositor.rs+2−2
@@ -19,7 +19,7 @@ use smol::Executor;
19use tui::buffer::Buffer as Surface;
19use tui::buffer::Buffer as Surface;
20use tui::layout::Rect;
20use tui::layout::Rect;
21
21
22−pub type Callback = Box<dyn FnOnce(&mut Compositor)>;
22+pub type Callback = Box<dyn FnOnce(&mut Compositor, &mut Editor)>;
23
23
24// --> EventResult should have a callback that takes a context with methods like .popup(),
24// --> EventResult should have a callback that takes a context with methods like .popup(),
25// .prompt() etc. That way we can abstract it from the renderer.
25// .prompt() etc. That way we can abstract it from the renderer.
@@ -128,7 +128,7 @@ impl Compositor {
128 if let Some(layer) = self.layers.last_mut() {
128 if let Some(layer) = self.layers.last_mut() {
129 return match layer.handle_event(event, cx) {
129 return match layer.handle_event(event, cx) {
130 EventResult::Consumed(Some(callback)) => {
130 EventResult::Consumed(Some(callback)) => {
131− callback(self);
131+ callback(self, cx.editor);
132 true
132 true
133 }
133 }
134 EventResult::Consumed(None) => true,
134 EventResult::Consumed(None) => true,
helix-term/src/keymap.rs+1
@@ -185,6 +185,7 @@ pub fn default() -> Keymaps {
185 vec![ctrl!('d')] => commands::half_page_down,
185 vec![ctrl!('d')] => commands::half_page_down,
186
186
187 vec![ctrl!('p')] => commands::file_picker,
187 vec![ctrl!('p')] => commands::file_picker,
188+ vec![ctrl!('b')] => commands::buffer_picker,
188 ),
189 ),
189 Mode::Insert => hashmap!(
190 Mode::Insert => hashmap!(
190 vec![Key {
191 vec![Key {
helix-term/src/ui/mod.rs+26−2
@@ -15,7 +15,7 @@ pub fn text_color() -> Style {
15 Style::default().fg(Color::Rgb(219, 191, 239)) // lilac
15 Style::default().fg(Color::Rgb(219, 191, 239)) // lilac
16}
16}
17
17
18−use std::path::PathBuf;
18+use std::path::{Path, PathBuf};
19pub fn file_picker(root: &str) -> Picker<PathBuf> {
19pub fn file_picker(root: &str) -> Picker<PathBuf> {
20 use ignore::Walk;
20 use ignore::Walk;
21 // TODO: determine root based on git root
21 // TODO: determine root based on git root
@@ -38,7 +38,7 @@ pub fn file_picker(root: &str) -> Picker<PathBuf> {
38 files.take(MAX).collect(),
38 files.take(MAX).collect(),
39 |path: &PathBuf| {
39 |path: &PathBuf| {
40 // format_fn
40 // format_fn
41− path.strip_prefix("./").unwrap().to_str().unwrap() // TODO: render paths without ./
41+ path.strip_prefix("./").unwrap().to_str().unwrap()
42 },
42 },
43 |editor: &mut Editor, path: &PathBuf| {
43 |editor: &mut Editor, path: &PathBuf| {
44 let size = editor.view().unwrap().size;
44 let size = editor.view().unwrap().size;
@@ -46,3 +46,27 @@ pub fn file_picker(root: &str) -> Picker<PathBuf> {
46 },
46 },
47 )
47 )
48}
48}
49+
50+use helix_view::View;
51+pub fn buffer_picker(views: &[View], current: usize) -> Picker<(Option<PathBuf>, usize)> {
52+ use helix_view::Editor;
53+ Picker::new(
54+ views
55+ .iter()
56+ .enumerate()
57+ .map(|(i, view)| (view.doc.relative_path().map(Path::to_path_buf), i))
58+ .collect(),
59+ |(path, index): &(Option<PathBuf>, usize)| {
60+ // format_fn
61+ match path {
62+ Some(path) => path.to_str().unwrap(),
63+ None => "[NEW]",
64+ }
65+ },
66+ |editor: &mut Editor, &(_, index): &(Option<PathBuf>, usize)| {
67+ if index < editor.views.len() {
68+ editor.focus = index;
69+ }
70+ },
71+ )
72+}
helix-term/src/ui/picker.rs+6−4
@@ -123,10 +123,12 @@ impl<T> Component for Picker<T> {
123 _ => return EventResult::Ignored,
123 _ => return EventResult::Ignored,
124 };
124 };
125
125
126− let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor| {
126+ let close_fn = EventResult::Consumed(Some(Box::new(
127+ |compositor: &mut Compositor, editor: &mut Editor| {
127− // remove the layer
128+ // remove the layer
128− compositor.pop();
129+ compositor.pop();
130+ },
129− })));
131+ )));
130
132
131 match key_event {
133 match key_event {
132 // KeyEvent {
134 // KeyEvent {
helix-term/src/ui/prompt.rs+6−4
@@ -167,10 +167,12 @@ impl Component for Prompt {
167 _ => return EventResult::Ignored,
167 _ => return EventResult::Ignored,
168 };
168 };
169
169
170− let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor| {
170+ let close_fn = EventResult::Consumed(Some(Box::new(
171+ |compositor: &mut Compositor, editor: &mut Editor| {
171− // remove the layer
172+ // remove the layer
172− compositor.pop();
173+ compositor.pop();
174+ },
173− })));
175+ )));
174
176
175 match event {
177 match event {
176 KeyEvent {
178 KeyEvent {