aboutsummaryrefslogtreecommitdiff
path: root/helix-view/src/document.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-view/src/document.rs')
-rw-r--r--helix-view/src/document.rs81
1 files changed, 54 insertions, 27 deletions
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index 1f1b1f5f..ce5df8ee 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -23,6 +23,8 @@ use crate::{DocumentId, Theme, ViewId};
/// 8kB of buffer space for encoding and decoding `Rope`s.
const BUF_SIZE: usize = 8192;
+const DEFAULT_INDENT: IndentStyle = IndentStyle::Spaces(4);
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Mode {
Normal,
@@ -95,6 +97,9 @@ pub struct Document {
// it back as it separated from the edits. We could split out the parts manually but that will
// be more troublesome.
history: Cell<History>,
+
+ pub savepoint: Option<Transaction>,
+
last_saved_revision: usize,
version: i32, // should be usize?
@@ -306,8 +311,7 @@ where
T: Default,
F: FnOnce(T) -> T,
{
- let t = mem::take(mut_ref);
- let _ = mem::replace(mut_ref, f(t));
+ *mut_ref = f(mem::take(mut_ref));
}
use helix_lsp::lsp;
@@ -325,7 +329,8 @@ impl Document {
encoding,
text,
selections: HashMap::default(),
- indent_style: IndentStyle::Spaces(4),
+ indent_style: DEFAULT_INDENT,
+ line_ending: DEFAULT_LINE_ENDING,
mode: Mode::Normal,
restore_cursor: false,
syntax: None,
@@ -335,9 +340,9 @@ impl Document {
diagnostics: Vec::new(),
version: 0,
history: Cell::new(History::default()),
+ savepoint: None,
last_saved_revision: 0,
language_server: None,
- line_ending: DEFAULT_LINE_ENDING,
}
}
@@ -363,7 +368,7 @@ impl Document {
let mut doc = Self::from(rope, Some(encoding));
// set the path and try detecting the language
- doc.set_path(path)?;
+ doc.set_path(Some(path))?;
if let Some(loader) = config_loader {
doc.detect_language(theme, loader);
}
@@ -495,17 +500,15 @@ impl Document {
}
/// Detect the indentation used in the file, or otherwise defaults to the language indentation
- /// configured in `languages.toml`, with a fallback back to 2 space indentation if it isn't
+ /// configured in `languages.toml`, with a fallback to 4 space indentation if it isn't
/// specified. Line ending is likewise auto-detected, and will fallback to the default OS
/// line ending.
pub fn detect_indent_and_line_ending(&mut self) {
self.indent_style = auto_detect_indent_style(&self.text).unwrap_or_else(|| {
- IndentStyle::from_str(
- self.language
- .as_ref()
- .and_then(|config| config.indent.as_ref())
- .map_or(" ", |config| config.unit.as_str()), // Fallback to 2 spaces.
- )
+ self.language
+ .as_ref()
+ .and_then(|config| config.indent.as_ref())
+ .map_or(DEFAULT_INDENT, |config| IndentStyle::from_str(&config.unit))
});
self.line_ending = auto_detect_line_ending(&self.text).unwrap_or(DEFAULT_LINE_ENDING);
}
@@ -550,12 +553,14 @@ impl Document {
self.encoding
}
- pub fn set_path(&mut self, path: &Path) -> Result<(), std::io::Error> {
- let path = helix_core::path::get_canonicalized_path(path)?;
+ pub fn set_path(&mut self, path: Option<&Path>) -> Result<(), std::io::Error> {
+ let path = path
+ .map(helix_core::path::get_canonicalized_path)
+ .transpose()?;
// if parent doesn't exist we still want to open the document
// and error out when document is saved
- self.path = Some(path);
+ self.path = path;
Ok(())
}
@@ -635,6 +640,14 @@ impl Document {
if !transaction.changes().is_empty() {
self.version += 1;
+ // generate revert to savepoint
+ if self.savepoint.is_some() {
+ take_with(&mut self.savepoint, |prev_revert| {
+ let revert = transaction.invert(&old_doc);
+ Some(revert.compose(prev_revert.unwrap()))
+ });
+ }
+
// update tree-sitter syntax tree
if let Some(syntax) = &mut self.syntax {
// TODO: no unwrap
@@ -644,14 +657,13 @@ impl Document {
}
// map state.diagnostics over changes::map_pos too
- // NOTE: seems to do nothing since the language server resends diagnostics on each edit
- // for diagnostic in &mut self.diagnostics {
- // use helix_core::Assoc;
- // let changes = transaction.changes();
- // diagnostic.range.start = changes.map_pos(diagnostic.range.start, Assoc::After);
- // diagnostic.range.end = changes.map_pos(diagnostic.range.end, Assoc::After);
- // diagnostic.line = self.text.char_to_line(diagnostic.range.start);
- // }
+ for diagnostic in &mut self.diagnostics {
+ use helix_core::Assoc;
+ let changes = transaction.changes();
+ diagnostic.range.start = changes.map_pos(diagnostic.range.start, Assoc::After);
+ diagnostic.range.end = changes.map_pos(diagnostic.range.end, Assoc::After);
+ diagnostic.line = self.text.char_to_line(diagnostic.range.start);
+ }
// emit lsp notification
if let Some(language_server) = self.language_server() {
@@ -692,8 +704,8 @@ impl Document {
success
}
- /// Undo the last modification to the [`Document`].
- pub fn undo(&mut self, view_id: ViewId) {
+ /// Undo the last modification to the [`Document`]. Returns whether the undo was successful.
+ pub fn undo(&mut self, view_id: ViewId) -> bool {
let mut history = self.history.take();
let success = if let Some(transaction) = history.undo() {
self.apply_impl(transaction, view_id)
@@ -706,10 +718,11 @@ impl Document {
// reset changeset to fix len
self.changes = ChangeSet::new(self.text());
}
+ success
}
- /// Redo the last modification to the [`Document`].
- pub fn redo(&mut self, view_id: ViewId) {
+ /// Redo the last modification to the [`Document`]. Returns whether the redo was sucessful.
+ pub fn redo(&mut self, view_id: ViewId) -> bool {
let mut history = self.history.take();
let success = if let Some(transaction) = history.redo() {
self.apply_impl(transaction, view_id)
@@ -722,6 +735,17 @@ impl Document {
// reset changeset to fix len
self.changes = ChangeSet::new(self.text());
}
+ success
+ }
+
+ pub fn savepoint(&mut self) {
+ self.savepoint = Some(Transaction::new(self.text()));
+ }
+
+ pub fn restore(&mut self, view_id: ViewId) {
+ if let Some(revert) = self.savepoint.take() {
+ self.apply(&revert, view_id);
+ }
}
/// Undo modifications to the [`Document`] according to `uk`.
@@ -894,6 +918,9 @@ impl Document {
pub fn set_diagnostics(&mut self, diagnostics: Vec<Diagnostic>) {
self.diagnostics = diagnostics;
+ // sort by range
+ self.diagnostics
+ .sort_unstable_by_key(|diagnostic| diagnostic.range);
}
}