patch: IDEA-125412 support N lines of context in patch builder
authorNadya Zabrodina <Nadya.Zabrodina@jetbrains.com>
Wed, 7 Apr 2021 08:34:33 +0000 (11:34 +0300)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Tue, 13 Apr 2021 16:10:24 +0000 (16:10 +0000)
* provide a registry key

GitOrigin-RevId: 1132a76e00527f58c43a605cb798e5866b837412

platform/platform-tests/testData/diff/patch/contextLineCount/after/1.txt [new file with mode: 0644]
platform/platform-tests/testData/diff/patch/contextLineCount/before/1.txt [new file with mode: 0644]
platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/patch/PatchBuilderTest.java
platform/vcs-impl/resources/META-INF/VcsExtensions.xml
platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java

diff --git a/platform/platform-tests/testData/diff/patch/contextLineCount/after/1.txt b/platform/platform-tests/testData/diff/patch/contextLineCount/after/1.txt
new file mode 100644 (file)
index 0000000..79b9f6c
--- /dev/null
@@ -0,0 +1,8 @@
+one
+two
+four
+five
+six
+seven
+eight
+nine
\ No newline at end of file
diff --git a/platform/platform-tests/testData/diff/patch/contextLineCount/before/1.txt b/platform/platform-tests/testData/diff/patch/contextLineCount/before/1.txt
new file mode 100644 (file)
index 0000000..533481e
--- /dev/null
@@ -0,0 +1,9 @@
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
\ No newline at end of file
index ecedf57ac647d5feb5ccb4519613b25a8a2e90c3..dab0d9bbad9843ae275fbcbe9a7d469e92b23897 100644 (file)
@@ -4,6 +4,7 @@ package com.intellij.openapi.diff.impl.patch;
 
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.registry.Registry;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vcs.FilePath;
 import com.intellij.openapi.vcs.VcsException;
@@ -126,6 +127,12 @@ public class PatchBuilderTest extends LightPlatformTestCase {
     doTest(getProject(), true);
   }
 
+  public void testContextLineCount() throws Exception {
+    Registry.get("patch.context.line.count").setValue(5);
+    doTest(getProject(), true, null);
+    Registry.get("patch.context.line.count").resetToDefault();
+  }
+
   private void doTest() throws IOException, VcsException {
     doTest(getProject(), true);
   }
index 11d93e7d7984bd07a17e92d293892ce6b3f34c6f..cdc6808b66bf711f0e1858f54e531699c83348fa 100644 (file)
     <statistics.notificationIdsHolder implementation="com.intellij.openapi.vcs.VcsNotificationIdsHolder"/>
 
     <diff.editor.diffRequestProcessorEditorCustomizer implementation="com.intellij.openapi.vcs.changes.ShowDiffInEditorTooltipInstaller"/>
+    <registryKey key="patch.context.line.count" defaultValue="3" description="Number of context lines for creating patches"/>
   </extensions>
 
   <extensions defaultExtensionNs="org.jetbrains">
index b9183bffb3a62a7d7445e5a98c1e4db5b8fcca9e..be80c04cc2844d664d7f04085f0ad41fb8b49d2c 100644 (file)
@@ -7,6 +7,7 @@ import com.intellij.diff.comparison.DiffTooBigException;
 import com.intellij.diff.comparison.iterables.FairDiffIterable;
 import com.intellij.diff.util.Range;
 import com.intellij.openapi.progress.DumbProgressIndicator;
+import com.intellij.openapi.util.registry.Registry;
 import com.intellij.openapi.util.text.LineTokenizer;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vcs.FileStatus;
