editor.open can now either replace the current view or open in a split.

pull/11/head
Blaž Hrastnik 4 years ago
parent b24cdd1295
commit 8a0ab447ec

@ -39,7 +39,8 @@ impl Application {
let files = args.values_of_t::<PathBuf>("files").unwrap(); let files = args.values_of_t::<PathBuf>("files").unwrap();
for file in files { for file in files {
editor.open(file)?; use helix_view::editor::Action;
editor.open(file, Action::HorizontalSplit)?;
} }
compositor.push(Box::new(ui::EditorView::new())); compositor.push(Box::new(ui::EditorView::new()));

@ -798,7 +798,8 @@ pub fn command_mode(cx: &mut Context) {
// editor.should_close = true, // editor.should_close = true,
} }
["o", path] | ["open", path] => { ["o", path] | ["open", path] => {
editor.open(path.into()); use helix_view::editor::Action;
editor.open(path.into(), Action::Replace);
} }
["w"] | ["write"] => { ["w"] | ["write"] => {
// TODO: non-blocking via save() command // 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>) { fn goto(cx: &mut Context, locations: Vec<lsp::Location>) {
use helix_view::editor::Action;
cx.doc().mode = Mode::Normal; cx.doc().mode = Mode::Normal;
match locations.as_slice() { match locations.as_slice() {
[location] => { [location] => {
cx.editor.open(PathBuf::from(location.uri.path())); cx.editor
.open(PathBuf::from(location.uri.path()), Action::Replace);
let doc = cx.doc(); let doc = cx.doc();
let definition_pos = location.range.start; let definition_pos = location.range.start;
let new_pos = helix_lsp::util::lsp_pos_to_pos(doc.text(), definition_pos); 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() format!("{}:{}", file, line).into()
}, },
move |editor: &mut Editor, item| { 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 // TODO: issues with doc already being broo
let id = editor.view().doc; let id = editor.view().doc;
let doc = &mut editor.documents[id]; let doc = &mut editor.documents[id];

@ -101,7 +101,10 @@ pub fn file_picker(root: &str) -> Picker<PathBuf> {
path.strip_prefix("./").unwrap().to_str().unwrap().into() path.strip_prefix("./").unwrap().to_str().unwrap().into()
}, },
move |editor: &mut Editor, path: &PathBuf| { 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");
}, },
) )
} }

@ -16,6 +16,12 @@ pub struct Editor {
pub executor: &'static smol::Executor<'static>, pub executor: &'static smol::Executor<'static>,
} }
pub enum Action {
Replace,
HorizontalSplit,
VerticalSplit,
}
impl Editor { impl Editor {
pub fn new(executor: &'static smol::Executor<'static>, mut area: tui::layout::Rect) -> Self { pub fn new(executor: &'static smol::Executor<'static>, mut area: tui::layout::Rect) -> Self {
let theme = Theme::default(); let theme = Theme::default();
@ -41,50 +47,63 @@ impl Editor {
} }
} }
pub fn open(&mut self, path: PathBuf) -> Result<DocumentId, Error> { pub fn open(&mut self, path: PathBuf, action: Action) -> Result<DocumentId, Error> {
let existing_view = self.documents().find(|doc| doc.path() == Some(&path)); let id = self
.documents()
// TODO: .find(|doc| doc.path() == Some(&path))
// if view with doc, focus it .map(|doc| doc.id);
// else open new split
let id = if let Some(id) = id {
// if let Some((view, _)) = existing_view { id
// let id = view.doc.id; } else {
// self.tree.focus = view.id; let mut doc = Document::load(path, self.theme.scopes())?;
// return Ok(id);
// } // try to find a language server based on the language name
let language_server = doc
let mut doc = Document::load(path, self.theme.scopes())?; .language
.as_ref()
// try to find a language server based on the language name .and_then(|language| self.language_servers.get(language, self.executor));
let language_server = doc
.language if let Some(language_server) = language_server {
.as_ref() doc.set_language_server(Some(language_server.clone()));
.and_then(|language| self.language_servers.get(language, self.executor));
let language_id = doc
if let Some(language_server) = language_server { .language()
doc.set_language_server(Some(language_server.clone())); .and_then(|s| s.split('.').last()) // source.rust
.map(ToOwned::to_owned)
let language_id = doc .unwrap_or_default();
.language()
.and_then(|s| s.split('.').last()) // source.rust smol::block_on(language_server.text_document_did_open(
.map(ToOwned::to_owned) doc.url().unwrap(),
.unwrap_or_default(); doc.version(),
doc.text(),
smol::block_on(language_server.text_document_did_open( language_id,
doc.url().unwrap(), ))
doc.version(), .unwrap();
doc.text(), }
language_id,
)) let id = self.documents.insert(doc);
.unwrap(); 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(); self._refresh();
Ok(id) Ok(id)

@ -28,10 +28,10 @@ pub enum Content {
} }
impl Node { impl Node {
pub fn container() -> Self { pub fn container(layout: Layout) -> Self {
Node { Node {
parent: ViewId::default(), 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 // TODO: screen coord to container + container coordinate helpers
#[derive(PartialEq, Eq)]
pub enum Layout { pub enum Layout {
Horizontal, Horizontal,
Vertical, Vertical,
@ -58,9 +59,9 @@ pub struct Container {
} }
impl Container { impl Container {
pub fn new() -> Self { pub fn new(layout: Layout) -> Self {
Self { Self {
layout: Layout::Horizontal, layout,
children: Vec::new(), children: Vec::new(),
area: Rect::default(), area: Rect::default(),
} }
@ -69,13 +70,13 @@ impl Container {
impl Default for Container { impl Default for Container {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new(Layout::Horizontal)
} }
} }
impl Tree { impl Tree {
pub fn new(area: Rect) -> Self { pub fn new(area: Rect) -> Self {
let root = Node::container(); let root = Node::container(Layout::Horizontal);
let mut nodes = HopSlotMap::with_key(); let mut nodes = HopSlotMap::with_key();
let root = nodes.insert(root); let root = nodes.insert(root);
@ -131,6 +132,79 @@ impl Tree {
node 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) { pub fn remove(&mut self, index: ViewId) {
let mut stack = Vec::new(); let mut stack = Vec::new();

Loading…
Cancel
Save