Support long diff conflict markers
git can be configured to use more than 7 characters for conflict markers, and jj automatically uses longer conflict markers when the text contains any char sequence that could be confused with conflict markers. Ensure that we only point at markers that are consistent with the start marker's length. Ensure that we only consider char sequences at the beginning of a line as a diff marker.
This commit is contained in:
parent
5497a36a7f
commit
ebd4bc9224
3 changed files with 74 additions and 11 deletions
|
|
@ -3037,27 +3037,53 @@ impl<'a> Parser<'a> {
|
|||
long_kind: &TokenKind,
|
||||
short_kind: &TokenKind,
|
||||
) -> bool {
|
||||
(0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
|
||||
&& self.look_ahead(3, |tok| tok == short_kind)
|
||||
if long_kind == short_kind {
|
||||
// For conflict marker chars like `%` and `\`.
|
||||
(0..7).all(|i| self.look_ahead(i, |tok| tok == long_kind))
|
||||
} else {
|
||||
// For conflict marker chars like `<` and `|`.
|
||||
(0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
|
||||
&& self.look_ahead(3, |tok| tok == short_kind || tok == long_kind)
|
||||
}
|
||||
}
|
||||
|
||||
fn conflict_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> Option<Span> {
|
||||
fn conflict_marker(
|
||||
&mut self,
|
||||
long_kind: &TokenKind,
|
||||
short_kind: &TokenKind,
|
||||
expected: Option<usize>,
|
||||
) -> Option<(Span, usize)> {
|
||||
if self.is_vcs_conflict_marker(long_kind, short_kind) {
|
||||
let lo = self.token.span;
|
||||
for _ in 0..4 {
|
||||
self.bump();
|
||||
if self.psess.source_map().span_to_margin(lo) != Some(0) {
|
||||
return None;
|
||||
}
|
||||
return Some(lo.to(self.prev_token.span));
|
||||
let mut len = 0;
|
||||
while self.token.kind == *long_kind || self.token.kind == *short_kind {
|
||||
if self.token.kind.break_two_token_op(1).is_some() {
|
||||
len += 2;
|
||||
} else {
|
||||
len += 1;
|
||||
}
|
||||
self.bump();
|
||||
if expected == Some(len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if expected.is_some() && expected != Some(len) {
|
||||
return None;
|
||||
}
|
||||
return Some((lo.to(self.prev_token.span), len));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(super) fn recover_vcs_conflict_marker(&mut self) {
|
||||
// <<<<<<<
|
||||
let Some(start) = self.conflict_marker(&TokenKind::Shl, &TokenKind::Lt) else {
|
||||
let Some((start, len)) = self.conflict_marker(&TokenKind::Shl, &TokenKind::Lt, None) else {
|
||||
return;
|
||||
};
|
||||
let mut spans = Vec::with_capacity(3);
|
||||
let mut spans = Vec::with_capacity(2);
|
||||
spans.push(start);
|
||||
// |||||||
|
||||
let mut middlediff3 = None;
|
||||
|
|
@ -3069,13 +3095,19 @@ impl<'a> Parser<'a> {
|
|||
if self.token == TokenKind::Eof {
|
||||
break;
|
||||
}
|
||||
if let Some(span) = self.conflict_marker(&TokenKind::OrOr, &TokenKind::Or) {
|
||||
if let Some((span, _)) =
|
||||
self.conflict_marker(&TokenKind::OrOr, &TokenKind::Or, Some(len))
|
||||
{
|
||||
middlediff3 = Some(span);
|
||||
}
|
||||
if let Some(span) = self.conflict_marker(&TokenKind::EqEq, &TokenKind::Eq) {
|
||||
if let Some((span, _)) =
|
||||
self.conflict_marker(&TokenKind::EqEq, &TokenKind::Eq, Some(len))
|
||||
{
|
||||
middle = Some(span);
|
||||
}
|
||||
if let Some(span) = self.conflict_marker(&TokenKind::Shr, &TokenKind::Gt) {
|
||||
if let Some((span, _)) =
|
||||
self.conflict_marker(&TokenKind::Shr, &TokenKind::Gt, Some(len))
|
||||
{
|
||||
spans.push(span);
|
||||
end = Some(span);
|
||||
break;
|
||||
|
|
|
|||
11
tests/ui/parser/diff-markers/long-conflict-markers.rs
Normal file
11
tests/ui/parser/diff-markers/long-conflict-markers.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
enum E {
|
||||
Foo {
|
||||
<<<<<<<<< HEAD //~ ERROR encountered diff marker
|
||||
x: u8,
|
||||
|||||||
|
||||
z: (),
|
||||
=========
|
||||
y: i8,
|
||||
>>>>>>>>> branch
|
||||
}
|
||||
}
|
||||
20
tests/ui/parser/diff-markers/long-conflict-markers.stderr
Normal file
20
tests/ui/parser/diff-markers/long-conflict-markers.stderr
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
error: encountered diff marker
|
||||
--> $DIR/long-conflict-markers.rs:3:1
|
||||
|
|
||||
LL | <<<<<<<<< HEAD
|
||||
| ^^^^^^^^^ between this marker and `=======` is the code that you are merging into
|
||||
...
|
||||
LL | =========
|
||||
| --------- between this marker and `>>>>>>>` is the incoming code
|
||||
LL | y: i8,
|
||||
LL | >>>>>>>>> branch
|
||||
| ^^^^^^^^^ this marker concludes the conflict region
|
||||
|
|
||||
= note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts
|
||||
to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers
|
||||
= help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code
|
||||
if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased
|
||||
= note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue