on master help sign in
Allow closing individual views.
7877647Blaž Hrastnik
helix-term/src/application.rs+2−3
@@ -82,7 +82,7 @@ impl Application {
82 self.render();
82 self.render();
83
83
84 loop {
84 loop {
85− if self.editor.should_close {
85+ if self.editor.should_close() {
86 break;
86 break;
87 }
87 }
88
88
@@ -116,9 +116,8 @@ impl Application {
116 None => panic!(),
116 None => panic!(),
117 };
117 };
118
118
119− if should_redraw {
119+ if should_redraw && !self.editor.should_close() {
120 self.render();
120 self.render();
121− // calling render twice here fixes it for some reason
122 }
121 }
123 }
122 }
124
123
helix-term/src/commands.rs+4−1
@@ -558,7 +558,10 @@ pub fn command_mode(cx: &mut Context) {
558 let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
558 let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
559
559
560 match *parts.as_slice() {
560 match *parts.as_slice() {
561+ ["q"] => {
562+ editor.tree.remove(editor.view().id);
561− ["q"] => editor.should_close = true,
563+ // editor.should_close = true,
564+ }
562 ["o", path] => {
565 ["o", path] => {
563 editor.open(path.into(), executor);
566 editor.open(path.into(), executor);
564 }
567 }
helix-view/src/editor.rs+12−3
@@ -4,12 +4,13 @@ use crate::{Document, View};
4
4
5use std::path::PathBuf;
5use std::path::PathBuf;
6
6
7+use slotmap::DefaultKey as Key;
8+
7use anyhow::Error;
9use anyhow::Error;
8
10
9pub struct Editor {
11pub struct Editor {
10 pub tree: Tree,
12 pub tree: Tree,
11 // pub documents: Vec<Document>,
13 // pub documents: Vec<Document>,
12− pub should_close: bool,
13 pub count: Option<usize>,
14 pub count: Option<usize>,
14 pub theme: Theme, // TODO: share one instance
15 pub theme: Theme, // TODO: share one instance
15 pub language_servers: helix_lsp::Registry,
16 pub language_servers: helix_lsp::Registry,
@@ -25,7 +26,6 @@ impl Editor {
25
26
26 Self {
27 Self {
27 tree: Tree::new(area),
28 tree: Tree::new(area),
28− should_close: false,
29 count: None,
29 count: None,
30 theme,
30 theme,
31 language_servers,
31 language_servers,
@@ -54,10 +54,19 @@ impl Editor {
54 }
54 }
55
55
56 let view = View::new(doc)?;
56 let view = View::new(doc)?;
57− self.tree.insert(view);
57+ let id = self.tree.insert(view);
58+ self.tree.get_mut(id).id = id;
58 Ok(())
59 Ok(())
59 }
60 }
60
61
62+ pub fn close(&mut self, id: Key) {
63+ self.tree.remove(id)
64+ }
65+
66+ pub fn should_close(&mut self) -> bool {
67+ self.tree.is_empty()
68+ }
69+
61 pub fn view(&self) -> &View {
70 pub fn view(&self) -> &View {
62 self.tree.get(self.tree.focus)
71 self.tree.get(self.tree.focus)
63 }
72 }
helix-view/src/tree.rs+102−22
@@ -7,7 +7,6 @@ use tui::layout::Rect;
7pub struct Tree {
7pub struct Tree {
8 root: Key,
8 root: Key,
9 // (container, index inside the container)
9 // (container, index inside the container)
10− current: (Key, usize),
11 pub focus: Key,
10 pub focus: Key,
12 // fullscreen: bool,
11 // fullscreen: bool,
13 area: Rect,
12 area: Rect,
@@ -18,18 +17,29 @@ pub struct Tree {
18 stack: Vec<(Key, Rect)>,
17 stack: Vec<(Key, Rect)>,
19}
18}
20
19
21−pub enum Node {
20+pub struct Node {
21+ parent: Key,
22+ content: Content,
23+}
24+
25+pub enum Content {
22 View(Box<View>),
26 View(Box<View>),
23 Container(Box<Container>),
27 Container(Box<Container>),
24}
28}
25
29
26impl Node {
30impl Node {
27 pub fn container() -> Self {
31 pub fn container() -> Self {
32+ Node {
33+ parent: Key::default(),
28− Self::Container(Box::new(Container::new()))
34+ content: Content::Container(Box::new(Container::new())),
35+ }
29 }
36 }
30
37
31 pub fn view(view: View) -> Self {
38 pub fn view(view: View) -> Self {
39+ Node {
40+ parent: Key::default(),
32− Self::View(Box::new(view))
41+ content: Content::View(Box::new(view)),
42+ }
33 }
43 }
34}
44}
35
45
@@ -66,13 +76,16 @@ impl Default for Container {
66impl Tree {
76impl Tree {
67 pub fn new(area: Rect) -> Self {
77 pub fn new(area: Rect) -> Self {
68 let root = Node::container();
78 let root = Node::container();
79+
69 let mut nodes = HopSlotMap::new();
80 let mut nodes = HopSlotMap::new();
70 let root = nodes.insert(root);
81 let root = nodes.insert(root);
71
82
83+ // root is it's own parent
84+ nodes[root].parent = root;
85+
72 Self {
86 Self {
73 root,
87 root,
74− current: (root, 0),
88+ focus: root,
75− focus: Key::default(),
76 // fullscreen: false,
89 // fullscreen: false,
77 area,
90 area,
78 nodes,
91 nodes,
@@ -81,23 +94,34 @@ impl Tree {
81 }
94 }
82
95
83 pub fn insert(&mut self, view: View) -> Key {
96 pub fn insert(&mut self, view: View) -> Key {
97+ let focus = self.focus;
98+ let parent = self.nodes[focus].parent;
99+ let mut node = Node::view(view);
100+ node.parent = parent;
84− let node = self.nodes.insert(Node::view(view));
101+ let node = self.nodes.insert(node);
85− let (id, pos) = self.current;
102+
86− let container = match &mut self.nodes[id] {
103+ let container = match &mut self.nodes[parent] {
104+ Node {
87− Node::Container(container) => container,
105+ content: Content::Container(container),
106+ ..
107+ } => container,
88 _ => unreachable!(),
108 _ => unreachable!(),
89 };
109 };
90
110
91 // insert node after the current item if there is children already
111 // insert node after the current item if there is children already
92 let pos = if container.children.is_empty() {
112 let pos = if container.children.is_empty() {
93− pos
113+ 0
94 } else {
114 } else {
115+ let pos = container
116+ .children
117+ .iter()
118+ .position(|&child| child == focus)
119+ .unwrap();
95 pos + 1
120 pos + 1
96 };
121 };
97
122
98 container.children.insert(pos, node);
123 container.children.insert(pos, node);
99 // focus the new node
124 // focus the new node
100− self.current = (id, pos);
101 self.focus = node;
125 self.focus = node;
102
126
103 // recalculate all the sizes
127 // recalculate all the sizes
@@ -106,26 +130,78 @@ impl Tree {
106 node
130 node
107 }
131 }
108
132
133+ pub fn remove(&mut self, index: Key) {
134+ let mut stack = Vec::new();
135+
136+ if self.focus == index {
137+ // focus on something else
138+ self.focus_next();
139+ }
140+
141+ stack.push(index);
142+
143+ while let Some(index) = stack.pop() {
144+ let parent_id = self.nodes[index].parent;
145+ if let Node {
146+ content: Content::Container(container),
147+ ..
148+ } = &mut self.nodes[parent_id]
149+ {
150+ if let Some(pos) = container.children.iter().position(|&child| child == index) {
151+ container.children.remove(pos);
152+
153+ // TODO: if container now only has one child, remove it and place child in parent
154+ if container.children.is_empty() && parent_id != self.root {
155+ // if container now empty, remove it
156+ stack.push(parent_id);
157+ }
158+ }
159+ }
160+ self.nodes.remove(index);
161+ }
162+
163+ self.recalculate()
164+ }
165+
109 pub fn views(&mut self) -> impl Iterator<Item = (&mut View, bool)> {
166 pub fn views(&mut self) -> impl Iterator<Item = (&mut View, bool)> {
110 let focus = self.focus;
167 let focus = self.focus;
111 self.nodes
168 self.nodes
112 .iter_mut()
169 .iter_mut()
113 .filter_map(move |(key, node)| match node {
170 .filter_map(move |(key, node)| match node {
171+ Node {
172+ content: Content::View(view),
173+ ..
114− Node::View(view) => Some((view.as_mut(), focus == key)),
174+ } => Some((view.as_mut(), focus == key)),
115− Node::Container(..) => None,
175+ _ => None,
116 })
176 })
117 }
177 }
118
178
119 pub fn get(&self, index: Key) -> &View {
179 pub fn get(&self, index: Key) -> &View {
120 match &self.nodes[index] {
180 match &self.nodes[index] {
181+ Node {
121− Node::View(view) => view,
182+ content: Content::View(view),
183+ ..
184+ } => view,
122 _ => unreachable!(),
185 _ => unreachable!(),
123 }
186 }
124 }
187 }
125
188
126 pub fn get_mut(&mut self, index: Key) -> &mut View {
189 pub fn get_mut(&mut self, index: Key) -> &mut View {
127 match &mut self.nodes[index] {
190 match &mut self.nodes[index] {
191+ Node {
128− Node::View(view) => view,
192+ content: Content::View(view),
193+ ..
194+ } => view,
195+ _ => unreachable!(),
196+ }
197+ }
198+
199+ pub fn is_empty(&self) -> bool {
200+ match &self.nodes[self.root] {
201+ Node {
202+ content: Content::Container(container),
203+ ..
204+ } => container.children.is_empty(),
129 _ => unreachable!(),
205 _ => unreachable!(),
130 }
206 }
131 }
207 }
@@ -136,6 +212,10 @@ impl Tree {
136 }
212 }
137
213
138 pub fn recalculate(&mut self) {
214 pub fn recalculate(&mut self) {
215+ if self.is_empty() {
216+ return;
217+ }
218+
139 self.stack.push((self.root, self.area));
219 self.stack.push((self.root, self.area));
140
220
141 // take the area
221 // take the area
@@ -146,12 +226,12 @@ impl Tree {
146 while let Some((key, area)) = self.stack.pop() {
226 while let Some((key, area)) = self.stack.pop() {
147 let node = &mut self.nodes[key];
227 let node = &mut self.nodes[key];
148
228
149− match node {
229+ match &mut node.content {
150− Node::View(view) => {
230+ Content::View(view) => {
151 // debug!!("setting view area {:?}", area);
231 // debug!!("setting view area {:?}", area);
152 view.area = area;
232 view.area = area;
153 } // TODO: call f()
233 } // TODO: call f()
154− Node::Container(container) => {
234+ Content::Container(container) => {
155 // debug!!("setting container area {:?}", area);
235 // debug!!("setting container area {:?}", area);
156 container.area = area;
236 container.area = area;
157
237
@@ -263,9 +343,9 @@ impl<'a> Iterator for Traverse<'a> {
263
343
264 let node = &self.tree.nodes[key];
344 let node = &self.tree.nodes[key];
265
345
266− match node {
346+ match &node.content {
267− Node::View(view) => return Some((key, view)),
347+ Content::View(view) => return Some((key, view)),
268− Node::Container(container) => {
348+ Content::Container(container) => {
269 self.stack.extend(container.children.iter().rev());
349 self.stack.extend(container.children.iter().rev());
270 }
350 }
271 }
351 }
helix-view/src/view.rs+3
@@ -8,6 +8,7 @@ use helix_core::{
8 indent::TAB_WIDTH,
8 indent::TAB_WIDTH,
9 Position, RopeSlice,
9 Position, RopeSlice,
10};
10};
11+use slotmap::DefaultKey as Key;
11use tui::layout::Rect;
12use tui::layout::Rect;
12
13
13pub const PADDING: usize = 5;
14pub const PADDING: usize = 5;
@@ -15,6 +16,7 @@ pub const PADDING: usize = 5;
15// TODO: view should be View { doc: Document(state, history,..) }
16// TODO: view should be View { doc: Document(state, history,..) }
16// since we can have multiple views into the same file
17// since we can have multiple views into the same file
17pub struct View {
18pub struct View {
19+ pub id: Key,
18 pub doc: Document,
20 pub doc: Document,
19 pub first_line: usize,
21 pub first_line: usize,
20 pub area: Rect,
22 pub area: Rect,
@@ -24,6 +26,7 @@ pub struct View {
24impl View {
26impl View {
25 pub fn new(doc: Document) -> Result<Self, Error> {
27 pub fn new(doc: Document) -> Result<Self, Error> {
26 let view = Self {
28 let view = Self {
29+ id: Key::default(),
27 doc,
30 doc,
28 first_line: 0,
31 first_line: 0,
29 area: Rect::default(), // will get calculated upon inserting into tree
32 area: Rect::default(), // will get calculated upon inserting into tree