| 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 |