@@ -22,7 +22,7 @@ use anyhow::Error;
2222pub use helix_core::diagnostic::Severity;
2323pub use helix_core::register::Registers;
2424use helix_core::syntax;
25−use helix_core::Position;
25+use helix_core::{Position, Selection};
2626
2727use serde::Deserialize;
2828
@@ -235,9 +235,28 @@ impl Editor {
235235 }
236236 }
237237
238+ fn replace_document_in_view(&mut self, current_view: ViewId, doc_id: DocumentId) {
239+ let view = self.tree.get_mut(current_view);
240+ view.doc = doc_id;
241+ view.offset = Position::default();
242+
243+ let doc = self.documents.get_mut(&doc_id).unwrap();
244+
245+ // initialize selection for view
246+ doc.selections
247+ .entry(view.id)
248+ .or_insert_with(|| Selection::point(0));
249+ // TODO: reuse align_view
250+ let pos = doc
251+ .selection(view.id)
252+ .primary()
253+ .cursor(doc.text().slice(..));
254+ let line = doc.text().char_to_line(pos);
255+ view.offset.row = line.saturating_sub(view.inner_area().height as usize / 2);
256+ }
257+
238258 pub fn switch(&mut self, id: DocumentId, action: Action) {
239259 use crate::tree::Layout;
240− use helix_core::Selection;
241260
242261 if !self.documents.contains_key(&id) {
243262 log::error!("cannot switch to document that does not exist (anymore)");
@@ -271,22 +290,9 @@ impl Editor {
271290 view.jumps.push(jump);
272291 view.last_accessed_doc = Some(view.doc);
273292 }
274− view.doc = id;
275− view.offset = Position::default();
276−
277− let (view, doc) = current!(self);
278293
279− // initialize selection for view
280− doc.selections
281− .entry(view.id)
282− .or_insert_with(|| Selection::point(0));
283− // TODO: reuse align_view
284− let pos = doc
285− .selection(view.id)
286− .primary()
287− .cursor(doc.text().slice(..));
288− let line = doc.text().char_to_line(pos);
289− view.offset.row = line.saturating_sub(view.inner_area().height as usize / 2);
294+ let view_id = view.id;
295+ self.replace_document_in_view(view_id, id);
290296
291297 return;
292298 }
@@ -318,11 +324,16 @@ impl Editor {
318324 self._refresh();
319325 }
320326
321− fn new_file_from_document(&mut self, action: Action, mut document: Document) -> DocumentId {
327+ fn new_document(&mut self, mut document: Document) -> DocumentId {
322328 let id = DocumentId(self.next_document_id);
323329 self.next_document_id += 1;
324330 document.id = id;
325331 self.documents.insert(id, document);
332+ id
333+ }
334+
335+ fn new_file_from_document(&mut self, action: Action, document: Document) -> DocumentId {
336+ let id = self.new_document(document);
326337 self.switch(id, action);
327338 id
328339 }
@@ -392,7 +403,7 @@ impl Editor {
392403 Ok(id)
393404 }
394405
395− pub fn close(&mut self, id: ViewId, close_buffer: bool) {
406+ pub fn close(&mut self, id: ViewId) {
396407 let view = self.tree.get(self.tree.focus);
397408 // remove selection
398409 self.documents
@@ -401,18 +412,66 @@ impl Editor {
401412 .selections
402413 .remove(&id);
403414
404− if close_buffer {
405− // get around borrowck issues
406− let doc = &self.documents[&view.doc];
415+ self.tree.remove(id);
416+ self._refresh();
417+ }
407418
408− if let Some(language_server) = doc.language_server() {
409− tokio::spawn(language_server.text_document_did_close(doc.identifier()));
410− }
411− self.documents.remove(&view.doc);
419+ pub fn close_document(&mut self, doc_id: DocumentId, force: bool) -> anyhow::Result<()> {
420+ let doc = match self.documents.get(&doc_id) {
421+ Some(doc) => doc,
422+ None => anyhow::bail!("document does not exist"),
423+ };
424+
425+ if !force && doc.is_modified() {
426+ anyhow::bail!(
427+ "buffer {:?} is modified",
428+ doc.relative_path()
429+ .map(|path| path.to_string_lossy().to_string())
430+ .unwrap_or_else(|| "[scratch]".into())
431+ );
432+ }
433+
434+ if let Some(language_server) = doc.language_server() {
435+ tokio::spawn(language_server.text_document_did_close(doc.identifier()));
436+ }
437+
438+ let views_to_close = self
439+ .tree
440+ .views()
441+ .filter_map(|(view, _focus)| {
442+ if view.doc == doc_id {
443+ Some(view.id)
444+ } else {
445+ None
446+ }
447+ })
448+ .collect::<Vec<_>>();
449+
450+ for view_id in views_to_close {
451+ self.close(view_id);
452+ }
453+
454+ self.documents.remove(&doc_id);
455+
456+ // If the document we removed was visible in all views, we will have no more views. We don't
457+ // want to close the editor just for a simple buffer close, so we need to create a new view
458+ // containing either an existing document, or a brand new document.
459+ if self.tree.views().peekable().peek().is_none() {
460+ let doc_id = self
461+ .documents
462+ .iter()
463+ .map(|(&doc_id, _)| doc_id)
464+ .next()
465+ .unwrap_or_else(|| self.new_document(Document::default()));
466+ let view = View::new(doc_id);
467+ let view_id = self.tree.insert(view);
468+ let doc = self.documents.get_mut(&doc_id).unwrap();
469+ doc.selections.insert(view_id, Selection::point(0));
412470 }
413471
414− self.tree.remove(id);
415472 self._refresh();
473+
474+ Ok(())
416475 }
417476
418477 pub fn resize(&mut self, area: Rect) {