1    	package acl2s.plugin.editors;
2    	
3    	import java.io.File;
4    	import java.util.ArrayList;
5    	import java.util.Iterator;
6    	
7    	import org.eclipse.core.runtime.IPath;
8    	import org.eclipse.core.runtime.Path;
9    	import org.eclipse.jface.text.BadLocationException;
10   	import org.eclipse.jface.text.Document;
11   	import org.eclipse.jface.text.IRegion;
12   	import org.eclipse.jface.text.source.Annotation;
13   	import org.eclipse.jface.text.source.AnnotationModel;
14   	import org.eclipse.jface.text.source.IAnnotationModel;
15   	import org.eclipse.swt.widgets.Display;
16   	import org.eclipse.text.undo.DocumentUndoManagerRegistry;
17   	import org.eclipse.text.undo.IDocumentUndoManager;
18   	import org.eclipse.ui.IEditorInput;
19   	import org.eclipse.ui.IFileEditorInput;
20   	import org.eclipse.ui.IPathEditorInput;
21   	import org.eclipse.ui.IURIEditorInput;
22   	import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
23   	
24   	import acl2s.lib.contentassist.WorkspaceDictionary;
25   	import acl2s.plugin.Acl2sPlugin;
26   	import acl2s.plugin.indent.DefaultLispIndent;
27   	import acl2s.plugin.indent.ILispIndent;
28   	import acl2s.plugin.parse.LispToken;
29   	import acl2s.plugin.parse.LispTokens;
30   	
31   	
32   	public abstract class A2sDocument extends Document {
33   		protected final Display display = Display.getDefault();
34   		
35   		protected LispTokens tokens;
36   		protected MyDocumentProvider dp;
37   		protected IEditorInput input = null;
38   		protected AnnotationModel annotations = null;
39   		protected String[] eols = null;
40   		protected boolean startedDirty = false;
41   		protected ILispIndent indent = null;
42   		
43   		protected A2sDocument(MyDocumentProvider dp) {
44   			super();
45   			this.dp = dp;
46   			annotations = new AnnotationModel();
47   			WorkspaceDictionary.addFile(this, null);
48   		}
49   		
50   		public IPath getOSPath() {
51   			if (input instanceof IFileEditorInput) {
52   				return ((IFileEditorInput)input).getFile().getLocation();
53   			} else if (input instanceof IPathEditorInput) {
54   				return ((IPathEditorInput)input).getPath();
55   			} else if (input instanceof IURIEditorInput) {
56   				try {
57   					return new Path(new File(((IURIEditorInput)input).getURI()).getAbsolutePath());
58   				} catch (IllegalArgumentException e) {
59   					return null;
60   				}
61   			} else {
62   				return null;
63   			}
64   		}
65   		
66   		public File getOSFile() {
67   			if (input instanceof IFileEditorInput) {
68   				return ((IFileEditorInput)input).getFile().getLocation().toFile();
69   			} else if (input instanceof IPathEditorInput) {
70   				return ((IPathEditorInput)input).getPath().toFile();
71   			} else if (input instanceof IURIEditorInput) {
72   				try {
73   					return new File(((IURIEditorInput)input).getURI());
74   				} catch (IllegalArgumentException e) {
75   					return null;
76   				}
77   			} else {
Event null_literal: Using a literal null value.
78   				return null;
79   			}
80   		}
81   		
82   		public IEditorInput getInput() { return input; }
83   		
84   		@SuppressWarnings("unchecked") // stupid Eclipse API
85   		public void setInput(IEditorInput i) {
86   			input = i;
87   			if (i instanceof IFileEditorInput) {
88   				AnnotationModel old = annotations;
89   				annotations = new ResourceMarkerAnnotationModel(((IFileEditorInput)i).getFile());
90   				Iterator<Annotation> foo = old.getAnnotationIterator();
91   				while (foo.hasNext()) {
92   					Annotation a = foo.next();
93   					annotations.addAnnotation(a,old.getPosition(a));
94   				}
95   			}
96   			eols = getLegalLineDelimiters();
97   			indent = new DefaultLispIndent(tokens, this);
98   		}
99   		
100  		public abstract MyDocumentProvider getProvider();
101  		
102  		public void ensureDirty() {
103  			if (input != null) {
104  				getProvider().setCanSaveDocument(input);
105  			} else {
106  				startedDirty = true;
107  			}
108  		}
109  		
110  		public boolean startedDirty() { return startedDirty; }
111  		
112  		public boolean isDirty() {
113  			return getProvider().canSaveDocument(input);
114  		}
115  		
116  		
117  		public IDocumentUndoManager getUndoManager() {
118  			return DocumentUndoManagerRegistry.getDocumentUndoManager(this);
119  		}
120  		
121  		public void resetUndoStuff() {
122  			IDocumentUndoManager m = getUndoManager();
123  			if (m != null) m.reset();
124  		}
125  		
126  		
127  		public boolean isEOL(String txt) {
128  			for (String s : eols) {
129  				if (s.equals(txt)) {
130  					return true;
131  				}
132  			}
133  			return false;
134  		}
135  		
136  		public String get2(int offset, int len) {
137  			try {
138  				return get(offset,len);
139  			} catch (BadLocationException e) {
140  				Acl2sPlugin.logError("Bad document location.",e);
141  				return "";
142  			}
143  		}
144  	
145  		public char getChar2(int i) {
146  			try {
147  				return getChar(i);
148  			} catch (BadLocationException e) {
149  				Acl2sPlugin.logError("Bad document location.",e);
150  				return '\0';
151  			}
152  		}
153  	
154  		public void replace2(int offset, int len, String s) {
155  			try {
156  				replace(offset,len,s);
157  			} catch (BadLocationException e) {
158  				Acl2sPlugin.logError("Bad document location.",e);
159  			}
160  		}
161  	
162  	
163  		
164  		public void replace(int pos, int length, String text) throws BadLocationException {
165  			if (text == null) text = "";  // Eclipse will actually call with null in places!!!
166  	
167  			if (allowReplace(pos, length, text)) {
168  				super.replace(pos, length, text);
169  			}
170  		}
171  	
172  		protected boolean allowReplace(int pos, int length, String text) {
173  			return pos >= readOnlyPoint();
174  		}
175  		
176  		public abstract int readOnlyPoint();
177  		
178  		public LispTokens getTokens() { return tokens; }
179  	
180  		public IAnnotationModel getAnnotationModel() {
181  			return annotations;
182  		}
183  		
184  		/* ***************  INDENT ************* */
185  		
186  		public ILispIndent getIndentStrategy() { return indent; }
187  		
188  		public void indentRegion(IRegion region) {
189  			try {
190  				int start = region.getOffset();
191  				int end = start + region.getLength();
192  				start = Math.max(start,readOnlyPoint());
193  				if (end > start) {
194  					end--;
195  				} else if (end < start) {
196  					return;
197  				}
198  				int firstLine = getLineOfOffset(start);
199  				int lastLine = getLineOfOffset(end);
200  				for (int i = firstLine; i <= lastLine; i++) {
201  					indent.indentLine(i);
202  				}
203  			} catch (BadLocationException e) {
204  				e.printStackTrace();
205  			}
206  		}
207  	
208  	
209  		
210  		/* ======= Sexp navigation/selection ======== */
211  		public int fwdToplevelSexp(int fromOffset) {
212  			int tIdx = tokens.getTokenIdxContaining(fromOffset);
213  			LispToken tok = tokens.getToken(tIdx);
214  			if (tok.ctx == null && tok.offset > fromOffset) {
215  				return tok.offset;
216  			}
217  			for (;;) {
218  				tIdx++;
219  				if (tIdx >= tokens.getTokenCount()) break;
220  				tok = tokens.getToken(tIdx);
221  				if (tok.ctx == null) break;
222  			}
223  			return tok.offset;
224  		}
225  	
226  		public int backToplevelSexp(int fromOffset) {
227  			int tIdx = tokens.getTokenIdxContaining(fromOffset);
228  			LispToken tok = tokens.getToken(tIdx);
229  			if (tok.ctx == null && tok.offset > fromOffset) {
230  				tIdx--;
231  			}
232  			for (;;) {
233  				if (tIdx < 0) break;
234  				tok = tokens.getToken(tIdx);
235  				if (tok.ctx == null) break;
236  				tIdx--;
237  			}
238  			return tok.offset;
239  		}
240  	
241  	
242  		
243  		/* ====== Description Notification ====== */
244  		protected abstract String doGetDescription();
245  		
246  		protected final ArrayList<IDescriptionListener> descListeners = new ArrayList<IDescriptionListener>();
247  	
248  		public void addDescriptionListener(IDescriptionListener l) {
249  			if (!descListeners.contains(l)) {
250  				descListeners.add(l);
251  				updateDescriptions();
252  			}
253  		}
254  		
255  		public void removeDescriptionListener(IDescriptionListener l) {
256  			descListeners.remove(l);
257  		}
258  		
259  		protected void updateDescriptions() {
260  			String desc = doGetDescription();
261  			for (IDescriptionListener l : descListeners) {
262  				l.descriptionChanged(desc);
263  			}
264  		}
265  		
266  		
267  	}