Moved opener/switcher to panes rather than root

This commit is contained in:
Joshua Barretto 2025-11-20 13:56:28 +00:00
parent cffa6fe487
commit c1caa5dc12
4 changed files with 89 additions and 42 deletions

View file

@ -24,6 +24,7 @@
- [ ] Terminal buffers
- [ ] Ability to resize panes (weighted sum?)
- [ ] Matching delimiter highlighting
- [ ] Ability to close buffers
## Issues to fix
@ -31,4 +32,5 @@
- Double click should select ident, not highlighted token
- Switcher search should allow searching whole path, not just parent
- Scroll drag should work in opener preview
- Switching buffers should preserve scroll position
- Switching buffers should preserve scroll position
- Allow opening directories immediately into the opener

View file

@ -6,9 +6,81 @@ pub enum PaneKind {
Doc(Doc),
}
enum PaneTask {
Opener(Opener),
Switcher(Switcher),
}
pub struct Pane {
kind: PaneKind,
last_area: Area,
task: Option<PaneTask>,
}
impl Element for Pane {
fn handle(&mut self, state: &mut State, event: Event) -> Result<Resp, Event> {
match event.to_action(|_| None) {
Some(Action::OpenOpener(path)) => {
self.task = Some(PaneTask::Opener(Opener::new(path)));
Ok(Resp::handled(None))
}
Some(Action::OpenSwitcher) => {
self.task = Some(PaneTask::Switcher(Switcher::new(state.most_recent())));
Ok(Resp::handled(None))
}
_ => {
let event = if let Some(task) = &mut self.task {
let resp = match task {
PaneTask::Opener(opener) => opener.handle(state, event),
PaneTask::Switcher(switcher) => switcher.handle(state, event),
};
match resp {
Ok(resp) => {
if resp.is_end() {
self.task = None;
}
return Ok(Resp::handled(resp.event));
}
Err(event) => event,
}
} else {
event
};
match &mut self.kind {
PaneKind::Empty => Err(event),
PaneKind::Doc(doc) => doc.handle(state, event),
}
}
}
}
}
impl Visual for Pane {
fn render(&mut self, state: &State, frame: &mut Rect) {
let remaining_space = match &mut self.task {
Some(PaneTask::Opener(opener)) => {
opener.render(state, frame);
None
}
Some(PaneTask::Switcher(switcher)) => {
let switcher_h = switcher.requested_height();
switcher.render(
state,
&mut frame.rect([0, frame.size()[1] - switcher_h], [!0, !0]),
);
Some(([0, 0], [!0, frame.size()[1] - switcher_h]))
}
None => Some(([0, 0], [!0, !0])),
};
if let Some((pos, sz)) = remaining_space {
match &mut self.kind {
PaneKind::Empty => {}
PaneKind::Doc(doc) => doc.render(state, &mut frame.rect(pos, sz)),
}
}
}
}
pub struct HBox {
@ -64,6 +136,7 @@ impl Element<()> for HBox {
Pane {
kind,
last_area: Area::default(),
task: None,
},
);
self.selected = new_idx;
@ -75,15 +148,9 @@ impl Element<()> for HBox {
if matches!(m_action, MouseAction::Click) {
self.selected = i;
}
match &mut pane.kind {
PaneKind::Doc(doc) => {
return doc
.handle(state, action.clone().into())
.map(Resp::into_can_end);
}
PaneKind::Empty => {}
}
break;
return pane
.handle(state, action.clone().into())
.map(Resp::into_can_end);
}
}
Ok(Resp::handled(None))
@ -92,10 +159,7 @@ impl Element<()> for HBox {
_ => {
if let Some(pane) = self.panes.get_mut(self.selected) {
// Pass to pane
match &mut pane.kind {
PaneKind::Empty => Err(event),
PaneKind::Doc(doc) => doc.handle(state, event).map(Resp::into_can_end),
}
pane.handle(state, event).map(Resp::into_can_end)
} else {
// No active pane, don't handle
Err(event)
@ -122,10 +186,7 @@ impl Visual for HBox {
.with_focus(self.selected == i)
.with(|frame| {
pane.last_area = frame.area();
match &mut pane.kind {
PaneKind::Empty => {}
PaneKind::Doc(doc) => doc.render(state, frame),
}
pane.render(state, frame);
});
}
}
@ -148,6 +209,7 @@ impl Panes {
panes: vec![Pane {
kind: PaneKind::Doc(Doc::new(state, *b)),
last_area: Area::default(),
task: None,
}],
last_area: Area::default(),
})
@ -199,6 +261,7 @@ impl Element for Panes {
panes: vec![Pane {
kind,
last_area: Area::default(),
task: None,
}],
last_area: Area::default(),
},

View file

@ -537,13 +537,12 @@ impl Visual for Opener {
});
let path_input_sz = 3;
let remaining_sz = frame.size()[1].saturating_sub(path_input_sz);
let (preview_sz, options_sz) = if remaining_sz > 12 {
let preview_sz = remaining_sz / 2;
(preview_sz, remaining_sz - preview_sz)
} else {
(0, remaining_sz)
};
let options_sz = self
.options
.requested_height()
.max(1)
.min(frame.size()[1] * 2 / 3);
let preview_sz = frame.size()[1].saturating_sub(options_sz);
if let Some((buffer, cursor_id, input)) = &mut self.preview {
frame.rect([0, 0], [frame.size()[0], preview_sz]).with(|f| {

View file

@ -12,8 +12,6 @@ pub enum Task {
Prompt(Prompt),
Show(Show),
Confirm(Confirm),
Switcher(Switcher),
Opener(Opener),
Searcher(Searcher),
}
@ -23,8 +21,6 @@ impl Task {
Self::Prompt(p) => p.requested_height(),
Self::Show(s) => s.requested_height(),
Self::Confirm(c) => c.requested_height(),
Self::Switcher(s) => s.requested_height(),
Self::Opener(o) => o.requested_height(),
Self::Searcher(s) => s.requested_height(),
}
}
@ -66,8 +62,6 @@ impl Element<()> for Root {
Task::Prompt(p) => p.handle(state, event),
Task::Show(s) => s.handle(state, event),
Task::Confirm(c) => c.handle(state, event),
Task::Switcher(s) => s.handle(state, event),
Task::Opener(o) => o.handle(state, event),
Task::Searcher(s) => s.handle(state, event),
};
@ -100,15 +94,6 @@ impl Element<()> for Root {
self.tasks.clear(); // Prompt overrides all
self.tasks.push(Task::Prompt(Prompt::new("")));
}
Action::OpenSwitcher => {
self.tasks.clear(); // Overrides all
self.tasks
.push(Task::Switcher(Switcher::new(state.most_recent())));
}
Action::OpenOpener(path) => {
self.tasks.clear(); // Overrides all
self.tasks.push(Task::Opener(Opener::new(path)));
}
Action::OpenSearcher(path, needle) => {
self.tasks.clear(); // Overrides all
self.tasks.push(Task::Searcher(Searcher::new(path, needle)));
@ -179,8 +164,6 @@ impl Visual for Root {
Task::Prompt(p) => p.render(state, frame),
Task::Show(s) => s.render(state, frame),
Task::Confirm(c) => c.render(state, frame),
Task::Switcher(s) => s.render(state, frame),
Task::Opener(o) => o.render(state, frame),
Task::Searcher(s) => s.render(state, frame),
});
}