Skip to content

Commit a72eb8c

Browse files
committed
add a diff source for the diff gutter based on the on-disk file contents
1 parent 8cac2d5 commit a72eb8c

File tree

4 files changed

+101
-45
lines changed

4 files changed

+101
-45
lines changed

helix-term/src/application.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use helix_lsp::{
1313
use helix_view::{
1414
align_view,
1515
document::DocumentSavedEventResult,
16-
editor::{ConfigEvent, EditorEvent},
16+
editor::{ConfigEvent, DiffSource, EditorEvent},
1717
graphics::Rect,
1818
theme,
1919
tree::Layout,
@@ -351,11 +351,15 @@ impl Application {
351351
// the Application can apply it.
352352
ConfigEvent::Update(editor_config) => {
353353
let mut app_config = (*self.config.load().clone()).clone();
354+
let update_diff_base = app_config.editor.diff_source != editor_config.diff_source;
354355
app_config.editor = *editor_config;
355356
if let Err(err) = self.terminal.reconfigure(app_config.editor.clone().into()) {
356357
self.editor.set_error(err.to_string());
357358
};
358359
self.config.store(Arc::new(app_config));
360+
if update_diff_base {
361+
self.editor.update_diff_base();
362+
}
359363
}
360364
}
361365

@@ -557,6 +561,15 @@ impl Application {
557561
self.editor.refresh_language_servers(id);
558562
}
559563

564+
let diff_source = self.editor.config().diff_source;
565+
let doc = doc_mut!(self.editor, &doc_save_event.doc_id);
566+
doc.set_original_text(doc.text().clone());
567+
if diff_source == DiffSource::File {
568+
if let Some(path) = doc.path().cloned() {
569+
doc.update_diff_base(&path, &self.editor.diff_provider, diff_source);
570+
}
571+
}
572+
560573
// TODO: fix being overwritten by lsp
561574
self.editor.set_status(format!(
562575
"'{}' written, {}L {}B",

helix-term/src/commands/typed.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,10 +1266,12 @@ fn reload(
12661266
}
12671267

12681268
let scrolloff = cx.editor.config().scrolloff;
1269+
let diff_source = cx.editor.config().diff_source;
12691270
let (view, doc) = current!(cx.editor);
1270-
doc.reload(view, &cx.editor.diff_provider).map(|_| {
1271-
view.ensure_cursor_in_view(doc, scrolloff);
1272-
})?;
1271+
doc.reload(view, &cx.editor.diff_provider, diff_source)
1272+
.map(|_| {
1273+
view.ensure_cursor_in_view(doc, scrolloff);
1274+
})?;
12731275
if let Some(path) = doc.path() {
12741276
cx.editor
12751277
.language_servers
@@ -1307,6 +1309,7 @@ fn reload_all(
13071309
.collect();
13081310

13091311
for (doc_id, view_ids) in docs_view_ids {
1312+
let diff_source = cx.editor.config().diff_source;
13101313
let doc = doc_mut!(cx.editor, &doc_id);
13111314

13121315
// Every doc is guaranteed to have at least 1 view at this point.
@@ -1315,7 +1318,7 @@ fn reload_all(
13151318
// Ensure that the view is synced with the document's history.
13161319
view.sync_changes(doc);
13171320

1318-
doc.reload(view, &cx.editor.diff_provider)?;
1321+
doc.reload(view, &cx.editor.diff_provider, diff_source)?;
13191322
if let Some(path) = doc.path() {
13201323
cx.editor
13211324
.language_servers

helix-view/src/document.rs

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use helix_core::{
3333
ChangeSet, Diagnostic, LineEnding, Range, Rope, RopeBuilder, Selection, Syntax, Transaction,
3434
};
3535

36-
use crate::editor::Config;
36+
use crate::editor::{Config, DiffSource};
3737
use crate::{DocumentId, Editor, Theme, View, ViewId};
3838

3939
/// 8kB of buffer space for encoding and decoding `Rope`s.
@@ -130,6 +130,7 @@ impl SavePoint {
130130
pub struct Document {
131131
pub(crate) id: DocumentId,
132132
text: Rope,
133+
original_text: Rope,
133134
selections: HashMap<ViewId, Selection>,
134135

135136
/// Inlay hints annotations for the document, by view.
@@ -652,7 +653,8 @@ impl Document {
652653
path: None,
653654
encoding,
654655
has_bom,
655-
text,
656+
text: text.clone(),
657+
original_text: text,
656658
selections: HashMap::default(),
657659
inlay_hints: HashMap::default(),
658660
inlay_hints_oudated: false,
@@ -991,7 +993,12 @@ impl Document {
991993
}
992994

993995
/// Reload the document from its path.
994-
pub fn reload(&mut self, view: &mut View, diff_provider: &Git) -> Result<(), Error> {
996+
pub fn reload(
997+
&mut self,
998+
view: &mut View,
999+
diff_provider: &Git,
1000+
diff_source: DiffSource,
1001+
) -> Result<(), Error> {
9951002
let encoding = self.encoding;
9961003
let path = self
9971004
.path()
@@ -1017,23 +1024,9 @@ impl Document {
10171024

10181025
self.detect_indent_and_line_ending();
10191026

1020-
match diff_provider.get_diff_base(&path) {
1021-
Ok(diff_base) => self.set_diff_base(diff_base),
1022-
Err(err) => {
1023-
log::info!("{err:#?}");
1024-
log::info!("failed to open diff base for for {}", path.display());
1025-
self.diff_handle = None;
1026-
}
1027-
}
1027+
self.original_text = rope;
10281028

1029-
self.version_control_head = match diff_provider.get_current_head_name(&path) {
1030-
Ok(res) => Some(res),
1031-
Err(err) => {
1032-
log::info!("{err:#?}");
1033-
log::info!("failed to obtain current head name for {}", path.display());
1034-
None
1035-
}
1036-
};
1029+
self.update_diff_base(&path, diff_provider, diff_source);
10371030

10381031
Ok(())
10391032
}
@@ -1591,16 +1584,48 @@ impl Document {
15911584
/// Intialize/updates the differ for this document with a new base.
15921585
pub fn set_diff_base(&mut self, diff_base: Vec<u8>) {
15931586
if let Ok((diff_base, ..)) = from_reader(&mut diff_base.as_slice(), Some(self.encoding)) {
1594-
if let Some(differ) = &self.diff_handle {
1595-
differ.update_diff_base(diff_base);
1596-
return;
1597-
}
1598-
self.diff_handle = Some(DiffHandle::new(diff_base, self.text.clone()))
1587+
self.set_diff_base_raw(diff_base);
15991588
} else {
16001589
self.diff_handle = None;
16011590
}
16021591
}
16031592

1593+
pub fn set_diff_base_raw(&mut self, diff_base: Rope) {
1594+
if let Some(differ) = &self.diff_handle {
1595+
differ.update_diff_base(diff_base);
1596+
return;
1597+
}
1598+
self.diff_handle = Some(DiffHandle::new(diff_base, self.text.clone()))
1599+
}
1600+
1601+
pub fn update_diff_base(&mut self, path: &Path, diff_provider: &Git, diff_source: DiffSource) {
1602+
match diff_source {
1603+
DiffSource::Git => {
1604+
match diff_provider.get_diff_base(path) {
1605+
Ok(diff_base) => self.set_diff_base(diff_base),
1606+
Err(err) => {
1607+
log::info!("{err:#?}");
1608+
log::info!("failed to open diff base for for {}", path.display());
1609+
self.diff_handle = None;
1610+
}
1611+
}
1612+
1613+
self.version_control_head = match diff_provider.get_current_head_name(path) {
1614+
Ok(res) => Some(res),
1615+
Err(err) => {
1616+
log::info!("{err:#?}");
1617+
log::info!("failed to obtain current head name for {}", path.display());
1618+
None
1619+
}
1620+
};
1621+
}
1622+
DiffSource::File => {
1623+
self.set_diff_base_raw(self.original_text.clone());
1624+
self.version_control_head = None;
1625+
}
1626+
}
1627+
}
1628+
16041629
pub fn version_control_head(&self) -> Option<Arc<Box<str>>> {
16051630
self.version_control_head.as_ref().map(|a| a.load_full())
16061631
}
@@ -1650,6 +1675,15 @@ impl Document {
16501675
&self.text
16511676
}
16521677

1678+
#[inline]
1679+
pub fn original_text(&self) -> &Rope {
1680+
&self.original_text
1681+
}
1682+
1683+
pub fn set_original_text(&mut self, text: Rope) {
1684+
self.original_text = text;
1685+
}
1686+
16531687
#[inline]
16541688
pub fn selection(&self, view_id: ViewId) -> &Selection {
16551689
&self.selections[&view_id]

helix-view/src/editor.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ where
7373
)
7474
}
7575

76+
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
77+
#[serde(rename_all = "kebab-case")]
78+
pub enum DiffSource {
79+
#[default]
80+
Git,
81+
File,
82+
}
83+
7684
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7785
#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
7886
pub struct GutterConfig {
@@ -289,6 +297,9 @@ pub struct Config {
289297
pub default_line_ending: LineEndingConfig,
290298
/// Enables smart tab
291299
pub smart_tab: Option<SmartTabConfig>,
300+
#[serde(default)]
301+
/// What the diff gutter should diff against
302+
pub diff_source: DiffSource,
292303
}
293304

294305
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)]
@@ -843,6 +854,7 @@ impl Default for Config {
843854
workspace_lsp_roots: Vec::new(),
844855
default_line_ending: LineEndingConfig::default(),
845856
smart_tab: Some(SmartTabConfig::default()),
857+
diff_source: DiffSource::default(),
846858
}
847859
}
848860
}
@@ -1445,22 +1457,7 @@ impl Editor {
14451457
self.config.clone(),
14461458
)?;
14471459

1448-
match self.diff_provider.get_diff_base(&path) {
1449-
Ok(diff_base) => doc.set_diff_base(diff_base),
1450-
Err(err) => {
1451-
log::info!("{err:#?}");
1452-
log::info!("failed to open diff base for for {}", path.display());
1453-
}
1454-
}
1455-
1456-
doc.set_version_control_head(match self.diff_provider.get_current_head_name(&path) {
1457-
Ok(res) => Some(res),
1458-
Err(err) => {
1459-
log::info!("{err:#?}");
1460-
log::info!("failed to obtain current head name for {}", path.display());
1461-
None
1462-
}
1463-
});
1460+
doc.update_diff_base(&path, &self.diff_provider, self.config().diff_source);
14641461

14651462
let id = self.new_document(doc);
14661463
let _ = self.launch_language_servers(id);
@@ -1832,6 +1829,15 @@ impl Editor {
18321829
.as_ref()
18331830
.and_then(|debugger| debugger.current_stack_frame())
18341831
}
1832+
1833+
pub fn update_diff_base(&mut self) {
1834+
let diff_source = self.config().diff_source;
1835+
for doc in self.documents.values_mut() {
1836+
if let Some(path) = doc.path().cloned() {
1837+
doc.update_diff_base(&path, &self.diff_provider, diff_source);
1838+
}
1839+
}
1840+
}
18351841
}
18361842

18371843
fn try_restore_indent(doc: &mut Document, view: &mut View) {

0 commit comments

Comments
 (0)