OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012, the Dart project authors. | 2 * Copyright (c) 2012, the Dart project authors. |
3 * | 3 * |
4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except | 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except |
5 * in compliance with the License. You may obtain a copy of the License at | 5 * in compliance with the License. You may obtain a copy of the License at |
6 * | 6 * |
7 * http://www.eclipse.org/legal/epl-v10.html | 7 * http://www.eclipse.org/legal/epl-v10.html |
8 * | 8 * |
9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License | 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License |
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express | 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 // TODO (danrubel): Replace with interface so that html editor can use this st
rategy | 61 // TODO (danrubel): Replace with interface so that html editor can use this st
rategy |
62 private final DartReconcilingEditor editor; | 62 private final DartReconcilingEditor editor; |
63 | 63 |
64 /** | 64 /** |
65 * The document with source to be reconciled. This is set by the {@link IRecon
ciler} and should | 65 * The document with source to be reconciled. This is set by the {@link IRecon
ciler} and should |
66 * not be {@code null}. | 66 * not be {@code null}. |
67 */ | 67 */ |
68 private IDocument document; | 68 private IDocument document; |
69 | 69 |
70 /** | 70 /** |
| 71 * The display in which the editor is visible. |
| 72 */ |
| 73 private final Display display; |
| 74 |
| 75 /** |
71 * The time when the context was last notified of a source change. | 76 * The time when the context was last notified of a source change. |
72 */ | 77 */ |
73 private volatile long notifyContextTime; | 78 private volatile long notifyContextTime; |
74 | 79 |
75 /** | 80 /** |
76 * The time when the source was last modified. | 81 * The time when the source was last modified. |
77 */ | 82 */ |
78 private volatile long sourceChangedTime; | 83 private volatile long sourceChangedTime; |
79 | 84 |
80 /** | 85 /** |
(...skipping 15 matching lines...) Expand all Loading... |
96 if (event.getSource().equals(editor.getInputSource())) { | 101 if (event.getSource().equals(editor.getInputSource())) { |
97 applyAnalysisResult(event.getUnit()); | 102 applyAnalysisResult(event.getUnit()); |
98 } | 103 } |
99 } | 104 } |
100 } | 105 } |
101 }; | 106 }; |
102 | 107 |
103 /** | 108 /** |
104 * Listen for changes to the source to clear the cached AST and record the las
t modification time. | 109 * Listen for changes to the source to clear the cached AST and record the las
t modification time. |
105 */ | 110 */ |
106 final IDocumentListener documentListener = new IDocumentListener() { | 111 private final IDocumentListener documentListener = new IDocumentListener() { |
107 @Override | 112 @Override |
108 public void documentAboutToBeChanged(DocumentEvent event) { | 113 public void documentAboutToBeChanged(DocumentEvent event) { |
109 } | 114 } |
110 | 115 |
111 @Override | 116 @Override |
112 public void documentChanged(DocumentEvent event) { | 117 public void documentChanged(DocumentEvent event) { |
113 sourceChangedTime = System.currentTimeMillis(); | 118 sourceChangedTime = System.currentTimeMillis(); |
114 editor.applyCompilationUnitElement(null); | 119 editor.applyCompilationUnitElement(null); |
115 | 120 |
116 // Start analysis immediately if "." pressed to improve code completion re
sponse | 121 // Start analysis immediately if "." pressed to improve code completion re
sponse |
117 // TODO (danrubel): do the same for ctrl-space ? | |
118 | 122 |
119 // This may need to be modified or removed | 123 // This may need to be modified or removed |
120 // if we enable/set content assist immediate-activation character(s) | 124 // if we enable/set content assist immediate-activation character(s) |
121 | 125 |
122 if (".".equals(event.getText())) { | 126 if (".".equals(event.getText())) { |
123 updateSourceInBackground(true); | 127 updateSourceInBackground(true); |
124 } | 128 } |
125 } | 129 } |
126 }; | 130 }; |
127 | 131 |
128 /** | 132 /** |
129 * Construct a new instance for the specified editor. | 133 * Construct a new instance for the specified editor. |
130 * | 134 * |
131 * @param editor the editor (not {@code null}) | 135 * @param editor the editor (not {@code null}) |
132 */ | 136 */ |
133 public DartReconcilingStrategy(DartReconcilingEditor editor) { | 137 public DartReconcilingStrategy(DartReconcilingEditor editor) { |
134 this.editor = editor; | 138 this.editor = editor; |
| 139 this.display = Display.getDefault(); |
135 | 140 |
136 // Prioritize analysis when editor becomes active | 141 // Prioritize analysis when editor becomes active |
137 editor.addViewerFocusListener(new FocusListener() { | 142 editor.addViewerFocusListener(new FocusListener() { |
138 @Override | 143 @Override |
139 public void focusGained(FocusEvent e) { | 144 public void focusGained(FocusEvent e) { |
140 updateAnalysisPriorityOrder(true); | 145 updateAnalysisPriorityOrder(true); |
141 } | 146 } |
142 | 147 |
143 @Override | 148 @Override |
144 public void focusLost(FocusEvent e) { | 149 public void focusLost(FocusEvent e) { |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 applyAnalysisResult(unit); | 260 applyAnalysisResult(unit); |
256 return true; | 261 return true; |
257 } | 262 } |
258 } | 263 } |
259 } | 264 } |
260 return false; | 265 return false; |
261 } | 266 } |
262 | 267 |
263 /** | 268 /** |
264 * Answer the list of sources associated with the specified context that are o
pen and visible. | 269 * Answer the list of sources associated with the specified context that are o
pen and visible. |
| 270 * This method blocks until the information can be retrieved on the UI thread. |
265 * | 271 * |
266 * @param context the context (not {@code null}) | 272 * @param context the context (not {@code null}) |
267 * @return a list of sources (not {@code null}, contains no {@code null}s) | 273 * @return a list of sources (not {@code null}, contains no {@code null}s) |
268 */ | 274 */ |
269 private List<Source> getVisibleSourcesForContext(AnalysisContext context) { | 275 private List<Source> getVisibleSourcesForContext(final AnalysisContext context
) { |
270 ArrayList<Source> sources = new ArrayList<Source>(); | 276 final ArrayList<Source> sources = new ArrayList<Source>(); |
271 IWorkbench workbench = PlatformUI.getWorkbench(); | 277 display.syncExec(new Runnable() { |
272 for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) { | 278 @Override |
273 for (IWorkbenchPage page : window.getPages()) { | 279 public void run() { |
274 IEditorReference[] allEditors = page.getEditorReferences(); | 280 IWorkbench workbench = PlatformUI.getWorkbench(); |
275 for (IEditorReference editorRef : allEditors) { | 281 for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) { |
276 IEditorPart part = editorRef.getEditor(false); | 282 for (IWorkbenchPage page : window.getPages()) { |
277 if (part instanceof DartEditor) { | 283 IEditorReference[] allEditors = page.getEditorReferences(); |
278 DartEditor otherEditor = (DartEditor) part; | 284 for (IEditorReference editorRef : allEditors) { |
279 if (otherEditor.getInputAnalysisContext() == context && otherEditor.
isVisible()) { | 285 IEditorPart part = editorRef.getEditor(false); |
280 Source otherSource = otherEditor.getInputSource(); | 286 if (part instanceof DartEditor) { |
281 if (otherSource != null) { | 287 DartEditor otherEditor = (DartEditor) part; |
282 sources.add(otherSource); | 288 if (otherEditor.getInputAnalysisContext() == context && otherEdi
tor.isVisible()) { |
| 289 Source otherSource = otherEditor.getInputSource(); |
| 290 if (otherSource != null) { |
| 291 sources.add(otherSource); |
| 292 } |
| 293 } |
283 } | 294 } |
284 } | 295 } |
285 } | 296 } |
286 } | 297 } |
287 } | 298 } |
288 } | 299 }); |
289 return sources; | 300 return sources; |
290 } | 301 } |
291 | 302 |
292 /** | 303 /** |
293 * Start background analysis of the context containing the source being edited
. | 304 * Start background analysis of the context containing the source being edited
. |
294 */ | 305 */ |
295 private void performAnalysisInBackground() { | 306 private void performAnalysisInBackground() { |
296 AnalysisContext context = editor.getInputAnalysisContext(); | 307 AnalysisContext context = editor.getInputAnalysisContext(); |
297 if (context != null) { | 308 if (context != null) { |
298 ContextManager manager = editor.getInputProject(); | 309 ContextManager manager = editor.getInputProject(); |
299 if (manager == null) { | 310 if (manager == null) { |
300 manager = DartCore.getProjectManager(); | 311 manager = DartCore.getProjectManager(); |
301 } | 312 } |
302 AnalysisWorker.performAnalysisInBackground(manager, context); | 313 AnalysisWorker.performAnalysisInBackground(manager, context); |
303 } | 314 } |
304 } | 315 } |
305 | 316 |
306 /** | 317 /** |
307 * Clear the cached compilation unit and notify the context that the source ha
s changed. | 318 * Clear the cached compilation unit and notify the context that the source ha
s changed. |
308 * | 319 * |
309 * @param code the new source code (not {@code null}) | 320 * @param code the new source code or {@code null} if the source should be pul
led from disk |
310 */ | 321 */ |
311 private void sourceChanged(String code) { | 322 private void sourceChanged(String code) { |
312 notifyContextTime = System.currentTimeMillis(); | 323 notifyContextTime = System.currentTimeMillis(); |
313 AnalysisContext context = editor.getInputAnalysisContext(); | 324 AnalysisContext context = editor.getInputAnalysisContext(); |
314 Source source = editor.getInputSource(); | 325 Source source = editor.getInputSource(); |
315 if (context != null && source != null) { | 326 if (context != null && source != null) { |
316 context.setContents(source, code); | 327 context.setContents(source, code); |
317 } | 328 } |
318 } | 329 } |
319 | 330 |
320 /** | 331 /** |
321 * Update the order in which sources are analyzed in the context associated wi
th the editor. This | 332 * Update the order in which sources are analyzed in the context associated wi
th the editor. This |
322 * is called once per instantiated editor on startup and then once for each ed
itor as it becomes | 333 * is called once per instantiated editor on startup and then once for each ed
itor as it becomes |
323 * active. For example, if there are 2 of 7 editors visible on startup, then t
his will be called | 334 * active. For example, if there are 2 of 7 editors visible on startup, then t
his will be called |
324 * for the 2 visible editors. | 335 * for the 2 visible editors. |
325 * | 336 * |
326 * @param isOpen {@code true} if the editor is open and the source should be t
he first source | 337 * @param isOpen {@code true} if the editor is open and the source should be t
he first source |
327 * analyzed or {@code false} if the editor is closed and the source s
hould be removed | 338 * analyzed or {@code false} if the editor is closed and the source s
hould be removed |
328 * from the priority list. | 339 * from the priority list. |
329 */ | 340 */ |
330 private void updateAnalysisPriorityOrder(final boolean isOpen) { | 341 private void updateAnalysisPriorityOrder(final boolean isOpen) { |
331 Display.getDefault().asyncExec(new Runnable() { | 342 // TODO (danrubel): Revisit when reviewing performance of startup, open, and
activate |
332 @Override | 343 AnalysisContext context = editor.getInputAnalysisContext(); |
333 public void run() { | 344 Source source = editor.getInputSource(); |
334 // TODO (danrubel): Revisit when reviewing performance of startup, open,
and activate | 345 if (context != null && source != null) { |
335 AnalysisContext context = editor.getInputAnalysisContext(); | 346 final List<Source> sources = getVisibleSourcesForContext(context); |
336 Source source = editor.getInputSource(); | 347 sources.remove(source); |
337 if (context != null && source != null) { | 348 if (isOpen) { |
338 List<Source> sources = getVisibleSourcesForContext(context); | 349 sources.add(0, source); |
339 sources.remove(source); | |
340 if (isOpen) { | |
341 sources.add(0, source); | |
342 } | |
343 updateAnalysisPriorityOrderInBackground(sources); | |
344 } | |
345 } | 350 } |
346 }); | 351 // TODO (danrubel): Keep this off the UI thread until lock contention has
been resolved |
347 } | 352 if (Display.getCurrent() == null) { |
348 | 353 context.setAnalysisPriorityOrder(sources); |
349 /** | 354 } else { |
350 * Update the order in which sources are analyzed in the context associated wi
th the editor. | 355 new Thread("updateAnalysisPriorityOrder") { |
351 * | 356 @Override |
352 * @param sources the list of sources to be analyzed first (not <code>null</co
de>, contains no | 357 public void run() { |
353 * <code>null</code>s) | 358 AnalysisContext context = editor.getInputAnalysisContext(); |
354 */ | 359 if (context != null) { |
355 private void updateAnalysisPriorityOrderInBackground(final List<Source> source
s) { | 360 context.setAnalysisPriorityOrder(sources); |
356 // TODO (danrubel): Put this back on UI thread once analysis lock contention
has been resolved | 361 } |
357 new Thread("updateAnalysisPriorityOrderInBackground") { | 362 }; |
358 @Override | 363 }.start(); |
359 public void run() { | 364 } |
360 AnalysisContext context = editor.getInputAnalysisContext(); | 365 } |
361 if (context != null) { | |
362 context.setAnalysisPriorityOrder(sources); | |
363 } | |
364 }; | |
365 }.start(); | |
366 } | 366 } |
367 | 367 |
368 /** | 368 /** |
369 * Update the source being analyzed in the context associated with the editor. | 369 * Update the source being analyzed in the context associated with the editor. |
370 * | 370 * |
371 * @param isOpen {@code true} if the editor is open and the source should be c
ached or | 371 * @param isOpen {@code true} if the editor is open and the source should be c
ached or |
372 * {@code false} if the editor is closed and the source should read f
rom disk. | 372 * {@code false} if the editor is closed and the source should read f
rom disk. |
373 */ | 373 */ |
374 private void updateSourceInBackground(final boolean isOpen) { | 374 private void updateSourceInBackground(final boolean isOpen) { |
375 // TODO (danrubel): Put this back on UI thread once analysis lock contention
has been resolved | 375 // TODO (danrubel): Keep this off the UI thread until lock contention has be
en resolved |
376 new Thread("updateSourceInBackground") { | 376 new Thread("updateSourceInBackground") { |
377 @Override | 377 @Override |
378 public void run() { | 378 public void run() { |
379 sourceChanged(isOpen ? document.get() : null); | 379 sourceChanged(isOpen ? document.get() : null); |
380 performAnalysisInBackground(); | 380 performAnalysisInBackground(); |
381 } | 381 } |
382 }.start(); | 382 }.start(); |
383 } | 383 } |
384 } | 384 } |
OLD | NEW |