@@ -38,6 +39,7 @@ public final class TextPatchBuilder {
 
   @NotNull private final Path myBasePath;
   private final boolean myIsReversePath;
+  private final int myContextLineCount = Registry.get("patch.context.line.count").asInteger();
   @Nullable private final Runnable myCancelChecker;
 
   private TextPatchBuilder(@NotNull Path basePath,
@@ -102,7 +104,7 @@ public final class TextPatchBuilder {
 
     TextFilePatch patch = buildPatchHeading(beforeRevision, afterRevision);
 
-    List<PatchHunk> hunks = buildPatchHunks(beforeContent, afterContent);
+    List<PatchHunk> hunks = buildPatchHunks(beforeContent, afterContent, myContextLineCount);
     for (PatchHunk hunk : hunks) {
       patch.addHunk(hunk);
     }
@@ -113,8 +115,14 @@ public final class TextPatchBuilder {
     return patch;
   }
 
+  @SuppressWarnings("unused")
   @NotNull
   public static List<PatchHunk> buildPatchHunks(@NotNull String beforeContent, @NotNull String afterContent) {
+    return buildPatchHunks(beforeContent, afterContent, CONTEXT_LINES);
+  }
+
+  @NotNull
+  public static List<PatchHunk> buildPatchHunks(@NotNull String beforeContent, @NotNull String afterContent, int contextLineCount) {
     if (beforeContent.equals(afterContent)) return Collections.emptyList();
     if (beforeContent.isEmpty()) {
       return singletonList(createWholeFileHunk(afterContent, true, true));
@@ -134,9 +142,9 @@ public final class TextPatchBuilder {
 
     int hunkStart = 0;
     while (hunkStart < fragments.size()) {
-      List<Range> hunkFragments = getAdjacentFragments(fragments, hunkStart);
+      List<Range> hunkFragments = getAdjacentFragments(fragments, hunkStart, contextLineCount);
 
-      hunks.add(createHunk(hunkFragments, beforeLines, afterLines, beforeNoNewlineAtEOF, afterNoNewlineAtEOF));
+      hunks.add(createHunk(hunkFragments, beforeLines, afterLines, beforeNoNewlineAtEOF, afterNoNewlineAtEOF, contextLineCount));
 
       hunkStart += hunkFragments.size();
     }
@@ -145,14 +153,14 @@ public final class TextPatchBuilder {
   }
 
   @NotNull
-  private static List<Range> getAdjacentFragments(@NotNull List<Range> fragments, int hunkStart) {
+  private static List<Range> getAdjacentFragments(@NotNull List<Range> fragments, int hunkStart, int contextLineCount) {
     int hunkEnd = hunkStart + 1;
     while (hunkEnd < fragments.size()) {
       Range lastFragment = fragments.get(hunkEnd - 1);
       Range nextFragment = fragments.get(hunkEnd);
 
-      if (lastFragment.end1 + CONTEXT_LINES < nextFragment.start1 - CONTEXT_LINES &&
-          lastFragment.end2 + CONTEXT_LINES < nextFragment.start2 - CONTEXT_LINES) {
+      if (lastFragment.end1 + contextLineCount < nextFragment.start1 - contextLineCount &&
+          lastFragment.end2 + contextLineCount < nextFragment.start2 - contextLineCount) {
         break;
       }
       hunkEnd++;
@@ -165,14 +173,15 @@ public final class TextPatchBuilder {
                                       @NotNull List<String> beforeLines,
                                       @NotNull List<String> afterLines,
                                       boolean beforeNoNewlineAtEOF,
-                                      boolean afterNoNewlineAtEOF) {
+                                      boolean afterNoNewlineAtEOF,
+                                      int contextLineCount) {
     Range first = hunkFragments.get(0);
     Range last = hunkFragments.get(hunkFragments.size() - 1);
 
-    int contextStart1 = Math.max(first.start1 - CONTEXT_LINES, 0);
-    int contextStart2 = Math.max(first.start2 - CONTEXT_LINES, 0);
-    int contextEnd1 = Math.min(last.end1 + CONTEXT_LINES, beforeLines.size());
-    int contextEnd2 = Math.min(last.end2 + CONTEXT_LINES, afterLines.size());
+    int contextStart1 = Math.max(first.start1 - contextLineCount, 0);
+    int contextStart2 = Math.max(first.start2 - contextLineCount, 0);
+    int contextEnd1 = Math.min(last.end1 + contextLineCount, beforeLines.size());
+    int contextEnd2 = Math.min(last.end2 + contextLineCount, afterLines.size());
 
     PatchHunk hunk = new PatchHunk(contextStart1, contextEnd1, contextStart2, contextEnd2);
 
@@ -280,7 +289,7 @@ public final class TextPatchBuilder {
     TextFilePatch result = buildPatchHeading(afterRevision, afterRevision);
     result.setFileStatus(FileStatus.ADDED);
     String content = getContent(afterRevision);
-    if(!content.isEmpty()) {
+    if (!content.isEmpty()) {
       result.addHunk(createWholeFileHunk(content, true, false));
     }
     return result;
@@ -363,7 +372,8 @@ public final class TextPatchBuilder {
     String beforeContent = revision.getContentAsString();
     if (beforeContent == null) {
       throw new VcsException(
-        VcsBundle.message("patch.failed.to.fetch.old.content.for.file.name.in.revision", revision.getPath().getPath(),revision.getRevisionNumber()));
+        VcsBundle.message("patch.failed.to.fetch.old.content.for.file.name.in.revision", revision.getPath().getPath(),
+                          revision.getRevisionNumber()));
     }
     return beforeContent;
   }