Allow closing individual views.

imgbot
Blaž Hrastnik 3 years ago
parent 1e1dae1c11
commit 7877647cf0

@ -82,7 +82,7 @@ impl Application {
self.render(); self.render();
loop { loop {
if self.editor.should_close { if self.editor.should_close() {
break; break;
} }
@ -116,9 +116,8 @@ impl Application {
None => panic!(), None => panic!(),
}; };
if should_redraw { if should_redraw && !self.editor.should_close() {
self.render(); self.render();
// calling render twice here fixes it for some reason
} }
} }

@ -558,7 +558,10 @@ pub fn command_mode(cx: &mut Context) {
let parts = input.split_ascii_whitespace().collect::<Vec<&str>>(); let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
match *parts.as_slice() { match *parts.as_slice() {
["q"] => editor.should_close = true, ["q"] => {
editor.tree.remove(editor.view().id);
// editor.should_close = true,
}
["o", path] => { ["o", path] => {
editor.open(path.into(), executor); editor.open(path.into(), executor);
} }

@ -4,12 +4,13 @@ use crate::{Document, View};
use std::path::PathBuf; use std::path::PathBuf;
use slotmap::DefaultKey as Key;
use anyhow::Error; use anyhow::Error;
pub struct Editor { pub struct Editor {
pub tree: Tree, pub tree: Tree,
// pub documents: Vec<Document>, // pub documents: Vec<Document>,
pub should_close: bool,
pub count: Option<usize>, pub count: Option<usize>,
pub theme: Theme, // TODO: share one instance pub theme: Theme, // TODO: share one instance
pub language_servers: helix_lsp::Registry, pub language_servers: helix_lsp::Registry,
@ -25,7 +26,6 @@ impl Editor {
Self { Self {
tree: Tree::new(area), tree: Tree::new(area),
should_close: false,
count: None, count: None,
theme, theme,
language_servers, language_servers,
@ -54,10 +54,19 @@ impl Editor {
} }
let view = View::new(doc)?; let view = View::new(doc)?;
self.tree.insert(view); let id = self.tree.insert(view);
self.tree.get_mut(id).id = id;
Ok(()) Ok(())
} }
pub fn close(&mut self, id: Key) {
self.tree.remove(id)
}
pub fn should_close(&mut self) -> bool {
self.tree.is_empty()
}
pub fn view(&self) -> &View { pub fn view(&self) -> &View {
self.tree.get(self.tree.focus) self.tree.get(self.tree.focus)
} }

@ -7,7 +7,6 @@ use tui::layout::Rect;
pub struct Tree { pub struct Tree {
root: Key, root: Key,
// (container, index inside the container) // (container, index inside the container)
current: (Key, usize),
pub focus: Key, pub focus: Key,
// fullscreen: bool, // fullscreen: bool,
area: Rect, area: Rect,
@ -18,18 +17,29 @@ pub struct Tree {
stack: Vec<(Key, Rect)>, stack: Vec<(Key, Rect)>,
} }
pub enum Node { pub struct Node {
parent: Key,
content: Content,
}
pub enum Content {
View(Box<View>), View(Box<View>),
Container(Box<Container>), Container(Box<Container>),
} }
impl Node { impl Node {
pub fn container() -> Self { pub fn container() -> Self {
Self::Container(Box::new(Container::new())) Node {
parent: Key::default(),
content: Content::Container(Box::new(Container::new())),
}
} }
pub fn view(view: View) -> Self { pub fn view(view: View) -> Self {
Self::View(Box::new(view)) Node {
parent: Key::default(),
content: Content::View(Box::new(view)),
}
} }
} }
@ -66,13 +76,16 @@ impl Default for Container {
impl Tree { impl Tree {
pub fn new(area: Rect) -> Self { pub fn new(area: Rect) -> Self {
let root = Node::container(); let root = Node::container();
let mut nodes = HopSlotMap::new(); let mut nodes = HopSlotMap::new();
let root = nodes.insert(root); let root = nodes.insert(root);
// root is it's own parent
nodes[root].parent = root;
Self { Self {
root, root,
current: (root, 0), focus: root,
focus: Key::default(),
// fullscreen: false, // fullscreen: false,
area, area,
nodes, nodes,
@ -81,23 +94,34 @@ impl Tree {
} }
pub fn insert(&mut self, view: View) -> Key { pub fn insert(&mut self, view: View) -> Key {
let node = self.nodes.insert(Node::view(view)); let focus = self.focus;
let (id, pos) = self.current; let parent = self.nodes[focus].parent;
let container = match &mut self.nodes[id] { let mut node = Node::view(view);
Node::Container(container) => container, node.parent = parent;
let node = self.nodes.insert(node);
let container = match &mut self.nodes[parent] {
Node {
content: Content::Container(container),
..
} => container,
_ => unreachable!(), _ => unreachable!(),
}; };
// insert node after the current item if there is children already // insert node after the current item if there is children already
let pos = if container.children.is_empty() { let pos = if container.children.is_empty() {
pos 0
} else { } else {
let pos = container
.children
.iter()
.position(|&child| child == focus)
.unwrap();
pos + 1 pos + 1
}; };
container.children.insert(pos, node); container.children.insert(pos, node);
// focus the new node // focus the new node
self.current = (id, pos);
self.focus = node; self.focus = node;
// recalculate all the sizes // recalculate all the sizes
@ -106,26 +130,78 @@ impl Tree {
node node
} }
pub fn remove(&mut self, index: Key) {
let mut stack = Vec::new();
if self.focus == index {
// focus on something else
self.focus_next();
}
stack.push(index);
while let Some(index) = stack.pop() {
let parent_id = self.nodes[index].parent;
if let Node {
content: Content::Container(container),
..
} = &mut self.nodes[parent_id]
{
if let Some(pos) = container.children.iter().position(|&child| child == index) {
container.children.remove(pos);
// TODO: if container now only has one child, remove it and place child in parent
if container.children.is_empty() && parent_id != self.root {
// if container now empty, remove it
stack.push(parent_id);
}
}
}
self.nodes.remove(index);
}
self.recalculate()
}
pub fn views(&mut self) -> impl Iterator<Item = (&mut View, bool)> { pub fn views(&mut self) -> impl Iterator<Item = (&mut View, bool)> {
let focus = self.focus; let focus = self.focus;
self.nodes self.nodes
.iter_mut() .iter_mut()
.filter_map(move |(key, node)| match node { .filter_map(move |(key, node)| match node {
Node::View(view) => Some((view.as_mut(), focus == key)), Node {
Node::Container(..) => None, content: Content::View(view),
..
} => Some((view.as_mut(), focus == key)),
_ => None,
}) })
} }
pub fn get(&self, index: Key) -> &View { pub fn get(&self, index: Key) -> &View {
match &self.nodes[index] { match &self.nodes[index] {
Node::View(view) => view, Node {
content: Content::View(view),
..
} => view,
_ => unreachable!(), _ => unreachable!(),
} }
} }
pub fn get_mut(&mut self, index: Key) -> &mut View { pub fn get_mut(&mut self, index: Key) -> &mut View {
match &mut self.nodes[index] { match &mut self.nodes[index] {
Node::View(view) => view, Node {
content: Content::View(view),
..
} => view,
_ => unreachable!(),
}
}
pub fn is_empty(&self) -> bool {
match &self.nodes[self.root] {
Node {
content: Content::Container(container),
..
} => container.children.is_empty(),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -136,6 +212,10 @@ impl Tree {
} }
pub fn recalculate(&mut self) { pub fn recalculate(&mut self) {
if self.is_empty() {
return;
}
self.stack.push((self.root, self.area)); self.stack.push((self.root, self.area));
// take the area // take the area
@ -146,12 +226,12 @@ impl Tree {
while let Some((key, area)) = self.stack.pop() { while let Some((key, area)) = self.stack.pop() {
let node = &mut self.nodes[key]; let node = &mut self.nodes[key];
match node { match &mut node.content {
Node::View(view) => { Content::View(view) => {
// debug!!("setting view area {:?}", area); // debug!!("setting view area {:?}", area);
view.area = area; view.area = area;
} // TODO: call f() } // TODO: call f()
Node::Container(container) => { Content::Container(container) => {
// debug!!("setting container area {:?}", area); // debug!!("setting container area {:?}", area);
container.area = area; container.area = area;
@ -263,9 +343,9 @@ impl<'a> Iterator for Traverse<'a> {
let node = &self.tree.nodes[key]; let node = &self.tree.nodes[key];
match node { match &node.content {
Node::View(view) => return Some((key, view)), Content::View(view) => return Some((key, view)),
Node::Container(container) => { Content::Container(container) => {
self.stack.extend(container.children.iter().rev()); self.stack.extend(container.children.iter().rev());
} }
} }

@ -8,6 +8,7 @@ use helix_core::{
indent::TAB_WIDTH, indent::TAB_WIDTH,
Position, RopeSlice, Position, RopeSlice,
}; };
use slotmap::DefaultKey as Key;
use tui::layout::Rect; use tui::layout::Rect;
pub const PADDING: usize = 5; pub const PADDING: usize = 5;
@ -15,6 +16,7 @@ pub const PADDING: usize = 5;
// TODO: view should be View { doc: Document(state, history,..) } // TODO: view should be View { doc: Document(state, history,..) }
// since we can have multiple views into the same file // since we can have multiple views into the same file
pub struct View { pub struct View {
pub id: Key,
pub doc: Document, pub doc: Document,
pub first_line: usize, pub first_line: usize,
pub area: Rect, pub area: Rect,
@ -24,6 +26,7 @@ pub struct View {
impl View { impl View {
pub fn new(doc: Document) -> Result<Self, Error> { pub fn new(doc: Document) -> Result<Self, Error> {
let view = Self { let view = Self {
id: Key::default(),
doc, doc,
first_line: 0, first_line: 0,
area: Rect::default(), // will get calculated upon inserting into tree area: Rect::default(), // will get calculated upon inserting into tree

Loading…
Cancel
Save