diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 0d40fa66f0257..eeef1dd086f60 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -13,7 +13,7 @@ use helix_lsp::{ use helix_view::{ align_view, document::DocumentSavedEventResult, - editor::{ConfigEvent, EditorEvent}, + editor::{ConfigEvent, DiffSource, EditorEvent}, graphics::Rect, theme, tree::Layout, @@ -351,11 +351,15 @@ impl Application { // the Application can apply it. ConfigEvent::Update(editor_config) => { let mut app_config = (*self.config.load().clone()).clone(); + let update_diff_base = app_config.editor.diff_source != editor_config.diff_source; app_config.editor = *editor_config; if let Err(err) = self.terminal.reconfigure(app_config.editor.clone().into()) { self.editor.set_error(err.to_string()); }; self.config.store(Arc::new(app_config)); + if update_diff_base { + self.editor.update_diff_base(); + } } } @@ -557,6 +561,15 @@ impl Application { self.editor.refresh_language_servers(id); } + let diff_source = self.editor.config().diff_source; + let doc = doc_mut!(self.editor, &doc_save_event.doc_id); + doc.set_original_text(doc.text().clone()); + if diff_source == DiffSource::File { + if let Some(path) = doc.path().cloned() { + doc.update_diff_base(&path, &self.editor.diff_provider, diff_source); + } + } + // TODO: fix being overwritten by lsp self.editor.set_status(format!( "'{}' written, {}L {}B", diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index a9ff70b913227..1133d89cd5292 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1266,10 +1266,12 @@ fn reload( } let scrolloff = cx.editor.config().scrolloff; + let diff_source = cx.editor.config().diff_source; let (view, doc) = current!(cx.editor); - doc.reload(view, &cx.editor.diff_provider).map(|_| { - view.ensure_cursor_in_view(doc, scrolloff); - })?; + doc.reload(view, &cx.editor.diff_provider, diff_source) + .map(|_| { + view.ensure_cursor_in_view(doc, scrolloff); + })?; if let Some(path) = doc.path() { cx.editor .language_servers @@ -1307,6 +1309,7 @@ fn reload_all( .collect(); for (doc_id, view_ids) in docs_view_ids { + let diff_source = cx.editor.config().diff_source; let doc = doc_mut!(cx.editor, &doc_id); // Every doc is guaranteed to have at least 1 view at this point. @@ -1315,7 +1318,7 @@ fn reload_all( // Ensure that the view is synced with the document's history. view.sync_changes(doc); - doc.reload(view, &cx.editor.diff_provider)?; + doc.reload(view, &cx.editor.diff_provider, diff_source)?; if let Some(path) = doc.path() { cx.editor .language_servers diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 05895b7732382..280f166adcd81 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -33,7 +33,7 @@ use helix_core::{ ChangeSet, Diagnostic, LineEnding, Range, Rope, RopeBuilder, Selection, Syntax, Transaction, }; -use crate::editor::Config; +use crate::editor::{Config, DiffSource}; use crate::{DocumentId, Editor, Theme, View, ViewId}; /// 8kB of buffer space for encoding and decoding `Rope`s. @@ -130,6 +130,7 @@ impl SavePoint { pub struct Document { pub(crate) id: DocumentId, text: Rope, + original_text: Rope, selections: HashMap, /// Inlay hints annotations for the document, by view. @@ -652,7 +653,8 @@ impl Document { path: None, encoding, has_bom, - text, + text: text.clone(), + original_text: text, selections: HashMap::default(), inlay_hints: HashMap::default(), inlay_hints_oudated: false, @@ -991,7 +993,12 @@ impl Document { } /// Reload the document from its path. - pub fn reload(&mut self, view: &mut View, diff_provider: &Git) -> Result<(), Error> { + pub fn reload( + &mut self, + view: &mut View, + diff_provider: &Git, + diff_source: DiffSource, + ) -> Result<(), Error> { let encoding = self.encoding; let path = self .path() @@ -1017,23 +1024,9 @@ impl Document { self.detect_indent_and_line_ending(); - match diff_provider.get_diff_base(&path) { - Ok(diff_base) => self.set_diff_base(diff_base), - Err(err) => { - log::info!("{err:#?}"); - log::info!("failed to open diff base for for {}", path.display()); - self.diff_handle = None; - } - } + self.original_text = rope; - self.version_control_head = match diff_provider.get_current_head_name(&path) { - Ok(res) => Some(res), - Err(err) => { - log::info!("{err:#?}"); - log::info!("failed to obtain current head name for {}", path.display()); - None - } - }; + self.update_diff_base(&path, diff_provider, diff_source); Ok(()) } @@ -1591,16 +1584,48 @@ impl Document { /// Intialize/updates the differ for this document with a new base. pub fn set_diff_base(&mut self, diff_base: Vec) { if let Ok((diff_base, ..)) = from_reader(&mut diff_base.as_slice(), Some(self.encoding)) { - if let Some(differ) = &self.diff_handle { - differ.update_diff_base(diff_base); - return; - } - self.diff_handle = Some(DiffHandle::new(diff_base, self.text.clone())) + self.set_diff_base_raw(diff_base); } else { self.diff_handle = None; } } + pub fn set_diff_base_raw(&mut self, diff_base: Rope) { + if let Some(differ) = &self.diff_handle { + differ.update_diff_base(diff_base); + return; + } + self.diff_handle = Some(DiffHandle::new(diff_base, self.text.clone())) + } + + pub fn update_diff_base(&mut self, path: &Path, diff_provider: &Git, diff_source: DiffSource) { + match diff_source { + DiffSource::Git => { + match diff_provider.get_diff_base(path) { + Ok(diff_base) => self.set_diff_base(diff_base), + Err(err) => { + log::info!("{err:#?}"); + log::info!("failed to open diff base for for {}", path.display()); + self.diff_handle = None; + } + } + + self.version_control_head = match diff_provider.get_current_head_name(path) { + Ok(res) => Some(res), + Err(err) => { + log::info!("{err:#?}"); + log::info!("failed to obtain current head name for {}", path.display()); + None + } + }; + } + DiffSource::File => { + self.set_diff_base_raw(self.original_text.clone()); + self.version_control_head = None; + } + } + } + pub fn version_control_head(&self) -> Option>> { self.version_control_head.as_ref().map(|a| a.load_full()) } @@ -1650,6 +1675,15 @@ impl Document { &self.text } + #[inline] + pub fn original_text(&self) -> &Rope { + &self.original_text + } + + pub fn set_original_text(&mut self, text: Rope) { + self.original_text = text; + } + #[inline] pub fn selection(&self, view_id: ViewId) -> &Selection { &self.selections[&view_id] diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index b140a5954c61a..4474775b14dc2 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -73,6 +73,14 @@ where ) } +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum DiffSource { + #[default] + Git, + File, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default, deny_unknown_fields)] pub struct GutterConfig { @@ -289,6 +297,9 @@ pub struct Config { pub default_line_ending: LineEndingConfig, /// Enables smart tab pub smart_tab: Option, + #[serde(default)] + /// What the diff gutter should diff against + pub diff_source: DiffSource, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] @@ -843,6 +854,7 @@ impl Default for Config { workspace_lsp_roots: Vec::new(), default_line_ending: LineEndingConfig::default(), smart_tab: Some(SmartTabConfig::default()), + diff_source: DiffSource::default(), } } } @@ -1445,22 +1457,7 @@ impl Editor { self.config.clone(), )?; - match self.diff_provider.get_diff_base(&path) { - Ok(diff_base) => doc.set_diff_base(diff_base), - Err(err) => { - log::info!("{err:#?}"); - log::info!("failed to open diff base for for {}", path.display()); - } - } - - doc.set_version_control_head(match self.diff_provider.get_current_head_name(&path) { - Ok(res) => Some(res), - Err(err) => { - log::info!("{err:#?}"); - log::info!("failed to obtain current head name for {}", path.display()); - None - } - }); + doc.update_diff_base(&path, &self.diff_provider, self.config().diff_source); let id = self.new_document(doc); let _ = self.launch_language_servers(id); @@ -1832,6 +1829,15 @@ impl Editor { .as_ref() .and_then(|debugger| debugger.current_stack_frame()) } + + pub fn update_diff_base(&mut self) { + let diff_source = self.config().diff_source; + for doc in self.documents.values_mut() { + if let Some(path) = doc.path().cloned() { + doc.update_diff_base(&path, &self.diff_provider, diff_source); + } + } + } } fn try_restore_indent(doc: &mut Document, view: &mut View) {