Skip to content

Commit 18dfca0

Browse files
committed
add a diff source for the diff gutter based on the on-disk file contents
1 parent acdc670 commit 18dfca0

File tree

4 files changed

+96
-53
lines changed

4 files changed

+96
-53
lines changed

helix-term/src/application.rs

Lines changed: 13 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,
@@ -362,11 +362,15 @@ impl Application {
362362
// the Application can apply it.
363363
ConfigEvent::Update(editor_config) => {
364364
let mut app_config = (*self.config.load().clone()).clone();
365+
let update_diff_base = app_config.editor.diff_source != editor_config.diff_source;
365366
app_config.editor = *editor_config;
366367
if let Err(err) = self.terminal.reconfigure(app_config.editor.clone().into()) {
367368
self.editor.set_error(err.to_string());
368369
};
369370
self.config.store(Arc::new(app_config));
371+
if update_diff_base {
372+
self.editor.update_diff_base();
373+
}
370374
}
371375
}
372376

@@ -568,6 +572,14 @@ impl Application {
568572
self.editor.refresh_language_servers(id);
569573
}
570574

575+
let diff_source = self.editor.config().diff_source;
576+
let doc = doc_mut!(self.editor, &doc_save_event.doc_id);
577+
if diff_source == DiffSource::File {
578+
if let Some(path) = doc.path().cloned() {
579+
doc.update_diff_base(&path, &self.editor.diff_provider, diff_source);
580+
}
581+
}
582+
571583
// TODO: fix being overwritten by lsp
572584
self.editor.set_status(format!(
573585
"'{}' written, {}L {}B",

helix-term/src/commands/typed.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,10 +1283,12 @@ fn reload(
12831283
}
12841284

12851285
let scrolloff = cx.editor.config().scrolloff;
1286+
let diff_source = cx.editor.config().diff_source;
12861287
let (view, doc) = current!(cx.editor);
1287-
doc.reload(view, &cx.editor.diff_provider).map(|_| {
1288-
view.ensure_cursor_in_view(doc, scrolloff);
1289-
})?;
1288+
doc.reload(view, &cx.editor.diff_provider, diff_source)
1289+
.map(|_| {
1290+
view.ensure_cursor_in_view(doc, scrolloff);
1291+
})?;
12901292
if let Some(path) = doc.path() {
12911293
cx.editor
12921294
.language_servers
@@ -1324,6 +1326,7 @@ fn reload_all(
13241326
.collect();
13251327

13261328
for (doc_id, view_ids) in docs_view_ids {
1329+
let diff_source = cx.editor.config().diff_source;
13271330
let doc = doc_mut!(cx.editor, &doc_id);
13281331

13291332
// Every doc is guaranteed to have at least 1 view at this point.
@@ -1332,7 +1335,7 @@ fn reload_all(
13321335
// Ensure that the view is synced with the document's history.
13331336
view.sync_changes(doc);
13341337

1335-
doc.reload(view, &cx.editor.diff_provider)?;
1338+
doc.reload(view, &cx.editor.diff_provider, diff_source)?;
13361339
if let Some(path) = doc.path() {
13371340
cx.editor
13381341
.language_servers

helix-view/src/document.rs

Lines changed: 54 additions & 32 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.
@@ -991,7 +991,12 @@ impl Document {
991991
}
992992

993993
/// Reload the document from its path.
994-
pub fn reload(&mut self, view: &mut View, diff_provider: &Git) -> Result<(), Error> {
994+
pub fn reload(
995+
&mut self,
996+
view: &mut View,
997+
diff_provider: &Git,
998+
diff_source: DiffSource,
999+
) -> Result<(), Error> {
9951000
let encoding = self.encoding;
9961001
let path = self
9971002
.path()
@@ -1017,23 +1022,7 @@ impl Document {
10171022

10181023
self.detect_indent_and_line_ending();
10191024

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-
}
1028-
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-
};
1025+
self.update_diff_base(&path, diff_provider, diff_source);
10371026

10381027
Ok(())
10391028
}
@@ -1589,27 +1578,60 @@ impl Document {
15891578
}
15901579

15911580
/// Intialize/updates the differ for this document with a new base.
1592-
pub fn set_diff_base(&mut self, diff_base: Vec<u8>) {
1581+
fn set_diff_base_bytes(&mut self, diff_base: Vec<u8>) {
15931582
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()))
1583+
self.set_diff_base(diff_base);
15991584
} else {
16001585
self.diff_handle = None;
16011586
}
16021587
}
16031588

1604-
pub fn version_control_head(&self) -> Option<Arc<Box<str>>> {
1605-
self.version_control_head.as_ref().map(|a| a.load_full())
1589+
fn set_diff_base(&mut self, diff_base: Rope) {
1590+
if let Some(differ) = &self.diff_handle {
1591+
differ.update_diff_base(diff_base);
1592+
return;
1593+
}
1594+
self.diff_handle = Some(DiffHandle::new(diff_base, self.text.clone()))
16061595
}
16071596

1608-
pub fn set_version_control_head(
1609-
&mut self,
1610-
version_control_head: Option<Arc<ArcSwap<Box<str>>>>,
1611-
) {
1612-
self.version_control_head = version_control_head;
1597+
pub fn update_diff_base(&mut self, path: &Path, diff_provider: &Git, diff_source: DiffSource) {
1598+
match diff_source {
1599+
DiffSource::Git => match diff_provider.get_diff_base(path) {
1600+
Ok(diff_base) => self.set_diff_base_bytes(diff_base),
1601+
Err(err) => {
1602+
log::info!("{err:#?}");
1603+
log::info!("failed to open diff base for for {}", path.display());
1604+
self.diff_handle = None;
1605+
}
1606+
},
1607+
DiffSource::File => {
1608+
if self.is_modified() {
1609+
match std::fs::read(path) {
1610+
Ok(bytes) => self.set_diff_base_bytes(bytes),
1611+
Err(err) => {
1612+
log::info!("{err:#?}");
1613+
log::info!("failed to open diff base for for {}", path.display());
1614+
self.diff_handle = None;
1615+
}
1616+
}
1617+
} else {
1618+
self.set_diff_base(self.text.clone());
1619+
}
1620+
}
1621+
}
1622+
1623+
self.version_control_head = match diff_provider.get_current_head_name(path) {
1624+
Ok(res) => Some(res),
1625+
Err(err) => {
1626+
log::info!("{err:#?}");
1627+
log::info!("failed to obtain current head name for {}", path.display());
1628+
None
1629+
}
1630+
};
1631+
}
1632+
1633+
pub fn version_control_head(&self) -> Option<Arc<Box<str>>> {
1634+
self.version_control_head.as_ref().map(|a| a.load_full())
16131635
}
16141636

16151637
#[inline]

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 {
@@ -291,6 +299,9 @@ pub struct Config {
291299
pub insert_final_newline: bool,
292300
/// Enables smart tab
293301
pub smart_tab: Option<SmartTabConfig>,
302+
#[serde(default)]
303+
/// What the diff gutter should diff against
304+
pub diff_source: DiffSource,
294305
}
295306

296307
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)]
@@ -841,6 +852,7 @@ impl Default for Config {
841852
default_line_ending: LineEndingConfig::default(),
842853
insert_final_newline: true,
843854
smart_tab: Some(SmartTabConfig::default()),
855+
diff_source: DiffSource::default(),
844856
}
845857
}
846858
}
@@ -1452,22 +1464,7 @@ impl Editor {
14521464
self.config.clone(),
14531465
)?;
14541466

1455-
match self.diff_provider.get_diff_base(&path) {
1456-
Ok(diff_base) => doc.set_diff_base(diff_base),
1457-
Err(err) => {
1458-
log::info!("{err:#?}");
1459-
log::info!("failed to open diff base for for {}", path.display());
1460-
}
1461-
}
1462-
1463-
doc.set_version_control_head(match self.diff_provider.get_current_head_name(&path) {
1464-
Ok(res) => Some(res),
1465-
Err(err) => {
1466-
log::info!("{err:#?}");
1467-
log::info!("failed to obtain current head name for {}", path.display());
1468-
None
1469-
}
1470-
});
1467+
doc.update_diff_base(&path, &self.diff_provider, self.config().diff_source);
14711468

14721469
let id = self.new_document(doc);
14731470
self.launch_language_servers(id);
@@ -1839,6 +1836,15 @@ impl Editor {
18391836
.as_ref()
18401837
.and_then(|debugger| debugger.current_stack_frame())
18411838
}
1839+
1840+
pub fn update_diff_base(&mut self) {
1841+
let diff_source = self.config().diff_source;
1842+
for doc in self.documents.values_mut() {
1843+
if let Some(path) = doc.path().cloned() {
1844+
doc.update_diff_base(&path, &self.diff_provider, diff_source);
1845+
}
1846+
}
1847+
}
18421848
}
18431849

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

0 commit comments

Comments
 (0)