import com.intellij.openapi.diff.impl.patch.BinaryFilePatch;
import com.intellij.openapi.diff.impl.patch.FilePatch;
import com.intellij.openapi.diff.impl.patch.PatchReader;
+import com.intellij.openapi.diff.impl.patch.PatchVirtualFileReader;
import com.intellij.openapi.diff.impl.patch.formove.PatchApplier;
import com.intellij.openapi.vfs.VirtualFile;
protected void applyPatch() throws Exception {
List<FilePatch> patches = new ArrayList<FilePatch>();
- PatchReader reader = new PatchReader(getFS().refreshAndFindFileByPath(patchFilePath));
+ PatchReader reader = PatchVirtualFileReader.create(getFS().refreshAndFindFileByPath(patchFilePath));
while (true) {
FilePatch p = reader.readNextPatch();
return Collections.unmodifiableList(myLines);
}
- public ApplyPatchStatus apply(final List<String> lines) throws ApplyPatchException {
- List<String> originalLines = new ArrayList<String>(lines);
- try {
- return tryApply(lines, false);
- }
- catch(ApplyPatchException ex) {
- lines.clear();
- lines.addAll(originalLines);
- return tryApply(lines, true);
- }
- }
-
- private ApplyPatchStatus tryApply(final List<String> lines, boolean acceptPartial) throws ApplyPatchException {
- ApplyPatchStatus result = null;
- int curLine = findStartLine(lines);
- for(PatchLine line: myLines) {
- final String patchLineText = line.getText();
- switch (line.getType()) {
- case CONTEXT:
- checkContextMismatch(lines, curLine, patchLineText);
- curLine++;
- break;
-
- case ADD:
- if (curLine < lines.size() && lines.get(curLine).equals(patchLineText) && acceptPartial) {
- result = ApplyPatchStatus.and(result, ApplyPatchStatus.ALREADY_APPLIED);
- }
- else {
- lines.add(curLine, patchLineText);
- result = ApplyPatchStatus.and(result, ApplyPatchStatus.SUCCESS);
- }
- curLine++;
- break;
-
- case REMOVE:
- if (curLine >= lines.size() || !patchLineText.equals(lines.get(curLine))) {
- if (acceptPartial) {
- // we'll get a context mismatch exception later if it's actually a conflict and not an already applied line
- result = ApplyPatchStatus.and(result, ApplyPatchStatus.ALREADY_APPLIED);
- }
- else {
- checkContextMismatch(lines, curLine, patchLineText);
- }
- }
- else {
- lines.remove(curLine);
- result = ApplyPatchStatus.and(result, ApplyPatchStatus.SUCCESS);
- }
- break;
- }
- }
- if (result != null) {
- return result;
- }
- return ApplyPatchStatus.SUCCESS;
- }
-
- private static void checkContextMismatch(final List<String> lines, final int curLine, final String patchLineText) throws ApplyPatchException {
- if (curLine >= lines.size()) {
- throw new ApplyPatchException("Unexpected end of document. Expected line:\n" + patchLineText);
- }
- if (!patchLineText.equals(lines.get(curLine))) {
- throw new ApplyPatchException("Context mismatch. Expected line:\n" + patchLineText + "\nFound line:\n" + lines.get(curLine));
- }
- }
-
- private int findStartLine(final List<String> lines) throws ApplyPatchException {
- int totalContextLines = countContextLines();
- if (getLinesProcessingContext(lines, myStartLineBefore) == totalContextLines) {
- return myStartLineBefore;
- }
- int maxContextStartLine = -1;
- int maxContextLines = 0;
- for(int i=0;i< lines.size(); i++) {
- int contextLines = getLinesProcessingContext(lines, i);
- if (contextLines == totalContextLines) {
- return i;
- }
- if (contextLines > maxContextLines) {
- maxContextLines = contextLines;
- maxContextStartLine = i;
- }
- }
- if (maxContextLines < 2) {
- throw new ApplyPatchException("couldn't find context");
- }
- return maxContextStartLine;
- }
-
- private int countContextLines() {
- int count = 0;
- for(PatchLine line: myLines) {
- if (line.getType() == PatchLine.Type.CONTEXT || line.getType() == PatchLine.Type.REMOVE) {
- count++;
- }
- }
- return count;
- }
-
- private int getLinesProcessingContext(final List<String> lines, int startLine) {
- int count = 0;
- for(PatchLine line: myLines) {
- PatchLine.Type type = line.getType();
- if (type == PatchLine.Type.REMOVE || type == PatchLine.Type.CONTEXT) {
- // TODO: smarter algorithm (search outward from non-context lines)
- if (startLine >= lines.size() || !line.getText().equals(lines.get(startLine))) {
- return count;
- }
- count++;
- startLine++;
- }
- }
- return count;
- }
-
public boolean isNewContent() {
return myStartLineBefore == -1 && myEndLineBefore == -1;
}
*/
package com.intellij.openapi.diff.impl.patch;
-import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.util.text.LineTokenizer;
-import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.List;
-import java.util.ArrayList;
public class PatchReader {
@NonNls public static final String NO_NEWLINE_SIGNATURE = "\\ No newline at end of file";
@NonNls private static final Pattern ourContextBeforeHunkStartPattern = Pattern.compile("\\*\\*\\* (\\d+),(\\d+) \\*\\*\\*\\*");
@NonNls private static final Pattern ourContextAfterHunkStartPattern = Pattern.compile("--- (\\d+),(\\d+) ----");
- public PatchReader(VirtualFile virtualFile) throws IOException {
- byte[] patchContents = virtualFile.contentsToByteArray();
- CharSequence patchText = LoadTextUtil.getTextByBinaryPresentation(patchContents, virtualFile);
- myLines = LineTokenizer.tokenize(patchText, false);
- }
-
public PatchReader(CharSequence patchContent) {
myLines = LineTokenizer.tokenize(patchContent, false);
}
--- /dev/null
+/*
+ * Copyright 2000-2010 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.fileEditor.impl.LoadTextUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+
+import java.io.IOException;
+
+public class PatchVirtualFileReader {
+ private PatchVirtualFileReader() {
+ }
+
+ public static PatchReader create(final VirtualFile virtualFile) throws IOException {
+ final byte[] patchContents = virtualFile.contentsToByteArray();
+ final CharSequence patchText = LoadTextUtil.getTextByBinaryPresentation(patchContents, virtualFile);
+ return new PatchReader(patchText);
+ }
+}
Collections.addAll(lines, LineTokenizer.tokenize(text, false));
ApplyPatchStatus result = null;
for(PatchHunk hunk: hunks) {
- result = ApplyPatchStatus.and(result, hunk.apply(lines));
+ result = ApplyPatchStatus.and(result, new ApplyPatchHunk(hunk).apply(lines));
}
for(int i=0; i<lines.size(); i++) {
newText.append(lines.get(i));
--- /dev/null
+/*
+ * Copyright 2000-2010 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.apply;
+
+import com.intellij.openapi.diff.impl.patch.ApplyPatchException;
+import com.intellij.openapi.diff.impl.patch.ApplyPatchStatus;
+import com.intellij.openapi.diff.impl.patch.PatchHunk;
+import com.intellij.openapi.diff.impl.patch.PatchLine;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ApplyPatchHunk {
+ private final PatchHunk myHunk;
+
+ public ApplyPatchHunk(final PatchHunk hunk) {
+ myHunk = hunk;
+ }
+
+ public ApplyPatchStatus apply(final List<String> lines) throws ApplyPatchException {
+ List<String> originalLines = new ArrayList<String>(lines);
+ try {
+ return tryApply(lines, false);
+ }
+ catch(ApplyPatchException ex) {
+ lines.clear();
+ lines.addAll(originalLines);
+ return tryApply(lines, true);
+ }
+ }
+
+ private ApplyPatchStatus tryApply(final List<String> lines, boolean acceptPartial) throws ApplyPatchException {
+ final List<PatchLine> hunkLines = myHunk.getLines();
+ ApplyPatchStatus result = null;
+ int curLine = findStartLine(hunkLines, lines);
+ for(PatchLine line: hunkLines) {
+ final String patchLineText = line.getText();
+ switch (line.getType()) {
+ case CONTEXT:
+ checkContextMismatch(lines, curLine, patchLineText);
+ curLine++;
+ break;
+
+ case ADD:
+ if (curLine < lines.size() && lines.get(curLine).equals(patchLineText) && acceptPartial) {
+ result = ApplyPatchStatus.and(result, ApplyPatchStatus.ALREADY_APPLIED);
+ }
+ else {
+ lines.add(curLine, patchLineText);
+ result = ApplyPatchStatus.and(result, ApplyPatchStatus.SUCCESS);
+ }
+ curLine++;
+ break;
+
+ case REMOVE:
+ if (curLine >= lines.size() || !patchLineText.equals(lines.get(curLine))) {
+ if (acceptPartial) {
+ // we'll get a context mismatch exception later if it's actually a conflict and not an already applied line
+ result = ApplyPatchStatus.and(result, ApplyPatchStatus.ALREADY_APPLIED);
+ }
+ else {
+ checkContextMismatch(lines, curLine, patchLineText);
+ }
+ }
+ else {
+ lines.remove(curLine);
+ result = ApplyPatchStatus.and(result, ApplyPatchStatus.SUCCESS);
+ }
+ break;
+ }
+ }
+ if (result != null) {
+ return result;
+ }
+ return ApplyPatchStatus.SUCCESS;
+ }
+
+ private static void checkContextMismatch(final List<String> lines, final int curLine, final String patchLineText) throws ApplyPatchException {
+ if (curLine >= lines.size()) {
+ throw new ApplyPatchException("Unexpected end of document. Expected line:\n" + patchLineText);
+ }
+ if (!patchLineText.equals(lines.get(curLine))) {
+ throw new ApplyPatchException("Context mismatch. Expected line:\n" + patchLineText + "\nFound line:\n" + lines.get(curLine));
+ }
+ }
+
+ private int findStartLine(final List<PatchLine> hunkLines, final List<String> lines) throws ApplyPatchException {
+ int totalContextLines = countContextLines(hunkLines);
+ final int startLineBefore = myHunk.getStartLineBefore();
+ if (getLinesProcessingContext(hunkLines, lines, startLineBefore) == totalContextLines) {
+ return startLineBefore;
+ }
+ int maxContextStartLine = -1;
+ int maxContextLines = 0;
+ for(int i=0;i< lines.size(); i++) {
+ int contextLines = getLinesProcessingContext(hunkLines, lines, i);
+ if (contextLines == totalContextLines) {
+ return i;
+ }
+ if (contextLines > maxContextLines) {
+ maxContextLines = contextLines;
+ maxContextStartLine = i;
+ }
+ }
+ if (maxContextLines < 2) {
+ throw new ApplyPatchException("couldn't find context");
+ }
+ return maxContextStartLine;
+ }
+
+ private int countContextLines(final List<PatchLine> hunkLines) {
+ int count = 0;
+ for(PatchLine line: hunkLines) {
+ if (line.getType() == PatchLine.Type.CONTEXT || line.getType() == PatchLine.Type.REMOVE) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private int getLinesProcessingContext(final List<PatchLine> hunkLines, final List<String> lines, int startLine) {
+ int count = 0;
+ for(PatchLine line: hunkLines) {
+ PatchLine.Type type = line.getType();
+ if (type == PatchLine.Type.REMOVE || type == PatchLine.Type.CONTEXT) {
+ // TODO: smarter algorithm (search outward from non-context lines)
+ if (startLine >= lines.size() || !line.getText().equals(lines.get(startLine))) {
+ return count;
+ }
+ count++;
+ startLine++;
+ }
+ }
+ return count;
+ }
+}
Collections.addAll(lines, LineTokenizer.tokenize(text, false));
ApplyPatchStatus result = null;
for(PatchHunk hunk: hunks) {
- result = ApplyPatchStatus.and(result, hunk.apply(lines));
+ result = ApplyPatchStatus.and(result, new ApplyPatchHunk(hunk).apply(lines));
}
for(int i=0; i<lines.size(); i++) {
newText.append(lines.get(i));
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.*;
-import com.intellij.openapi.diff.impl.patch.FilePatch;
-import com.intellij.openapi.diff.impl.patch.PatchReader;
-import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
-import com.intellij.openapi.diff.impl.patch.TextFilePatch;
+import com.intellij.openapi.diff.impl.patch.*;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDialog;
}
PatchReader reader;
try {
- reader = new PatchReader(patchFile);
+ reader = PatchVirtualFileReader.create(patchFile);
}
catch (IOException e) {
//todo