feat: edit working-checkout comparisons with normal editor actions
This commit is contained in:
+151
-10
@@ -11,7 +11,7 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
diff::{Operation as DiffOperation, Outcome as DiffOutcome},
|
||||
diff::{Focus, Operation as DiffOperation, Outcome as DiffOutcome},
|
||||
editor::{Cursor, Editor, Effect, Input, Invocation, Mode},
|
||||
lsp::Lsp,
|
||||
plugin::{
|
||||
@@ -71,8 +71,12 @@ impl DiffWorker {
|
||||
DiffOperation::FetchRemote(remote) => {
|
||||
repository.fetch_remote(&remote).map(DiffOutcome::Catalog)
|
||||
}
|
||||
DiffOperation::Compare { before, after } => repository
|
||||
.compare(&before, &after)
|
||||
DiffOperation::Compare {
|
||||
before,
|
||||
after,
|
||||
buffers,
|
||||
} => repository
|
||||
.compare(&before, &after, &buffers)
|
||||
.map(DiffOutcome::Comparison),
|
||||
}
|
||||
})();
|
||||
@@ -254,6 +258,10 @@ impl EditorSession {
|
||||
&self.editor
|
||||
}
|
||||
|
||||
pub(crate) fn scroll_diff(&mut self, focus: Focus, down: bool) {
|
||||
self.editor.scroll_diff(focus, down);
|
||||
}
|
||||
|
||||
pub fn handle(&mut self, input: Input) {
|
||||
self.cancel_pending_popup_request();
|
||||
let invocation = self.editor.handle(input);
|
||||
@@ -386,6 +394,7 @@ impl EditorSession {
|
||||
return;
|
||||
}
|
||||
let context = self.editor.context();
|
||||
let read_only = self.editor.diff().is_some() && !self.editor.diff_editing();
|
||||
let result = match self.plugins.get_mut(&invocation.plugin) {
|
||||
Some(plugin) if plugin.is_async() => {
|
||||
let requests = self.requests.entry(invocation.plugin.clone()).or_default();
|
||||
@@ -402,7 +411,18 @@ impl EditorSession {
|
||||
}
|
||||
Some(plugin) => plugin
|
||||
.invoke(&invocation.command, &invocation.args, &context)
|
||||
.and_then(|effects| self.editor.apply(effects)),
|
||||
.and_then(|effects| {
|
||||
if read_only
|
||||
&& effects
|
||||
.iter()
|
||||
.any(|effect| matches!(effect, Effect::Insert(_) | Effect::Replace(_)))
|
||||
{
|
||||
self.editor.set_message("Diff pane is read-only");
|
||||
Ok(())
|
||||
} else {
|
||||
self.editor.apply(effects)
|
||||
}
|
||||
}),
|
||||
None => Err("plugin host is unavailable".into()),
|
||||
};
|
||||
if let Err(error) = result {
|
||||
@@ -555,7 +575,7 @@ impl EditorSession {
|
||||
request_id: Option<u64>,
|
||||
source: InvocationSource,
|
||||
) -> bool {
|
||||
if self.editor.diff().is_some() {
|
||||
if self.editor.diff().is_some() && !self.editor.diff_editing() {
|
||||
return false;
|
||||
}
|
||||
self.editor.buffer_id() == source.buffer_id
|
||||
@@ -791,6 +811,7 @@ impl EditorSession {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.editor.refresh_live_diff();
|
||||
Ok(changed)
|
||||
}
|
||||
|
||||
@@ -807,10 +828,7 @@ impl EditorSession {
|
||||
let Some(source) = source else {
|
||||
return Err("plugin response has an unknown invocation ID".into());
|
||||
};
|
||||
if !self.source_is_current(source)
|
||||
|| self.editor.buffer_id() != source.buffer_id
|
||||
|| self.editor.diff().is_some()
|
||||
{
|
||||
if !self.source_is_current(source) || self.editor.buffer_id() != source.buffer_id {
|
||||
return Ok(false);
|
||||
}
|
||||
if effects
|
||||
@@ -826,6 +844,9 @@ impl EditorSession {
|
||||
}
|
||||
return Ok(changed);
|
||||
}
|
||||
if self.editor.diff().is_some() && !self.editor.diff_editing() {
|
||||
return Ok(false);
|
||||
}
|
||||
let changed = !effects.is_empty();
|
||||
self.editor.apply(effects)?;
|
||||
Ok(changed)
|
||||
@@ -3314,11 +3335,131 @@ end
|
||||
});
|
||||
assert_eq!(session.editor().context().text, "original");
|
||||
assert_eq!(fs::read_to_string(&source).unwrap(), "original");
|
||||
session.handle(Input::Escape);
|
||||
session.execute("diff.close");
|
||||
session.execute("ping");
|
||||
drain_until(&mut session, |session| {
|
||||
session.editor().message() == "still alive"
|
||||
});
|
||||
assert_eq!(session.editor().context().text, "original");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_responses_edit_only_current_bound_working_after_and_refresh_projection() {
|
||||
use crate::diff::{
|
||||
Catalog, Category, ChangedFile, Comparison, FileStatus, RepoKind, Revision,
|
||||
RevisionTarget,
|
||||
};
|
||||
let fixture = Fixture::new();
|
||||
fixture.file("buffer.txt", "base");
|
||||
let mut session = fixture.open("");
|
||||
session.editor.execute("diff");
|
||||
let (id, _) = session.editor.take_diff_request().unwrap();
|
||||
let revision = |target, label: &str| Revision {
|
||||
target,
|
||||
label: label.into(),
|
||||
description: String::new(),
|
||||
category: Category::Commits,
|
||||
};
|
||||
session.editor.apply_diff_result(
|
||||
id,
|
||||
Ok(DiffOutcome::Catalog(Catalog {
|
||||
kind: RepoKind::Git,
|
||||
notice: None,
|
||||
entries: vec![
|
||||
revision(RevisionTarget::Commit("base".into()), "base"),
|
||||
revision(RevisionTarget::Working, "Working"),
|
||||
],
|
||||
})),
|
||||
);
|
||||
for input in [Input::Down, Input::Enter, Input::Enter] {
|
||||
session.editor.handle(input);
|
||||
}
|
||||
let (id, _) = session.editor.take_diff_request().unwrap();
|
||||
session.editor.apply_diff_result(
|
||||
id,
|
||||
Ok(DiffOutcome::Comparison(Comparison {
|
||||
root: fixture.0.canonicalize().unwrap(),
|
||||
before: "base".into(),
|
||||
after: "Working".into(),
|
||||
editable_paths: [PathBuf::from("buffer.txt")].into_iter().collect(),
|
||||
files: vec![ChangedFile {
|
||||
path: PathBuf::from("buffer.txt"),
|
||||
old_path: None,
|
||||
status: FileStatus::Modified,
|
||||
before: vec!["base".into()],
|
||||
after: vec!["base".into()],
|
||||
before_eof: false,
|
||||
after_eof: false,
|
||||
hunks: Vec::new(),
|
||||
notice: None,
|
||||
}],
|
||||
})),
|
||||
);
|
||||
session.editor.handle(Input::BackTab);
|
||||
let source = InvocationSource {
|
||||
buffer_id: session.editor.buffer_id(),
|
||||
revision: session.editor.text_revision(),
|
||||
};
|
||||
session
|
||||
.requests
|
||||
.entry("fixture".into())
|
||||
.or_default()
|
||||
.pending
|
||||
.insert(1, source);
|
||||
assert!(
|
||||
session
|
||||
.apply_response("fixture", 1, vec![Effect::Insert("accepted".into())])
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(session.editor.lines(), ["acceptedbase"]);
|
||||
let diff = session.editor.diff().unwrap();
|
||||
assert_eq!(diff.live_revision, Some(session.editor.text_revision()));
|
||||
assert_eq!(
|
||||
diff.comparison.as_ref().unwrap().files[0].after,
|
||||
session.editor.lines()
|
||||
);
|
||||
|
||||
session
|
||||
.requests
|
||||
.get_mut("fixture")
|
||||
.unwrap()
|
||||
.pending
|
||||
.insert(2, source);
|
||||
assert!(
|
||||
!session
|
||||
.apply_response("fixture", 2, vec![Effect::Insert("stale".into())])
|
||||
.unwrap()
|
||||
);
|
||||
let current = InvocationSource {
|
||||
buffer_id: session.editor.buffer_id(),
|
||||
revision: session.editor.text_revision(),
|
||||
};
|
||||
session.editor.scroll_diff(Focus::Before, false);
|
||||
session
|
||||
.requests
|
||||
.get_mut("fixture")
|
||||
.unwrap()
|
||||
.pending
|
||||
.insert(3, current);
|
||||
assert!(
|
||||
!session
|
||||
.apply_response("fixture", 3, vec![Effect::Insert("readonly".into())])
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(session.editor.lines(), ["acceptedbase"]);
|
||||
session
|
||||
.requests
|
||||
.get_mut("fixture")
|
||||
.unwrap()
|
||||
.pending
|
||||
.insert(4, current);
|
||||
assert!(
|
||||
session
|
||||
.apply_response("fixture", 4, vec![Effect::Message("allowed".into())])
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(session.editor.message(), "allowed");
|
||||
session.editor.execute("diff.close");
|
||||
assert!(session.editor.dirty());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user