diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index d27bbf879f..0a072a3b8a 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -429,6 +429,7 @@ namespace ts { case CharacterCodes.slash: // starts of normal trivia case CharacterCodes.lessThan: + case CharacterCodes.bar: case CharacterCodes.equals: case CharacterCodes.greaterThan: // Starts of conflict marker trivia @@ -496,6 +497,7 @@ namespace ts { break; case CharacterCodes.lessThan: + case CharacterCodes.bar: case CharacterCodes.equals: case CharacterCodes.greaterThan: if (isConflictMarkerTrivia(text, pos)) { @@ -562,12 +564,12 @@ namespace ts { } } else { - Debug.assert(ch === CharacterCodes.equals); - // Consume everything from the start of the mid-conflict marker to the start of the next - // end-conflict marker. + Debug.assert(ch === CharacterCodes.bar || ch === CharacterCodes.equals); + // Consume everything from the start of a ||||||| or ======= marker to the start + // of the next ======= or >>>>>>> marker. while (pos < len) { - const ch = text.charCodeAt(pos); - if (ch === CharacterCodes.greaterThan && isConflictMarkerTrivia(text, pos)) { + const currentChar = text.charCodeAt(pos); + if ((currentChar === CharacterCodes.equals || currentChar === CharacterCodes.greaterThan) && currentChar !== ch && isConflictMarkerTrivia(text, pos)) { break; } @@ -1562,6 +1564,16 @@ namespace ts { pos++; return token = SyntaxKind.OpenBraceToken; case CharacterCodes.bar: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos, error); + if (skipTrivia) { + continue; + } + else { + return token = SyntaxKind.ConflictMarkerTrivia; + } + } + if (text.charCodeAt(pos + 1) === CharacterCodes.bar) { return pos += 2, token = SyntaxKind.BarBarToken; } diff --git a/src/harness/unittests/services/colorization.ts b/src/harness/unittests/services/colorization.ts index fd7d932885..3fed9ec616 100644 --- a/src/harness/unittests/services/colorization.ts +++ b/src/harness/unittests/services/colorization.ts @@ -424,6 +424,50 @@ class D { }\r\n\ comment("=======\r\nclass D { }\r\n"), comment(">>>>>>> Branch - a"), finalEndOfLineState(ts.EndOfLineState.None)); + + testLexicalClassification( +"class C {\r\n\ +<<<<<<< HEAD\r\n\ + v = 1;\r\n\ +||||||| merged common ancestors\r\n\ + v = 3;\r\n\ +=======\r\n\ + v = 2;\r\n\ +>>>>>>> Branch - a\r\n\ +}", + ts.EndOfLineState.None, + keyword("class"), + identifier("C"), + punctuation("{"), + comment("<<<<<<< HEAD"), + identifier("v"), + operator("="), + numberLiteral("1"), + punctuation(";"), + comment("||||||| merged common ancestors\r\n v = 3;\r\n"), + comment("=======\r\n v = 2;\r\n"), + comment(">>>>>>> Branch - a"), + punctuation("}"), + finalEndOfLineState(ts.EndOfLineState.None)); + + testLexicalClassification( +"<<<<<<< HEAD\r\n\ +class C { }\r\n\ +||||||| merged common ancestors\r\n\ +class E { }\r\n\ +=======\r\n\ +class D { }\r\n\ +>>>>>>> Branch - a\r\n", + ts.EndOfLineState.None, + comment("<<<<<<< HEAD"), + keyword("class"), + identifier("C"), + punctuation("{"), + punctuation("}"), + comment("||||||| merged common ancestors\r\nclass E { }\r\n"), + comment("=======\r\nclass D { }\r\n"), + comment(">>>>>>> Branch - a"), + finalEndOfLineState(ts.EndOfLineState.None)); }); it("'of' keyword", function () { diff --git a/src/services/classifier.ts b/src/services/classifier.ts index acee8fe4b0..beeddda434 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -685,9 +685,9 @@ namespace ts { continue; } - // for the ======== add a comment for the first line, and then lex all - // subsequent lines up until the end of the conflict marker. - Debug.assert(ch === CharacterCodes.equals); + // for the ||||||| and ======== markers, add a comment for the first line, + // and then lex all subsequent lines up until the end of the conflict marker. + Debug.assert(ch === CharacterCodes.bar || ch === CharacterCodes.equals); classifyDisabledMergeCode(text, start, end); } } @@ -782,8 +782,8 @@ namespace ts { } function classifyDisabledMergeCode(text: string, start: number, end: number) { - // Classify the line that the ======= marker is on as a comment. Then just lex - // all further tokens and add them to the result. + // Classify the line that the ||||||| or ======= marker is on as a comment. + // Then just lex all further tokens and add them to the result. let i: number; for (i = start; i < end; i++) { if (isLineBreak(text.charCodeAt(i))) { diff --git a/tests/baselines/reference/conflictMarkerDiff3Trivia1.errors.txt b/tests/baselines/reference/conflictMarkerDiff3Trivia1.errors.txt new file mode 100644 index 0000000000..b38e4e189e --- /dev/null +++ b/tests/baselines/reference/conflictMarkerDiff3Trivia1.errors.txt @@ -0,0 +1,24 @@ +tests/cases/compiler/conflictMarkerDiff3Trivia1.ts(2,1): error TS1185: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerDiff3Trivia1.ts(4,1): error TS1185: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerDiff3Trivia1.ts(6,1): error TS1185: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerDiff3Trivia1.ts(8,1): error TS1185: Merge conflict marker encountered. + + +==== tests/cases/compiler/conflictMarkerDiff3Trivia1.ts (4 errors) ==== + class C { + <<<<<<< HEAD + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + v = 1; + ||||||| merged common ancestors + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + v = 3; + ======= + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + v = 2; + >>>>>>> Branch-a + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + } \ No newline at end of file diff --git a/tests/baselines/reference/conflictMarkerDiff3Trivia1.js b/tests/baselines/reference/conflictMarkerDiff3Trivia1.js new file mode 100644 index 0000000000..86cccd44e1 --- /dev/null +++ b/tests/baselines/reference/conflictMarkerDiff3Trivia1.js @@ -0,0 +1,18 @@ +//// [conflictMarkerDiff3Trivia1.ts] +class C { +<<<<<<< HEAD + v = 1; +||||||| merged common ancestors + v = 3; +======= + v = 2; +>>>>>>> Branch-a +} + +//// [conflictMarkerDiff3Trivia1.js] +var C = (function () { + function C() { + this.v = 1; + } + return C; +}()); diff --git a/tests/baselines/reference/conflictMarkerDiff3Trivia2.errors.txt b/tests/baselines/reference/conflictMarkerDiff3Trivia2.errors.txt new file mode 100644 index 0000000000..2e29826c43 --- /dev/null +++ b/tests/baselines/reference/conflictMarkerDiff3Trivia2.errors.txt @@ -0,0 +1,34 @@ +tests/cases/compiler/conflictMarkerDiff3Trivia2.ts(3,1): error TS1185: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerDiff3Trivia2.ts(4,6): error TS2304: Cannot find name 'a'. +tests/cases/compiler/conflictMarkerDiff3Trivia2.ts(6,1): error TS1185: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerDiff3Trivia2.ts(9,1): error TS1185: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerDiff3Trivia2.ts(12,1): error TS1185: Merge conflict marker encountered. + + +==== tests/cases/compiler/conflictMarkerDiff3Trivia2.ts (5 errors) ==== + class C { + foo() { + <<<<<<< B + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + a(); + ~ +!!! error TS2304: Cannot find name 'a'. + } + ||||||| merged common ancestors + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + c(); + } + ======= + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + b(); + } + >>>>>>> A + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + + public bar() { } + } + \ No newline at end of file diff --git a/tests/baselines/reference/conflictMarkerDiff3Trivia2.js b/tests/baselines/reference/conflictMarkerDiff3Trivia2.js new file mode 100644 index 0000000000..61a2273019 --- /dev/null +++ b/tests/baselines/reference/conflictMarkerDiff3Trivia2.js @@ -0,0 +1,28 @@ +//// [conflictMarkerDiff3Trivia2.ts] +class C { + foo() { +<<<<<<< B + a(); + } +||||||| merged common ancestors + c(); + } +======= + b(); + } +>>>>>>> A + + public bar() { } +} + + +//// [conflictMarkerDiff3Trivia2.js] +var C = (function () { + function C() { + } + C.prototype.foo = function () { + a(); + }; + C.prototype.bar = function () { }; + return C; +}()); diff --git a/tests/cases/compiler/conflictMarkerDiff3Trivia1.ts b/tests/cases/compiler/conflictMarkerDiff3Trivia1.ts new file mode 100644 index 0000000000..072cc4b968 --- /dev/null +++ b/tests/cases/compiler/conflictMarkerDiff3Trivia1.ts @@ -0,0 +1,9 @@ +class C { +<<<<<<< HEAD + v = 1; +||||||| merged common ancestors + v = 3; +======= + v = 2; +>>>>>>> Branch-a +} \ No newline at end of file diff --git a/tests/cases/compiler/conflictMarkerDiff3Trivia2.ts b/tests/cases/compiler/conflictMarkerDiff3Trivia2.ts new file mode 100644 index 0000000000..023d425cd4 --- /dev/null +++ b/tests/cases/compiler/conflictMarkerDiff3Trivia2.ts @@ -0,0 +1,15 @@ +class C { + foo() { +<<<<<<< B + a(); + } +||||||| merged common ancestors + c(); + } +======= + b(); + } +>>>>>>> A + + public bar() { } +} diff --git a/tests/cases/fourslash/formatConflictDiff3Marker1.ts b/tests/cases/fourslash/formatConflictDiff3Marker1.ts new file mode 100644 index 0000000000..f6492a6f60 --- /dev/null +++ b/tests/cases/fourslash/formatConflictDiff3Marker1.ts @@ -0,0 +1,22 @@ +/// + +////class C { +////<<<<<<< HEAD +////v = 1; +////||||||| merged common ancestors +////v = 3; +////======= +////v = 2; +////>>>>>>> Branch - a +////} + +format.document(); +verify.currentFileContentIs("class C {\r\n\ +<<<<<<< HEAD\r\n\ + v = 1;\r\n\ +||||||| merged common ancestors\r\n\ +v = 3;\r\n\ +=======\r\n\ +v = 2;\r\n\ +>>>>>>> Branch - a\r\n\ +}"); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers1.ts b/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers1.ts new file mode 100644 index 0000000000..669705307a --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers1.ts @@ -0,0 +1,23 @@ +/// + +////class C { +////<<<<<<< HEAD +//// v = 1; +////||||||| merged common ancestors +//// v = 3; +////======= +//// v = 2; +////>>>>>>> Branch - a +////} + +const c = classification; +verify.syntacticClassificationsAre( + c.keyword("class"), c.className("C"), c.punctuation("{"), + c.comment("<<<<<<< HEAD"), + c.identifier("v"), c.operator("="), c.numericLiteral("1"), c.punctuation(";"), + c.comment("||||||| merged common ancestors"), + c.identifier("v"), c.punctuation("="), c.numericLiteral("3"), c.punctuation(";"), + c.comment("======="), + c.identifier("v"), c.punctuation("="), c.numericLiteral("2"), c.punctuation(";"), + c.comment(">>>>>>> Branch - a"), + c.punctuation("}")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers2.ts b/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers2.ts new file mode 100644 index 0000000000..1714439718 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers2.ts @@ -0,0 +1,19 @@ +/// + +////<<<<<<< HEAD +////class C { } +////||||||| merged common ancestors +////class E { } +////======= +////class D { } +////>>>>>>> Branch - a + +const c = classification; +verify.syntacticClassificationsAre( + c.comment("<<<<<<< HEAD"), + c.keyword("class"), c.className("C"), c.punctuation("{"), c.punctuation("}"), + c.comment("||||||| merged common ancestors"), + c.keyword("class"), c.identifier("E"), c.punctuation("{"), c.punctuation("}"), + c.comment("======="), + c.keyword("class"), c.identifier("D"), c.punctuation("{"), c.punctuation("}"), + c.comment(">>>>>>> Branch - a")); \ No newline at end of file