View Javadoc
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  	//TODO XXX
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  	//TODO XXX
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 //	public static AceMarker adjustMarkerBasedOnContext(MarkerAddition ma,
161 //			String text) {
162 //		int start = GwtTextDiff.getDMP().match_main(text, ma., ma.startPos);
163 //		if (start == -1) {
164 //			return null;
165 //		}
166 //		int end = GwtTextDiff.getDMP().match_main(text, ma.endContext, ma.endPos);
167 //		if (end == -1) {
168 //			return null;
169 //		}
170 //		return null;
171 //	}
172 }