Added pane open/close
This commit is contained in:
parent
81ab27cbbf
commit
84056b5a74
3 changed files with 100 additions and 2 deletions
23
README.md
Normal file
23
README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# ZTE
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [ ] Buffers
|
||||||
|
- [ ] Buffer switching
|
||||||
|
- [ ] Prompt
|
||||||
|
- [ ] Cursor selection
|
||||||
|
- [ ] Basic cursor movement
|
||||||
|
- [ ] Multiple panes
|
||||||
|
- [ ] Pane creation/deletion
|
||||||
|
|
||||||
|
## Todo
|
||||||
|
|
||||||
|
- [ ] Opener
|
||||||
|
- [ ] Find
|
||||||
|
- [ ] Replace
|
||||||
|
- [ ] Project search
|
||||||
|
- [ ] Search in buffer switcher
|
||||||
|
- [ ] File saving
|
||||||
|
- [ ] Syntax highlighting
|
||||||
|
- [ ] Auto-indent (and related features)
|
||||||
|
- [ ] Undo/redo
|
||||||
|
|
@ -15,6 +15,8 @@ pub enum Action {
|
||||||
Backspace, // Backspace a character
|
Backspace, // Backspace a character
|
||||||
Move(Dir, bool, bool), // Move the cursor (dir, page, retain_base)
|
Move(Dir, bool, bool), // Move the cursor (dir, page, retain_base)
|
||||||
PaneMove(Dir), // Move panes
|
PaneMove(Dir), // Move panes
|
||||||
|
PaneOpen(Dir), // Create a new pane
|
||||||
|
PaneClose, // Close the current pane
|
||||||
Cancel, // Cancels the current context
|
Cancel, // Cancels the current context
|
||||||
Go, // Search, accept, or select the current option
|
Go, // Search, accept, or select the current option
|
||||||
Yes, // A binary confirmation is answered 'yes'
|
Yes, // A binary confirmation is answered 'yes'
|
||||||
|
|
@ -26,6 +28,7 @@ pub enum Action {
|
||||||
SwitchBuffer(BufferId), // Switch the current pane to the given buffer
|
SwitchBuffer(BufferId), // Switch the current pane to the given buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
// The incoming event is an action generated by some other internal component.
|
// The incoming event is an action generated by some other internal component.
|
||||||
Action(Action),
|
Action(Action),
|
||||||
|
|
@ -49,6 +52,9 @@ impl Event {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ALT_SHIFT: KeyModifiers = KeyModifiers::ALT.union(KeyModifiers::SHIFT);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct RawEvent(TerminalEvent);
|
pub struct RawEvent(TerminalEvent);
|
||||||
|
|
||||||
impl RawEvent {
|
impl RawEvent {
|
||||||
|
|
@ -92,6 +98,40 @@ impl RawEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_pane_open(&self) -> Option<Dir> {
|
||||||
|
match &self.0 {
|
||||||
|
TerminalEvent::Key(KeyEvent {
|
||||||
|
code,
|
||||||
|
modifiers: ALT_SHIFT,
|
||||||
|
kind: KeyEventKind::Press | KeyEventKind::Repeat,
|
||||||
|
..
|
||||||
|
}) => match code {
|
||||||
|
KeyCode::Char('A') => Some(Dir::Left),
|
||||||
|
KeyCode::Char('D') => Some(Dir::Right),
|
||||||
|
KeyCode::Char('W') => Some(Dir::Up),
|
||||||
|
KeyCode::Char('S') => Some(Dir::Down),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_pane_close(&self) -> Option<Action> {
|
||||||
|
if matches!(
|
||||||
|
&self.0,
|
||||||
|
TerminalEvent::Key(KeyEvent {
|
||||||
|
code: KeyCode::Char('q'),
|
||||||
|
modifiers: KeyModifiers::ALT,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
Some(Action::PaneClose)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_move(&self) -> Option<Action> {
|
pub fn to_move(&self) -> Option<Action> {
|
||||||
let TerminalEvent::Key(KeyEvent {
|
let TerminalEvent::Key(KeyEvent {
|
||||||
code,
|
code,
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ impl Visual for Doc {
|
||||||
let line_num_w = buffer.text.lines().count().max(1).ilog10() as usize + 1;
|
let line_num_w = buffer.text.lines().count().max(1).ilog10() as usize + 1;
|
||||||
let margin_w = line_num_w + 2;
|
let margin_w = line_num_w + 2;
|
||||||
|
|
||||||
self.last_size = [frame.size()[0] - margin_w, frame.size()[1]];
|
self.last_size = [frame.size()[0].saturating_sub(margin_w), frame.size()[1]];
|
||||||
|
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
for (i, (line_num, (line_pos, line))) in buffer
|
for (i, (line_num, (line_pos, line))) in buffer
|
||||||
|
|
@ -184,12 +184,14 @@ impl Visual for Doc {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Pane {
|
pub enum Pane {
|
||||||
|
Empty,
|
||||||
Doc(Doc),
|
Doc(Doc),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pane {
|
impl Pane {
|
||||||
fn title(&self, state: &State) -> Option<String> {
|
fn title(&self, state: &State) -> Option<String> {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Empty => None,
|
||||||
Self::Doc(doc) => {
|
Self::Doc(doc) => {
|
||||||
let Some(buffer) = state.buffers.get(doc.buffer) else {
|
let Some(buffer) = state.buffers.get(doc.buffer) else {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -219,7 +221,12 @@ impl Panes {
|
||||||
|
|
||||||
impl Element for Panes {
|
impl Element for Panes {
|
||||||
fn handle(&mut self, state: &mut State, event: Event) -> Result<Resp, Event> {
|
fn handle(&mut self, state: &mut State, event: Event) -> Result<Resp, Event> {
|
||||||
match event.to_action(|e| e.to_pane_move().map(Action::PaneMove)) {
|
match event.to_action(|e| {
|
||||||
|
e.to_pane_move()
|
||||||
|
.map(Action::PaneMove)
|
||||||
|
.or_else(|| e.to_pane_open().map(Action::PaneOpen))
|
||||||
|
.or_else(|| e.to_pane_close())
|
||||||
|
}) {
|
||||||
Some(Action::PaneMove(Dir::Left)) => {
|
Some(Action::PaneMove(Dir::Left)) => {
|
||||||
self.selected = (self.selected + self.panes.len() - 1) % self.panes.len();
|
self.selected = (self.selected + self.panes.len() - 1) % self.panes.len();
|
||||||
Ok(Resp::handled(None))
|
Ok(Resp::handled(None))
|
||||||
|
|
@ -228,11 +235,38 @@ impl Element for Panes {
|
||||||
self.selected = (self.selected + 1) % self.panes.len();
|
self.selected = (self.selected + 1) % self.panes.len();
|
||||||
Ok(Resp::handled(None))
|
Ok(Resp::handled(None))
|
||||||
}
|
}
|
||||||
|
Some(Action::PaneClose) => {
|
||||||
|
if self.selected < self.panes.len() {
|
||||||
|
match self.panes.remove(self.selected) {
|
||||||
|
Pane::Empty => {}
|
||||||
|
Pane::Doc(doc) => doc.close(state),
|
||||||
|
}
|
||||||
|
self.selected = self.selected.clamp(0, self.panes.len().saturating_sub(1));
|
||||||
|
Ok(Resp::handled(None))
|
||||||
|
} else {
|
||||||
|
Err(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(Action::PaneOpen(dir)) => {
|
||||||
|
let new_idx = match dir {
|
||||||
|
Dir::Left => self.selected.saturating_sub(1).clamp(0, self.panes.len()),
|
||||||
|
Dir::Right => (self.selected + 1).min(self.panes.len()),
|
||||||
|
Dir::Up | Dir::Down => return Err(event),
|
||||||
|
};
|
||||||
|
let pane = match state.buffers.keys().next() {
|
||||||
|
Some(b) => Pane::Doc(Doc::new(state, b)),
|
||||||
|
None => Pane::Empty,
|
||||||
|
};
|
||||||
|
self.panes.insert(new_idx, pane);
|
||||||
|
self.selected = new_idx;
|
||||||
|
Ok(Resp::handled(None))
|
||||||
|
}
|
||||||
// Pass anything else through to the active pane
|
// Pass anything else through to the active pane
|
||||||
err => {
|
err => {
|
||||||
if let Some(pane) = self.panes.get_mut(self.selected) {
|
if let Some(pane) = self.panes.get_mut(self.selected) {
|
||||||
// Pass to pane
|
// Pass to pane
|
||||||
match pane {
|
match pane {
|
||||||
|
Pane::Empty => Err(event),
|
||||||
Pane::Doc(doc) => doc.handle(state, event),
|
Pane::Doc(doc) => doc.handle(state, event),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -266,6 +300,7 @@ impl Visual for Panes {
|
||||||
.with_border(border_theme, pane.title(state).as_deref())
|
.with_border(border_theme, pane.title(state).as_deref())
|
||||||
.with_focus(is_selected)
|
.with_focus(is_selected)
|
||||||
.with(|frame| match pane {
|
.with(|frame| match pane {
|
||||||
|
Pane::Empty => {}
|
||||||
Pane::Doc(doc) => doc.render(state, frame),
|
Pane::Doc(doc) => doc.render(state, frame),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue