feat: support comments in ordinary source buffers

This commit is contained in:
2026-10-22 22:30:16 +02:00
parent ac5c64981d
commit e6d94dcb41
16 changed files with 1005 additions and 600 deletions
+99 -59
View File
@@ -990,96 +990,91 @@ core_actions![
true,
),
(
"core.diff.comment",
Action::DiffComment,
"core.comment",
Action::Comment,
&[Mode::Normal, Mode::Visual],
true
),
(
"core.diff.review.edit",
"core.review.edit",
Action::ReviewEdit,
&[Mode::Normal],
true,
true
),
(
"core.diff.review.delete",
"core.review.delete",
Action::ReviewDelete,
&[Mode::Normal],
true,
true
),
(
"core.diff.review.resolve",
"core.review.resolve",
Action::ReviewResolve,
&[Mode::Normal],
true,
true
),
(
"core.diff.review.unresolve",
"core.review.unresolve",
Action::ReviewUnresolve,
&[Mode::Normal],
true,
true
),
(
"core.diff.review.next",
"core.review.next",
Action::ReviewNext,
&[Mode::Normal],
true
),
(
"core.diff.review.previous",
"core.review.previous",
Action::ReviewPrevious,
&[Mode::Normal],
true
),
(
"core.diff.review.overview",
"core.review.overview",
Action::ReviewOverview,
&[Mode::Normal],
true
),
(
"core.diff.review.copy",
"core.review.copy",
Action::ReviewCopy,
&[Mode::Normal],
true
),
(
"core.diff.review.summary",
"core.review.summary",
Action::ReviewSummary,
&[Mode::Normal],
true
),
(
"core.diff.review.verdict",
"core.review.verdict",
Action::ReviewVerdict,
&[Mode::Normal],
true,
true
),
(
"core.diff.review.save",
"core.review.save",
Action::ReviewSave,
&[Mode::Normal],
true,
true
),
(
"core.diff.review.open",
"core.review.open",
Action::ReviewOpen,
&[Mode::Normal],
true,
true
),
(
"core.diff.review.new",
Action::ReviewNew,
&[Mode::Normal],
true
),
("core.review.new", Action::ReviewNew, &[Mode::Normal], true),
(
"core.word_wrap.toggle",
Action::WordWrapToggle,
@@ -1193,6 +1188,20 @@ const COMMAND_ALIASES: &[(&str, Action)] = &[
("bprev", Action::BufferPrevious),
("bdelete", Action::BufferDelete),
("bdelete!", Action::BufferForceDelete),
("diff.comment", Action::Comment),
("diff.review.edit", Action::ReviewEdit),
("diff.review.delete", Action::ReviewDelete),
("diff.review.resolve", Action::ReviewResolve),
("diff.review.unresolve", Action::ReviewUnresolve),
("diff.review.next", Action::ReviewNext),
("diff.review.previous", Action::ReviewPrevious),
("diff.review.overview", Action::ReviewOverview),
("diff.review.copy", Action::ReviewCopy),
("diff.review.summary", Action::ReviewSummary),
("diff.review.verdict", Action::ReviewVerdict),
("diff.review.save", Action::ReviewSave),
("diff.review.open", Action::ReviewOpen),
("diff.review.new", Action::ReviewNew),
];
fn core_command(name: &str) -> Option<&'static CoreAction> {
@@ -1893,6 +1902,7 @@ struct Tab {
pane_id: usize,
pane_layout: PaneTree,
review_pane: Option<usize>,
local_review: crate::review::ReviewState,
file_picker: Option<FilePicker>,
diff: Option<DiffState>,
parked_diff: Option<DiffState>,
@@ -2200,6 +2210,7 @@ pub struct Editor {
panes: BTreeMap<usize, Pane>,
pane_layout: PaneTree,
review_pane: Option<usize>,
pub(crate) local_review: crate::review::ReviewState,
tab_id: usize,
next_tab_id: usize,
tab_order: Vec<usize>,
@@ -2313,6 +2324,7 @@ impl Editor {
)]),
pane_layout: PaneTree::new(1),
review_pane: None,
local_review: Default::default(),
tab_id: 1,
next_tab_id: 2,
tab_order: vec![1],
@@ -3663,6 +3675,7 @@ impl Editor {
pane_id: std::mem::replace(&mut self.pane_id, next.pane_id),
pane_layout: std::mem::replace(&mut self.pane_layout, next.pane_layout),
review_pane: std::mem::replace(&mut self.review_pane, next.review_pane),
local_review: std::mem::replace(&mut self.local_review, next.local_review),
file_picker: std::mem::replace(&mut self.file_picker, next.file_picker),
diff: std::mem::replace(&mut self.diff, next.diff),
parked_diff: std::mem::replace(&mut self.parked_diff, next.parked_diff),
@@ -3712,6 +3725,7 @@ impl Editor {
pane_id,
pane_layout: PaneTree::new(pane_id),
review_pane: None,
local_review: Default::default(),
file_picker: None,
diff: None,
parked_diff: None,
@@ -3814,11 +3828,6 @@ impl Editor {
// No input dispatch or document copies: source documents stay unique in active/parked.
fn select_pane(&mut self, id: usize) {
let id = if self.review_pane == Some(id) && self.workspace_diff().is_none() {
self.panes[&id].origin.unwrap_or(id)
} else {
id
};
if id == self.pane_id {
return;
}
@@ -4223,7 +4232,12 @@ impl Editor {
return;
}
self.finish_pane_interaction();
if self.diff_owner == Some(id) && !force && self.local_review_close_blocked() {
let review_source =
self.review_pane.and_then(|panel| self.panes[&panel].origin) == Some(id);
if (self.diff_owner == Some(id) || review_source)
&& !force
&& self.local_review_close_blocked()
{
return;
}
if self.diff_owner == Some(id) {
@@ -4236,6 +4250,9 @@ impl Editor {
}
let next = self.pane_layout.close(id).expect("another pane exists");
self.select_pane(next);
if review_source && let Some(panel) = self.review_pane {
self.panes.get_mut(&panel).unwrap().origin = Some(next);
}
self.panes.remove(&id);
for buffer in buffers {
self.forget_buffer(buffer);
@@ -4627,11 +4644,17 @@ impl Editor {
view.clamp(&self.active.lines);
self.active.view = view;
}
if let Err(error) = self.initialize_local_review() {
if self.review_directory.is_some()
&& self.resolver().is_none()
&& self
.workspace_diff()
.is_some_and(|diff| diff.phase == Phase::View)
&& let Err(error) = self.initialize_local_review()
{
self.set_message(format!("Local review: {error}"));
}
if restore_reviewed && let Some(diff) = &mut self.diff {
diff.restore_reviewed_files();
diff.restore_reviewed_files(&self.local_review);
}
let reviewed = self.diff.as_mut().and_then(|diff| {
(refresh
@@ -5190,16 +5213,19 @@ impl Editor {
pub(crate) fn refresh_live_diff(&mut self) {
self.refresh_resolver_comparison();
for diff in self
.diff
.iter_mut()
.chain(self.parked_diff.iter_mut())
.chain(
self.tabs
.values_mut()
.flat_map(|tab| tab.diff.iter_mut().chain(tab.parked_diff.iter_mut())),
)
{
for (diff, parked, review) in std::iter::once((
&mut self.diff,
&mut self.parked_diff,
&mut self.local_review,
))
.chain(
self.tabs
.values_mut()
.map(|tab| (&mut tab.diff, &mut tab.parked_diff, &mut tab.local_review)),
) {
let Some(diff) = diff.as_mut().or(parked.as_mut()) else {
continue;
};
let buffer = diff.live_buffer.and_then(|id| {
if id == self.active.id {
Some(&self.active)
@@ -5211,7 +5237,7 @@ impl Editor {
&& diff.live_after_available()
&& diff.live_revision != Some(buffer.text_revision)
{
diff.refresh_after(&buffer.lines, buffer.text_revision);
diff.refresh_after(&buffer.lines, buffer.text_revision, review);
diff.follow_caret = true;
}
}
@@ -5485,7 +5511,7 @@ impl Editor {
| Action::DiffViewToggle
| Action::DiffOrientationToggle
| Action::DiffReviewToggle
| Action::DiffComment
| Action::Comment
| Action::ReviewEdit
| Action::ReviewDelete
| Action::ReviewResolve
@@ -8917,7 +8943,7 @@ impl Editor {
| Action::DiffViewToggle
| Action::DiffOrientationToggle
| Action::DiffReviewToggle
| Action::DiffComment
| Action::Comment
| Action::ReviewEdit
| Action::ReviewDelete
| Action::ReviewResolve
@@ -9559,15 +9585,22 @@ impl Editor {
.map(|buffer| buffer.id);
if let Some(id) = loaded {
self.switch_buffer(id);
return Ok(());
} else {
let buffer = Buffer::open(
self.next_buffer_id,
Some(path),
Some(identity),
allow_missing,
)?;
self.add_buffer(buffer);
}
if self.review_directory.is_some()
&& self.workspace_diff().is_none()
&& self.resolver().is_none()
&& let Err(error) = self.initialize_local_review()
{
self.set_message(format!("Local review: {error}"));
}
let buffer = Buffer::open(
self.next_buffer_id,
Some(path),
Some(identity),
allow_missing,
)?;
self.add_buffer(buffer);
Ok(())
}
@@ -9745,7 +9778,7 @@ impl Editor {
fn restart(&mut self, force: bool) {
if !force && self.local_reviews_dirty() {
self.set_message("Unsaved local review; use :diff.review.save <path>");
self.set_message("Unsaved local review; use :review.save <path>");
return;
}
if force || !self.any_dirty() {
@@ -9876,7 +9909,7 @@ impl Editor {
}
if matches!(
entry.action,
Action::DiffComment
Action::Comment
| Action::ReviewEdit
| Action::ReviewDelete
| Action::ReviewResolve
@@ -10102,15 +10135,15 @@ impl Editor {
self.diff_return_buffer = Some(self.active.id);
return None;
}
let Some(diff) = self
.picker_diff_mut()
.filter(|diff| diff.phase == Phase::View)
else {
self.set_message("No comparison is open");
return None;
};
if entry.action == Action::DiffReviewToggle {
match diff.toggle_reviewed() {
let mut review = std::mem::take(&mut self.local_review);
let result = self
.picker_diff_mut()
.filter(|diff| diff.phase == Phase::View)
.ok_or("No comparison is open")
.and_then(|diff| diff.toggle_reviewed(&mut review));
self.local_review = review;
match result {
Ok(reviewed) => {
if self.resolver().is_none()
&& let Err(error) = self.autosave_local_review()
@@ -10128,6 +10161,13 @@ impl Editor {
}
return None;
}
let Some(diff) = self
.picker_diff_mut()
.filter(|diff| diff.phase == Phase::View)
else {
self.set_message("No comparison is open");
return None;
};
if entry.action == Action::DiffViewToggle {
diff.set_view_mode(match diff.view_mode {
ViewMode::Split => ViewMode::Unified,