Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2000-2015 JetBrains s.r.o.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package com.intellij.openapi.diff.impl.patch;
 
 import  com.intellij.openapi.diff.ex.DiffFragment;
 import  com.intellij.openapi.diff.impl.ComparisonPolicy;
 import  com.intellij.openapi.diff.impl.fragments.LineFragment;
 import  com.intellij.openapi.diff.impl.processing.DiffCorrection;
 import  com.intellij.openapi.diff.impl.processing.DiffFragmentsProcessor;
 import  com.intellij.openapi.diff.impl.processing.DiffPolicy;
 import  com.intellij.openapi.diff.impl.string.DiffString;
 import  com.intellij.openapi.diff.impl.util.TextDiffTypeEnum;
 import  com.intellij.openapi.util.io.FileUtil;
 import  com.intellij.util.BeforeAfter;
 import  com.intellij.util.diff.FilesTooBigForDiffException;
 import  org.jetbrains.annotations.NonNls;
 import  org.jetbrains.annotations.NotNull;
 import  org.jetbrains.annotations.Nullable;
 
 import java.util.List;

Author(s):
yole
 
 public class TextPatchBuilder {
   private static final int CONTEXT_LINES = 3;
   @NonNls private static final String REVISION_NAME_TEMPLATE = "(revision {0})";
   @NonNls private static final String DATE_NAME_TEMPLATE = "(date {0})";
 
   private final String myBasePath;
   private final boolean myIsReversePath;
   private final boolean myIsCaseSensitive;
   @Nullable
   private final Runnable myCancelChecker;
   private final boolean myIncludeBaseText;
 
   private TextPatchBuilder(final String basePathfinal boolean isReversePathfinal boolean isCaseSensitive,
                            @Nullable final Runnable cancelCheckerboolean includeBaseText) {
      = basePath;
      = isReversePath;
      = isCaseSensitive;
      = cancelChecker;
      = includeBaseText;
   }
 
   private void checkCanceled() {
     if ( != null) {
       .run();
     }
   }
 
   public static List<FilePatchbuildPatch(final Collection<BeforeAfter<AirContentRevision>> changesfinal String basePath,
                                            final boolean reversePatch,
                                            final boolean isCaseSensitive,
                                            @Nullable final Runnable cancelChecker,
                                            final boolean includeBaseTextthrows VcsException {
     final TextPatchBuilder builder = new TextPatchBuilder(basePathreversePatchisCaseSensitivecancelCheckerincludeBaseText);
     return builder.build(changes);
   }
 
   private List<FilePatchbuild(final Collection<BeforeAfter<AirContentRevision>> changesthrows VcsException {
     List<FilePatchresult = new ArrayList<FilePatch>();
     for(BeforeAfter<AirContentRevisioncchanges) {
       checkCanceled();
 
       final AirContentRevision beforeRevision;
       final AirContentRevision afterRevision;
       if () {
         beforeRevision = c.getAfter();
         afterRevision = c.getBefore();
       }
       else {
         beforeRevision = c.getBefore();
         afterRevision = c.getAfter();
       }
       if (beforeRevision != null && beforeRevision.getPath().isDirectory()) {
         continue;
       }
       if (afterRevision != null && afterRevision.getPath().isDirectory()) {
         continue;
       }
 
      if ((beforeRevision != null) && beforeRevision.isBinary() || (afterRevision != null) && afterRevision.isBinary()) {
        result.add(buildBinaryPatch(beforeRevisionafterRevision));
        continue;
      }
      if (beforeRevision == null) {
        result.add(buildAddedFile(afterRevision));
        continue;
      }
      if (afterRevision == null) {
        result.add(buildDeletedFile(beforeRevision));
        continue;
      }
      final DiffString beforeContent = DiffString.createNullable(beforeRevision.getContentAsString());
      if (beforeContent == null) {
        throw new VcsException("Failed to fetch old content for changed file " + beforeRevision.getPath().getPath());
      }
      final DiffString afterContent = DiffString.createNullable(afterRevision.getContentAsString());
      if (afterContent == null) {
        throw new VcsException("Failed to fetch new content for changed file " + afterRevision.getPath().getPath());
      }
      DiffString[] beforeLines = tokenize(beforeContent);
      DiffString[] afterLines = tokenize(afterContent);
      DiffFragment[] woFormattingBlocks;
      DiffFragment[] step1lineFragments;
      try {
        woFormattingBlocks = DiffPolicy.LINES_WO_FORMATTING.buildFragments(beforeContentafterContent);
        step1lineFragments = new DiffCorrection.TrueLineBlocks(ComparisonPolicy.DEFAULT).correctAndNormalize(woFormattingBlocks);
      }
      catch (FilesTooBigForDiffException e) {
        throw new VcsException("File '" +  + "' is too big and there are too many changes to build diff"e);
      }
      ArrayList<LineFragment> fragments = new DiffFragmentsProcessor().process(step1lineFragments);
      if (fragments.size() > 1 || (fragments.size() == 1 && fragments.get(0).getType() != null && fragments.get(0).getType() != TextDiffTypeEnum.NONE)) {
        TextFilePatch patch = buildPatchHeading(beforeRevisionafterRevision);
        result.add(patch);
        int lastLine1 = 0;
        int lastLine2 = 0;
        while(fragments.size() > 0) {
          checkCanceled();
          List<LineFragment> adjacentFragments = getAdjacentFragments(fragments);
          if (adjacentFragments.size() > 0) {
            LineFragment first = adjacentFragments.get(0);
            LineFragment last = adjacentFragments.get(adjacentFragments.size()-1);
            final int start1 = first.getStartingLine1();
            final int start2 = first.getStartingLine2();
            final int end1 = last.getStartingLine1() + last.getModifiedLines1();
            final int end2 = last.getStartingLine2() + last.getModifiedLines2();
            int contextStart1 = Math.max(start1 - lastLine1);
            int contextStart2 = Math.max(start2 - lastLine2);
            int contextEnd1 = Math.min(end1 + beforeLines.length);
            int contextEnd2 = Math.min(end2 + afterLines.length);
            PatchHunk hunk = new PatchHunk(contextStart1contextEnd1contextStart2contextEnd2);
            patch.addHunk(hunk);
            for(LineFragment fragmentadjacentFragments) {
              checkCanceled();
              
              for(int i=contextStart1i<fragment.getStartingLine1(); i++) {
                addLineToHunk(hunkbeforeLines[i], PatchLine.Type.CONTEXT);
              }
              for(int i=fragment.getStartingLine1(); i<fragment.getStartingLine1()+fragment.getModifiedLines1(); i++) {
                addLineToHunk(hunkbeforeLines[i], PatchLine.Type.REMOVE);
              }
              for(int i=fragment.getStartingLine2(); i<fragment.getStartingLine2()+fragment.getModifiedLines2(); i++) {
                addLineToHunk(hunkafterLines[i], PatchLine.Type.ADD);
              }
              contextStart1 = fragment.getStartingLine1()+fragment.getModifiedLines1();
            }
            for(int i=contextStart1i<contextEnd1i++) {
              addLineToHunk(hunkbeforeLines[i], PatchLine.Type.CONTEXT);
            }
          }
        }
        checkPathEndLine(patchc.getAfter());
      } else if (! beforeRevision.getPath().equals(afterRevision.getPath())) {
        final TextFilePatch movedPatch = buildMovedFile(beforeRevisionafterRevision);
        checkPathEndLine(movedPatchc.getAfter());
        result.add(movedPatch);
      }
    }
    return result;
  }
  private void checkPathEndLine(TextFilePatch filePatchfinal AirContentRevision crthrows VcsException {
    if (cr == nullreturn;
    if (filePatch.isDeletedFile() || filePatch.getAfterName() == nullreturn;
    final List<PatchHunk> hunks = filePatch.getHunks();
    if (hunks.isEmpty()) return;
    final PatchHunk hunk = hunks.get(hunks.size() - 1);
    final List<PatchLine> lines = hunk.getLines();
    if (lines.isEmpty()) return;
    final String contentAsString = cr.getContentAsString();
    if (contentAsString == nullreturn;
    if (! contentAsString.endsWith("\n")) {
      lines.get(lines.size() - 1).setSuppressNewLine(true);
    }
  }
  @NotNull
  private static DiffString[] tokenize(@NotNull DiffString text) {
    return text.length() == 0 ? new DiffString[]{text} : text.tokenize();
  }
  private FilePatch buildBinaryPatch(final String basePath,
                                            final AirContentRevision beforeRevision,
                                            final AirContentRevision afterRevisionthrows VcsException {
    AirContentRevision headingBeforeRevision = beforeRevision != null ? beforeRevision : afterRevision;
    AirContentRevision headingAfterRevision = afterRevision != null ? afterRevision : beforeRevision;
    byte[] beforeContent = beforeRevision != null ? beforeRevision.getContentAsBytes() : null;
    byte[] afterContent = afterRevision != null ? afterRevision.getContentAsBytes() : null;
    BinaryFilePatch patch = new BinaryFilePatch(beforeContentafterContent);
    setPatchHeading(patchbasePathheadingBeforeRevisionheadingAfterRevision);
    return patch;
  }
  private static void addLineToHunk(@NotNull final PatchHunk hunk, @NotNull final DiffString linefinal PatchLine.Type type) {
    final PatchLine patchLine;
    if (!line.endsWith('\n')) {
      patchLine = new PatchLine(typeline.toString());
      patchLine.setSuppressNewLine(true);
    }
    else {
      patchLine = new PatchLine(typeline.substring(0, line.length() - 1).toString());
    }
    hunk.addLine(patchLine);
  }
  private TextFilePatch buildMovedFile(final String basePathfinal AirContentRevision beforeRevision,
                                       final AirContentRevision afterRevisionthrows VcsException {
    final TextFilePatch result = buildPatchHeading(basePathbeforeRevisionafterRevision);
    final PatchHunk hunk = new PatchHunk(0, 0, 0, 0);
    result.addHunk(hunk);
    return result;
  }
  private TextFilePatch buildAddedFile(final String basePathfinal AirContentRevision afterRevisionthrows VcsException {
    final DiffString content = DiffString.createNullable(afterRevision.getContentAsString());
    if (content == null) {
      throw new VcsException("Failed to fetch content for added file " + afterRevision.getPath().getPath());
    }
    DiffString[] lines = tokenize(content);
    TextFilePatch result = buildPatchHeading(basePathafterRevisionafterRevision);
    PatchHunk hunk = new PatchHunk(-1, -1, 0, lines.length);
    for (DiffString line : lines) {
      checkCanceled();
      addLineToHunk(hunkline, PatchLine.Type.ADD);
    }
    result.addHunk(hunk);
    return result;
  }
  private TextFilePatch buildDeletedFile(String basePathAirContentRevision beforeRevisionthrows VcsException {
    final DiffString content = DiffString.createNullable(beforeRevision.getContentAsString());
    if (content == null) {
      throw new VcsException("Failed to fetch old content for deleted file " + beforeRevision.getPath().getPath());
    }
    DiffString[] lines = tokenize(content);
    TextFilePatch result = buildPatchHeading(basePathbeforeRevisionbeforeRevision);
    PatchHunk hunk = new PatchHunk(0, lines.length, -1, -1);
    for (DiffString line : lines) {
      checkCanceled();
      addLineToHunk(hunkline, PatchLine.Type.REMOVE);
    }
    result.addHunk(hunk);
    return result;
  }
  private static List<LineFragment> getAdjacentFragments(final ArrayList<LineFragment> fragments) {
    List<LineFragment> result = new ArrayList<LineFragment>();
    int endLine = -1;
    while(!fragments.isEmpty()) {
      LineFragment fragment = fragments.get(0);
      if (fragment.getType() == null || fragment.getType() == TextDiffTypeEnum.NONE) {
        fragments.remove(0);
        continue;
      }
      if (result.isEmpty() || endLine +  >= fragment.getStartingLine1() - ) {
        result.add(fragment);
        fragments.remove(0);
        endLine = fragment.getStartingLine1() + fragment.getModifiedLines1();
      }
      else {
        break;
      }
    }
    return result;
  }
  private String getRelativePath(final String basePathfinal String secondPath) {
    final String baseModified = FileUtil.toSystemIndependentName(basePath);
    final String secondModified = FileUtil.toSystemIndependentName(secondPath);
    
    final String relPath = FileUtil.getRelativePath(baseModifiedsecondModified'/');
    if (relPath == nullreturn secondModified;
    return relPath;
  }
  private static String getRevisionName(final AirContentRevision revision) {
    final String revisionName = revision.getRevisionNumber();
    if (revisionName != null) {
      return MessageFormat.format(revisionName);
    }
    return MessageFormat.format(, Long.toString(revision.getPath().lastModified()));
  }
  private TextFilePatch buildPatchHeading(final String basePathfinal AirContentRevision beforeRevisionfinal AirContentRevision afterRevision) {
    TextFilePatch result = new TextFilePatch(afterRevision == null ? null : afterRevision.getCharset());
    setPatchHeading(resultbasePathbeforeRevisionafterRevision);
    return result;
  }
  private void setPatchHeading(final FilePatch resultfinal String basePath,
                                      @NotNull final AirContentRevision beforeRevision,
                                      @NotNull final AirContentRevision afterRevision) {
    result.setBeforeName(getRelativePath(basePathbeforeRevision.getPath().getPath()));
    result.setBeforeVersionId(getRevisionName(beforeRevision));
    result.setAfterName(getRelativePath(basePathafterRevision.getPath().getPath()));
    result.setAfterVersionId(getRevisionName(afterRevision));
  }
New to GrepCode? Check out our FAQ X