diff --git a/org.eclipse.wb.core.java/src/org/eclipse/wb/internal/core/editor/UndoManager.java b/org.eclipse.wb.core.java/src/org/eclipse/wb/internal/core/editor/UndoManager.java index 7b1a5b120f..77ada4b763 100644 --- a/org.eclipse.wb.core.java/src/org/eclipse/wb/internal/core/editor/UndoManager.java +++ b/org.eclipse.wb.core.java/src/org/eclipse/wb/internal/core/editor/UndoManager.java @@ -84,13 +84,28 @@ public UndoManager(DesignPage designPage, ICompilationUnit unit) throws Exceptio public void activate() { if (!m_active) { m_active = true; - if (!Objects.equals(m_currentSource, m_buffer.getContents())) { - refreshDesignerEditor(); - } + refreshIfSourceChanged(); addBufferListener(); } } + /** + * Reparses if the buffer no longer matches the parsed source, waiting for a running parse first. + */ + private void refreshIfSourceChanged() { + if (!m_active) { + return; + } + // the progress dialog of a running parse spins the event loop, so wait for it to finish + if (m_designPage.getDesignerState() == DesignerState.Parsing) { + Display.getDefault().timerExec(1, this::refreshIfSourceChanged); + return; + } + if (!Objects.equals(m_currentSource, m_buffer.getContents())) { + refreshDesignerEditor(); + } + } + /** * Deactivates {@link UndoManager}, so it stops listening for buffer changes. */ diff --git a/org.eclipse.wb.core/src/org/eclipse/wb/internal/core/utils/execution/ExecutionUtils.java b/org.eclipse.wb.core/src/org/eclipse/wb/internal/core/utils/execution/ExecutionUtils.java index 7398f2260e..20517f8fac 100644 --- a/org.eclipse.wb.core/src/org/eclipse/wb/internal/core/utils/execution/ExecutionUtils.java +++ b/org.eclipse.wb.core/src/org/eclipse/wb/internal/core/utils/execution/ExecutionUtils.java @@ -184,15 +184,22 @@ public void run() { } /** - * Runs given {@link RunnableEx} inside of UI thread, using {@link Display#syncExec(Runnable)}. + * Runs given {@link RunnableEx} inside of UI thread, using {@link Display#syncExec(Runnable)}, + * and re-throws its exceptions in the calling thread. */ public static void runRethrowUI(final RunnableEx runnable) { - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - ExecutionUtils.runRethrow(runnable); + // the workbench's display exception handler swallows what a syncExec runnable throws + Throwable[] failure = new Throwable[1]; + Display.getDefault().syncExec(() -> { + try { + runnable.run(); + } catch (Throwable e) { + failure[0] = e; } }); + if (failure[0] != null) { + throw ReflectionUtils.propagate(failure[0]); + } } /** diff --git a/org.eclipse.wb.tests/src/org/eclipse/wb/tests/designer/core/util/execution/ExecutionUtilsTest.java b/org.eclipse.wb.tests/src/org/eclipse/wb/tests/designer/core/util/execution/ExecutionUtilsTest.java index 8ee72cd24b..f05f9e9191 100644 --- a/org.eclipse.wb.tests/src/org/eclipse/wb/tests/designer/core/util/execution/ExecutionUtilsTest.java +++ b/org.eclipse.wb.tests/src/org/eclipse/wb/tests/designer/core/util/execution/ExecutionUtilsTest.java @@ -31,6 +31,8 @@ import java.beans.Beans; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; /** * Tests for {@link ExecutionUtils} and {@link RunnableEx}. @@ -458,6 +460,38 @@ public void test_runRethrowUI() throws Exception { } } + /** + * Test for {@link ExecutionUtils#runRethrowUI(RunnableEx)} when the display's exception handler + * swallows exceptions, as the workbench's does. + */ + @Test + public void test_runRethrowUI_exception() throws Exception { + Display display = Display.getCurrent(); + Consumer oldHandler = display.getRuntimeExceptionHandler(); + display.setRuntimeExceptionHandler(e -> { + }); + try { + IllegalStateException exception = new IllegalStateException(); + AtomicReference caught = new AtomicReference<>(); + Thread thread = new Thread(() -> { + try { + ExecutionUtils.runRethrowUI(() -> { + throw exception; + }); + } catch (Throwable e) { + caught.set(e); + } + }); + thread.start(); + while (thread.isAlive()) { + waitEventLoop(0); + } + assertSame(exception, caught.get()); + } finally { + display.setRuntimeExceptionHandler(oldHandler); + } + } + /** * Test for {@link ExecutionUtils#runAsync(RunnableEx)}. */