Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

helix-term/commands: implement buffer-close (bc, bclose) #1035

Merged
merged 17 commits into from
Nov 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 42 additions & 8 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1659,8 +1659,7 @@ mod cmd {
buffers_remaining_impl(cx.editor)?
}

cx.editor
.close(view!(cx.editor).id, /* close_buffer */ false);
cx.editor.close(view!(cx.editor).id);

Ok(())
}
Expand All @@ -1670,8 +1669,7 @@ mod cmd {
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
cx.editor
.close(view!(cx.editor).id, /* close_buffer */ false);
cx.editor.close(view!(cx.editor).id);

Ok(())
}
Expand All @@ -1689,6 +1687,28 @@ mod cmd {
Ok(())
}

fn buffer_close(
cole-h marked this conversation as resolved.
Show resolved Hide resolved
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
let view = view!(cx.editor);
let doc_id = view.doc;
cx.editor.close_document(doc_id, false)?;
Ok(())
}

fn force_buffer_close(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
let view = view!(cx.editor);
let doc_id = view.doc;
cx.editor.close_document(doc_id, true)?;
Ok(())
}

fn write_impl<P: AsRef<Path>>(
cx: &mut compositor::Context,
path: Option<P>,
Expand Down Expand Up @@ -1941,7 +1961,7 @@ mod cmd {
// close all views
let views: Vec<_> = cx.editor.tree.views().map(|(view, _)| view.id).collect();
for view_id in views {
cx.editor.close(view_id, false);
cx.editor.close(view_id);
}
}

Expand Down Expand Up @@ -1985,7 +2005,7 @@ mod cmd {
// close all views
let views: Vec<_> = editor.tree.views().map(|(view, _)| view.id).collect();
for view_id in views {
editor.close(view_id, false);
editor.close(view_id);
}

Ok(())
Expand Down Expand Up @@ -2278,6 +2298,20 @@ mod cmd {
fun: open,
completer: Some(completers::filename),
},
TypableCommand {
name: "buffer-close",
aliases: &["bc", "bclose"],
doc: "Close the current buffer.",
fun: buffer_close,
completer: None, // FIXME: buffer completer
cole-h marked this conversation as resolved.
Show resolved Hide resolved
},
TypableCommand {
name: "buffer-close!",
aliases: &["bc!", "bclose!"],
doc: "Close the current buffer forcefully (ignoring unsaved changes).",
fun: force_buffer_close,
completer: None, // FIXME: buffer completer
},
TypableCommand {
name: "write",
aliases: &["w"],
Expand Down Expand Up @@ -4740,7 +4774,7 @@ fn wclose(cx: &mut Context) {
}
let view_id = view!(cx.editor).id;
// close current split
cx.editor.close(view_id, /* close_buffer */ false);
cx.editor.close(view_id);
}

fn wonly(cx: &mut Context) {
Expand All @@ -4752,7 +4786,7 @@ fn wonly(cx: &mut Context) {
.collect::<Vec<_>>();
for (view_id, focus) in views {
if !focus {
cx.editor.close(view_id, /* close_buffer */ false);
cx.editor.close(view_id);
}
}
}
Expand Down
113 changes: 86 additions & 27 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use anyhow::Error;
pub use helix_core::diagnostic::Severity;
pub use helix_core::register::Registers;
use helix_core::syntax;
use helix_core::Position;
use helix_core::{Position, Selection};

use serde::Deserialize;

Expand Down Expand Up @@ -232,9 +232,28 @@ impl Editor {
}
}

fn replace_document_in_view(&mut self, current_view: ViewId, doc_id: DocumentId) {
let view = self.tree.get_mut(current_view);
view.doc = doc_id;
view.offset = Position::default();

let doc = self.documents.get_mut(&doc_id).unwrap();

// initialize selection for view
doc.selections
.entry(view.id)
.or_insert_with(|| Selection::point(0));
// TODO: reuse align_view
let pos = doc
.selection(view.id)
.primary()
.cursor(doc.text().slice(..));
let line = doc.text().char_to_line(pos);
view.offset.row = line.saturating_sub(view.inner_area().height as usize / 2);
}

pub fn switch(&mut self, id: DocumentId, action: Action) {
use crate::tree::Layout;
use helix_core::Selection;

if !self.documents.contains_key(&id) {
log::error!("cannot switch to document that does not exist (anymore)");
Expand Down Expand Up @@ -268,22 +287,9 @@ impl Editor {
view.jumps.push(jump);
view.last_accessed_doc = Some(view.doc);
}
view.doc = id;
view.offset = Position::default();

let (view, doc) = current!(self);

// initialize selection for view
doc.selections
.entry(view.id)
.or_insert_with(|| Selection::point(0));
// TODO: reuse align_view
let pos = doc
.selection(view.id)
.primary()
.cursor(doc.text().slice(..));
let line = doc.text().char_to_line(pos);
view.offset.row = line.saturating_sub(view.inner_area().height as usize / 2);
let view_id = view.id;
self.replace_document_in_view(view_id, id);

return;
}
Expand Down Expand Up @@ -315,11 +321,16 @@ impl Editor {
self._refresh();
}

fn new_file_from_document(&mut self, action: Action, mut document: Document) -> DocumentId {
fn new_document(&mut self, mut document: Document) -> DocumentId {
let id = DocumentId(self.next_document_id);
self.next_document_id += 1;
document.id = id;
self.documents.insert(id, document);
id
}

fn new_file_from_document(&mut self, action: Action, document: Document) -> DocumentId {
let id = self.new_document(document);
self.switch(id, action);
id
}
Expand Down Expand Up @@ -389,7 +400,7 @@ impl Editor {
Ok(id)
}

pub fn close(&mut self, id: ViewId, close_buffer: bool) {
pub fn close(&mut self, id: ViewId) {
let view = self.tree.get(self.tree.focus);
// remove selection
self.documents
Expand All @@ -398,18 +409,66 @@ impl Editor {
.selections
.remove(&id);

if close_buffer {
// get around borrowck issues
let doc = &self.documents[&view.doc];
self.tree.remove(id);
self._refresh();
}

if let Some(language_server) = doc.language_server() {
tokio::spawn(language_server.text_document_did_close(doc.identifier()));
}
self.documents.remove(&view.doc);
pub fn close_document(&mut self, doc_id: DocumentId, force: bool) -> anyhow::Result<()> {
let doc = match self.documents.get(&doc_id) {
Some(doc) => doc,
None => anyhow::bail!("document does not exist"),
};

if !force && doc.is_modified() {
anyhow::bail!(
"buffer {:?} is modified",
doc.relative_path()
.map(|path| path.to_string_lossy().to_string())
.unwrap_or_else(|| "[scratch]".into())
);
}

if let Some(language_server) = doc.language_server() {
tokio::spawn(language_server.text_document_did_close(doc.identifier()));
}

let views_to_close = self
.tree
.views()
.filter_map(|(view, _focus)| {
if view.doc == doc_id {
Some(view.id)
} else {
None
}
})
.collect::<Vec<_>>();

for view_id in views_to_close {
self.close(view_id);
}

self.documents.remove(&doc_id);

// If the document we removed was visible in all views, we will have no more views. We don't
// want to close the editor just for a simple buffer close, so we need to create a new view
// containing either an existing document, or a brand new document.
if self.tree.views().peekable().peek().is_none() {
let doc_id = self
.documents
.iter()
.map(|(&doc_id, _)| doc_id)
.next()
.unwrap_or_else(|| self.new_document(Document::default()));
let view = View::new(doc_id);
let view_id = self.tree.insert(view);
let doc = self.documents.get_mut(&doc_id).unwrap();
doc.selections.insert(view_id, Selection::point(0));
}

self.tree.remove(id);
self._refresh();

Ok(())
}

pub fn resize(&mut self, area: Rect) {
Expand Down
3 changes: 3 additions & 0 deletions helix-view/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,9 @@ impl Tree {

pub fn recalculate(&mut self) {
if self.is_empty() {
// There are no more views, so the tree should focus itself again.
self.focus = self.root;

return;
}

Expand Down
4 changes: 4 additions & 0 deletions helix-view/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ impl JumpList {
None
}
}

pub fn remove(&mut self, doc_id: &DocumentId) {
self.jumps.retain(|(other_id, _)| other_id != doc_id);
}
}

#[derive(Debug)]
Expand Down