aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-03-24 05:28:26 +0000
committerBlaž Hrastnik2021-03-24 05:28:26 +0000
commit8a0ab447ecfa6c2c448603d469ba4fd06e95c754 (patch)
tree9bf78106dbc54d02f7938d287467da44feaffe9d
parentb24cdd1295d1129dc730e02da2c6723938220d7e (diff)
editor.open can now either replace the current view or open in a split.
-rw-r--r--helix-term/src/application.rs3
-rw-r--r--helix-term/src/commands.rs9
-rw-r--r--helix-term/src/ui/mod.rs5
-rw-r--r--helix-view/src/editor.rs103
-rw-r--r--helix-view/src/tree.rs86
5 files changed, 153 insertions, 53 deletions
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index 38c0d88a..dcc6433b 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -39,7 +39,8 @@ impl Application {
let files = args.values_of_t::<PathBuf>("files").unwrap();
for file in files {
- editor.open(file)?;
+ use helix_view::editor::Action;
+ editor.open(file, Action::HorizontalSplit)?;
}
compositor.push(Box::new(ui::EditorView::new()));
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 9544b0e0..12d80a0f 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -798,7 +798,8 @@ pub fn command_mode(cx: &mut Context) {
// editor.should_close = true,
}
["o", path] | ["open", path] => {
- editor.open(path.into());
+ use helix_view::editor::Action;
+ editor.open(path.into(), Action::Replace);
}
["w"] | ["write"] => {
// TODO: non-blocking via save() command
@@ -992,11 +993,13 @@ pub fn exit_select_mode(cx: &mut Context) {
}
fn goto(cx: &mut Context, locations: Vec<lsp::Location>) {
+ use helix_view::editor::Action;
cx.doc().mode = Mode::Normal;
match locations.as_slice() {
[location] => {
- cx.editor.open(PathBuf::from(location.uri.path()));
+ cx.editor
+ .open(PathBuf::from(location.uri.path()), Action::Replace);
let doc = cx.doc();
let definition_pos = location.range.start;
let new_pos = helix_lsp::util::lsp_pos_to_pos(doc.text(), definition_pos);
@@ -1012,7 +1015,7 @@ fn goto(cx: &mut Context, locations: Vec<lsp::Location>) {
format!("{}:{}", file, line).into()
},
move |editor: &mut Editor, item| {
- editor.open(PathBuf::from(item.uri.path()));
+ editor.open(PathBuf::from(item.uri.path()), Action::Replace);
// TODO: issues with doc already being broo
let id = editor.view().doc;
let doc = &mut editor.documents[id];
diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs
index f91a9f35..a625aa14 100644
--- a/helix-term/src/ui/mod.rs
+++ b/helix-term/src/ui/mod.rs
@@ -101,7 +101,10 @@ pub fn file_picker(root: &str) -> Picker<PathBuf> {
path.strip_prefix("./").unwrap().to_str().unwrap().into()
},
move |editor: &mut Editor, path: &PathBuf| {
- let document_id = editor.open(path.into()).expect("editor.open failed");
+ use helix_view::editor::Action;
+ let document_id = editor
+ .open(path.into(), Action::Replace)
+ .expect("editor.open failed");
},
)
}
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index 0407f344..a2c3c101 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -16,6 +16,12 @@ pub struct Editor {
pub executor: &'static smol::Executor<'static>,
}
+pub enum Action {
+ Replace,
+ HorizontalSplit,
+ VerticalSplit,
+}
+
impl Editor {
pub fn new(executor: &'static smol::Executor<'static>, mut area: tui::layout::Rect) -> Self {
let theme = Theme::default();
@@ -41,50 +47,63 @@ impl Editor {
}
}
- pub fn open(&mut self, path: PathBuf) -> Result<DocumentId, Error> {
- let existing_view = self.documents().find(|doc| doc.path() == Some(&path));
-
- // TODO:
- // if view with doc, focus it
- // else open new split
-
- // if let Some((view, _)) = existing_view {
- // let id = view.doc.id;
- // self.tree.focus = view.id;
- // return Ok(id);
- // }
-
- let mut doc = Document::load(path, self.theme.scopes())?;
-
- // try to find a language server based on the language name
- let language_server = doc
- .language
- .as_ref()
- .and_then(|language| self.language_servers.get(language, self.executor));
-
- if let Some(language_server) = language_server {
- doc.set_language_server(Some(language_server.clone()));
-
- let language_id = doc
- .language()
- .and_then(|s| s.split('.').last()) // source.rust
- .map(ToOwned::to_owned)
- .unwrap_or_default();
-
- smol::block_on(language_server.text_document_did_open(
- doc.url().unwrap(),
- doc.version(),
- doc.text(),
- language_id,
- ))
- .unwrap();
+ pub fn open(&mut self, path: PathBuf, action: Action) -> Result<DocumentId, Error> {
+ let id = self
+ .documents()
+ .find(|doc| doc.path() == Some(&path))
+ .map(|doc| doc.id);
+
+ let id = if let Some(id) = id {
+ id
+ } else {
+ let mut doc = Document::load(path, self.theme.scopes())?;
+
+ // try to find a language server based on the language name
+ let language_server = doc
+ .language
+ .as_ref()
+ .and_then(|language| self.language_servers.get(language, self.executor));
+
+ if let Some(language_server) = language_server {
+ doc.set_language_server(Some(language_server.clone()));
+
+ let language_id = doc
+ .language()
+ .and_then(|s| s.split('.').last()) // source.rust
+ .map(ToOwned::to_owned)
+ .unwrap_or_default();
+
+ smol::block_on(language_server.text_document_did_open(
+ doc.url().unwrap(),
+ doc.version(),
+ doc.text(),
+ language_id,
+ ))
+ .unwrap();
+ }
+
+ let id = self.documents.insert(doc);
+ self.documents[id].id = id;
+ id
+ };
+
+ use crate::tree::Layout;
+ match action {
+ Action::Replace => {
+ self.view_mut().doc = id;
+ // TODO: reset selection?
+ return Ok(id);
+ }
+ Action::HorizontalSplit => {
+ let view = View::new(id)?;
+ self.tree.split(view, Layout::Horizontal);
+ }
+ Action::VerticalSplit => {
+ let view = View::new(id)?;
+ self.tree.split(view, Layout::Vertical);
+ }
}
- let id = self.documents.insert(doc);
- self.documents[id].id = id;
-
- let view = View::new(id)?;
- self.tree.insert(view);
self._refresh();
Ok(id)
diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs
index 4751f840..f7ef7806 100644
--- a/helix-view/src/tree.rs
+++ b/helix-view/src/tree.rs
@@ -28,10 +28,10 @@ pub enum Content {
}
impl Node {
- pub fn container() -> Self {
+ pub fn container(layout: Layout) -> Self {
Node {
parent: ViewId::default(),
- content: Content::Container(Box::new(Container::new())),
+ content: Content::Container(Box::new(Container::new(layout))),
}
}
@@ -45,6 +45,7 @@ impl Node {
// TODO: screen coord to container + container coordinate helpers
+#[derive(PartialEq, Eq)]
pub enum Layout {
Horizontal,
Vertical,
@@ -58,9 +59,9 @@ pub struct Container {
}
impl Container {
- pub fn new() -> Self {
+ pub fn new(layout: Layout) -> Self {
Self {
- layout: Layout::Horizontal,
+ layout,
children: Vec::new(),
area: Rect::default(),
}
@@ -69,13 +70,13 @@ impl Container {
impl Default for Container {
fn default() -> Self {
- Self::new()
+ Self::new(Layout::Horizontal)
}
}
impl Tree {
pub fn new(area: Rect) -> Self {
- let root = Node::container();
+ let root = Node::container(Layout::Horizontal);
let mut nodes = HopSlotMap::with_key();
let root = nodes.insert(root);
@@ -131,6 +132,79 @@ impl Tree {
node
}
+ pub fn split(&mut self, view: View, layout: Layout) -> ViewId {
+ let focus = self.focus;
+ let parent = self.nodes[focus].parent;
+
+ let node = Node::view(view);
+ let node = self.nodes.insert(node);
+ self.get_mut(node).id = node;
+
+ let container = match &mut self.nodes[parent] {
+ Node {
+ content: Content::Container(container),
+ ..
+ } => container,
+ _ => unreachable!(),
+ };
+
+ if container.layout == layout {
+ // insert node after the current item if there is children already
+ let pos = if container.children.is_empty() {
+ 0
+ } else {
+ let pos = container
+ .children
+ .iter()
+ .position(|&child| child == focus)
+ .unwrap();
+ pos + 1
+ };
+ container.children.insert(pos, node);
+ self.nodes[node].parent = parent;
+ } else {
+ let split = Node::container(layout);
+ let split = self.nodes.insert(split);
+
+ let container = match &mut self.nodes[split] {
+ Node {
+ content: Content::Container(container),
+ ..
+ } => container,
+ _ => unreachable!(),
+ };
+ container.children.push(focus);
+ container.children.push(node);
+ self.nodes[focus].parent = split;
+ self.nodes[node].parent = split;
+
+ let container = match &mut self.nodes[parent] {
+ Node {
+ content: Content::Container(container),
+ ..
+ } => container,
+ _ => unreachable!(),
+ };
+
+ let pos = container
+ .children
+ .iter()
+ .position(|&child| child == focus)
+ .unwrap();
+
+ // replace focus on parent with split
+ container.children[pos] = split;
+ }
+
+ // focus the new node
+ self.focus = node;
+
+ // recalculate all the sizes
+ self.recalculate();
+
+ node
+ }
+
pub fn remove(&mut self, index: ViewId) {
let mut stack = Vec::new();