mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-22 09:26:19 +04:00
Change focus to modified docs on quit (#3872)
* Change focus to modified docs on quit When quitting with modified documents, automatically switch focus to one of them. * Update helix-term/src/commands/typed.rs Co-authored-by: Poliorcetics <poliorcetics@users.noreply.github.com> * Make it work with buffer-close-all and the like * Cleanup Use Cow instead of String, and rename DoesntExist -> DoesNotExist Co-authored-by: Poliorcetics <poliorcetics@users.noreply.github.com>
This commit is contained in:
parent
6764744ce9
commit
1d8bb2249b
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use helix_view::editor::{Action, ConfigEvent};
|
use helix_view::editor::{Action, CloseError, ConfigEvent};
|
||||||
use ui::completers::{self, Completer};
|
use ui::completers::{self, Completer};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -71,8 +71,29 @@ fn buffer_close_by_ids_impl(
|
|||||||
doc_ids: &[DocumentId],
|
doc_ids: &[DocumentId],
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
for &doc_id in doc_ids {
|
let (modified_ids, modified_names): (Vec<_>, Vec<_>) = doc_ids
|
||||||
editor.close_document(doc_id, force)?;
|
.iter()
|
||||||
|
.filter_map(|&doc_id| {
|
||||||
|
if let Err(CloseError::BufferModified(name)) = editor.close_document(doc_id, force) {
|
||||||
|
Some((doc_id, name))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unzip();
|
||||||
|
|
||||||
|
if let Some(first) = modified_ids.first() {
|
||||||
|
let current = doc!(editor);
|
||||||
|
// If the current document is unmodified, and there are modified
|
||||||
|
// documents, switch focus to the first modified doc.
|
||||||
|
if !modified_ids.contains(¤t.id()) {
|
||||||
|
editor.switch(*first, Action::Replace);
|
||||||
|
}
|
||||||
|
bail!(
|
||||||
|
"{} unsaved buffer(s) remaining: {:?}",
|
||||||
|
modified_names.len(),
|
||||||
|
modified_names
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -513,23 +534,26 @@ fn force_write_quit(
|
|||||||
force_quit(cx, &[], event)
|
force_quit(cx, &[], event)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Results an error if there are modified buffers remaining and sets editor error,
|
/// Results in an error if there are modified buffers remaining and sets editor
|
||||||
/// otherwise returns `Ok(())`
|
/// error, otherwise returns `Ok(())`. If the current document is unmodified,
|
||||||
|
/// and there are modified documents, switches focus to one of them.
|
||||||
pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> {
|
pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> {
|
||||||
let modified: Vec<_> = editor
|
let (modified_ids, modified_names): (Vec<_>, Vec<_>) = editor
|
||||||
.documents()
|
.documents()
|
||||||
.filter(|doc| doc.is_modified())
|
.filter(|doc| doc.is_modified())
|
||||||
.map(|doc| {
|
.map(|doc| (doc.id(), doc.display_name()))
|
||||||
doc.relative_path()
|
.unzip();
|
||||||
.map(|path| path.to_string_lossy().to_string())
|
if let Some(first) = modified_ids.first() {
|
||||||
.unwrap_or_else(|| SCRATCH_BUFFER_NAME.into())
|
let current = doc!(editor);
|
||||||
})
|
// If the current document is unmodified, and there are modified
|
||||||
.collect();
|
// documents, switch focus to the first modified doc.
|
||||||
if !modified.is_empty() {
|
if !modified_ids.contains(¤t.id()) {
|
||||||
|
editor.switch(*first, Action::Replace);
|
||||||
|
}
|
||||||
bail!(
|
bail!(
|
||||||
"{} unsaved buffer(s) remaining: {:?}",
|
"{} unsaved buffer(s) remaining: {:?}",
|
||||||
modified.len(),
|
modified_names.len(),
|
||||||
modified
|
modified_names
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
use helix_core::Range;
|
use helix_core::Range;
|
||||||
use serde::de::{self, Deserialize, Deserializer};
|
use serde::de::{self, Deserialize, Deserializer};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
@ -1038,6 +1039,12 @@ pub fn relative_path(&self) -> Option<PathBuf> {
|
|||||||
.map(helix_core::path::get_relative_path)
|
.map(helix_core::path::get_relative_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn display_name(&self) -> Cow<'static, str> {
|
||||||
|
self.relative_path()
|
||||||
|
.map(|path| path.to_string_lossy().to_string().into())
|
||||||
|
.unwrap_or_else(|| SCRATCH_BUFFER_NAME.into())
|
||||||
|
}
|
||||||
|
|
||||||
// transact(Fn) ?
|
// transact(Fn) ?
|
||||||
|
|
||||||
// -- LSP methods
|
// -- LSP methods
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
clipboard::{get_clipboard_provider, ClipboardProvider},
|
clipboard::{get_clipboard_provider, ClipboardProvider},
|
||||||
document::{Mode, SCRATCH_BUFFER_NAME},
|
document::Mode,
|
||||||
graphics::{CursorKind, Rect},
|
graphics::{CursorKind, Rect},
|
||||||
info::Info,
|
info::Info,
|
||||||
input::KeyEvent,
|
input::KeyEvent,
|
||||||
@ -28,7 +28,7 @@
|
|||||||
time::{sleep, Duration, Instant, Sleep},
|
time::{sleep, Duration, Instant, Sleep},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{bail, Error};
|
use anyhow::Error;
|
||||||
|
|
||||||
pub use helix_core::diagnostic::Severity;
|
pub use helix_core::diagnostic::Severity;
|
||||||
pub use helix_core::register::Registers;
|
pub use helix_core::register::Registers;
|
||||||
@ -711,6 +711,14 @@ pub enum Action {
|
|||||||
VerticalSplit,
|
VerticalSplit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error thrown on failed document closed
|
||||||
|
pub enum CloseError {
|
||||||
|
/// Document doesn't exist
|
||||||
|
DoesNotExist,
|
||||||
|
/// Buffer is modified
|
||||||
|
BufferModified(String),
|
||||||
|
}
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
mut area: Rect,
|
mut area: Rect,
|
||||||
@ -1070,19 +1078,14 @@ pub fn close(&mut self, id: ViewId) {
|
|||||||
self._refresh();
|
self._refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_document(&mut self, doc_id: DocumentId, force: bool) -> anyhow::Result<()> {
|
pub fn close_document(&mut self, doc_id: DocumentId, force: bool) -> Result<(), CloseError> {
|
||||||
let doc = match self.documents.get(&doc_id) {
|
let doc = match self.documents.get(&doc_id) {
|
||||||
Some(doc) => doc,
|
Some(doc) => doc,
|
||||||
None => bail!("document does not exist"),
|
None => return Err(CloseError::DoesNotExist),
|
||||||
};
|
};
|
||||||
|
|
||||||
if !force && doc.is_modified() {
|
if !force && doc.is_modified() {
|
||||||
bail!(
|
return Err(CloseError::BufferModified(doc.display_name().into_owned()));
|
||||||
"buffer {:?} is modified",
|
|
||||||
doc.relative_path()
|
|
||||||
.map(|path| path.to_string_lossy().to_string())
|
|
||||||
.unwrap_or_else(|| SCRATCH_BUFFER_NAME.into())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(language_server) = doc.language_server() {
|
if let Some(language_server) = doc.language_server() {
|
||||||
|
Loading…
Reference in New Issue
Block a user