1 package org.vaadin.aceeditor.client;
2
3 import java.util.Collections;
4 import java.util.Map;
5 import java.util.Set;
6
7 import org.vaadin.aceeditor.client.AceAnnotation.MarkerAnnotation;
8 import org.vaadin.aceeditor.client.AceAnnotation.RowAnnotation;
9 import org.vaadin.aceeditor.client.GwtTextDiff.Diff;
10 import org.vaadin.aceeditor.client.GwtTextDiff.Patch;
11 import org.vaadin.aceeditor.client.TransportDoc.TransportMarkerAnnotation;
12 import org.vaadin.aceeditor.client.TransportDoc.TransportRowAnnotation;
13
14 import com.google.gwt.core.client.JsArray;
15
16
17
18 public class ClientSideDocDiff {
19
20 public static final DiffMatchPatchJSNI dmp = DiffMatchPatchJSNI.newInstance();
21
22 private final JsArray<GwtTextDiff.Patch> textPatches;
23 private final MarkerSetDiff markerSetDiff;
24 private final SetDiff<RowAnnotation,TransportRowAnnotation> rowAnnDiff;
25 private final SetDiff<MarkerAnnotation,TransportMarkerAnnotation> markerAnnDiff;
26
27 public static ClientSideDocDiff fromTransportDiff(TransportDiff ad) {
28
29 JsArray<Patch> patches = dmp.patch_fromText(ad.patchesAsString);
30 MarkerSetDiff msd = MarkerSetDiff.fromTransportDiff(ad.markerSetDiff);
31
32 SetDiff<RowAnnotation,TransportRowAnnotation> rowAnns = ad.rowAnnDiff==null ? null :
33 SetDiff.fromTransport(ad.rowAnnDiff);
34 SetDiff<MarkerAnnotation,TransportMarkerAnnotation> markerAnns = ad.markerAnnDiff==null ? null :
35 SetDiff.fromTransport(ad.markerAnnDiff);
36
37 return new ClientSideDocDiff(patches, msd, rowAnns, markerAnns);
38 }
39
40 public static ClientSideDocDiff diff(AceDoc doc1, AceDoc doc2) {
41 JsArray<GwtTextDiff.Patch> patches = dmp.patch_make(doc1.getText(), doc2.getText());
42 MarkerSetDiff msd = MarkerSetDiff.diff(doc1.getMarkers(), doc2.getMarkers(), doc2.getText());
43
44 SetDiff<RowAnnotation,TransportRowAnnotation> rowAnnDiff = diffRA(doc1.getRowAnnotations(), doc2.getRowAnnotations());
45 SetDiff<MarkerAnnotation,TransportMarkerAnnotation> markerAnnDiff = diffMA(doc1.getMarkerAnnotations(), doc2.getMarkerAnnotations());
46
47 return new ClientSideDocDiff(patches, msd, rowAnnDiff, markerAnnDiff);
48 }
49
50
51
52 private static SetDiff<MarkerAnnotation, TransportMarkerAnnotation> diffMA(
53 Set<MarkerAnnotation> anns1,
54 Set<MarkerAnnotation> anns2) {
55 if (anns2 == null && anns1 != null) {
56 return null;
57 }
58 if (anns1==null) {
59 anns1 = Collections.emptySet();
60 }
61 if (anns2==null) {
62 anns2 = Collections.emptySet();
63 }
64 return new SetDiff.Differ<MarkerAnnotation,TransportMarkerAnnotation>().diff(anns1, anns2);
65 }
66
67
68 private static SetDiff<RowAnnotation, TransportRowAnnotation> diffRA(
69 Set<RowAnnotation> anns1,
70 Set<RowAnnotation> anns2) {
71 if (anns2 == null && anns1 != null) {
72 return null;
73 }
74 if (anns1==null) {
75 anns1 = Collections.emptySet();
76 }
77 if (anns2==null) {
78 anns2 = Collections.emptySet();
79 }
80 return new SetDiff.Differ<RowAnnotation,TransportRowAnnotation>().diff(anns1, anns2);
81 }
82
83 private ClientSideDocDiff(JsArray<GwtTextDiff.Patch> patches, MarkerSetDiff markerSetDiff,
84 SetDiff<RowAnnotation,TransportRowAnnotation> rowAnnDiff,
85 SetDiff<MarkerAnnotation,TransportMarkerAnnotation> markerAnnDiff) {
86 this.textPatches = patches;
87 this.markerSetDiff = markerSetDiff;
88 this.rowAnnDiff = rowAnnDiff;
89 this.markerAnnDiff = markerAnnDiff;
90 }
91
92 public String getPatchesString() {
93 return dmp.patch_toText(textPatches);
94 }
95
96 public AceDoc applyTo(AceDoc doc) {
97 String text = dmp.patch_apply(textPatches, doc.getText());
98 Map<String, AceMarker> markers = markerSetDiff.applyTo(doc.getMarkers(), text);
99
100 Set<RowAnnotation> rowAnns = rowAnnDiff==null ? null : rowAnnDiff.applyTo(doc.getRowAnnotations());
101 Set<MarkerAnnotation> markerAnns = markerAnnDiff==null ? null : markerAnnDiff.applyTo(doc.getMarkerAnnotations());
102
103 return new AceDoc(text, markers, rowAnns, markerAnns);
104 }
105
106 public TransportDiff asTransport() {
107 TransportDiff d = new TransportDiff();
108 d.patchesAsString = getPatchesString();
109 d.markerSetDiff = markerSetDiff.asTransportDiff();
110 d.rowAnnDiff = rowAnnDiff==null ? null : rowAnnDiff.asTransportRowAnnotations();
111 d.markerAnnDiff = markerAnnDiff==null ? null : markerAnnDiff.asTransportMarkerAnnotations();
112 return d;
113 }
114
115 public boolean isIdentity() {
116 return textPatches == null || textPatches.length()==0;
117 }
118
119 @Override
120 public String toString() {
121 return getPatchesString() + "\nMSD: " + markerSetDiff.toString() + "\nrad:" + rowAnnDiff + ", mad:" + markerAnnDiff;
122 }
123
124 public static class Adjuster {
125 private String s1;
126 private String s2;
127 private String[] lines1;
128 private String[] lines2;
129 private JsArray<Diff> diffs;
130 private boolean stringsEqual;
131 private boolean calcDone;
132 public Adjuster(String s1, String s2) {
133 this.s1 = s1;
134 this.s2 = s2;
135 stringsEqual = s1.equals(s2);
136 }
137 public AceRange adjust(AceRange r) {
138 if (stringsEqual) {
139 return r;
140 }
141 if (!calcDone) {
142 calc();
143 }
144 boolean zeroLength = r.isZeroLength();
145 int start1 = Util.cursorPosFromLineCol(lines1, r.getStartRow(), r.getStartCol(), 0);
146 int end1 = zeroLength ? start1 : Util.cursorPosFromLineCol(lines1, r.getEndRow(), r.getEndCol(), 0);
147 int start2 = dmp.diff_xIndex(diffs, start1);
148 int end2 = zeroLength ? start2 : dmp.diff_xIndex(diffs, end1);
149 int[] startRowCol = Util.lineColFromCursorPos(lines2, start2, 0);
150 int[] endRowCol = zeroLength ? startRowCol : Util.lineColFromCursorPos(lines2, end2, 0);
151 return new AceRange(startRowCol[0], startRowCol[1], endRowCol[0], endRowCol[1]);
152 }
153 private void calc() {
154 lines1 = s1.split("\n", -1);
155 lines2 = s2.split("\n", -1);
156 diffs = dmp.diff_main(s1, s2);
157 }
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171
172 }