diff --git a/plugin/src/winterwell/markdown/editors/ActionBarContributor.java b/plugin/src/winterwell/markdown/editors/ActionBarContributor.java index e41793f..a04a3e8 100755 --- a/plugin/src/winterwell/markdown/editors/ActionBarContributor.java +++ b/plugin/src/winterwell/markdown/editors/ActionBarContributor.java @@ -22,10 +22,6 @@ public void setActiveEditor(IEditorPart targetEditor) { // todo bars.setGlobalActionHandler(ActionFactory.PRINT.getId(), print); // bars.updateActionBars(); } - // Update preview? - if (MarkdownPreview.preview != null) { - MarkdownPreview.preview.update(); - } } public static IEditorPart getActiveEditor() { return activeEditor; diff --git a/plugin/src/winterwell/markdown/editors/MarkdownEditor.java b/plugin/src/winterwell/markdown/editors/MarkdownEditor.java index 86699c4..9b49089 100755 --- a/plugin/src/winterwell/markdown/editors/MarkdownEditor.java +++ b/plugin/src/winterwell/markdown/editors/MarkdownEditor.java @@ -20,7 +20,9 @@ import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextListener; import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.TextEvent; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.IVerticalRuler; @@ -32,6 +34,7 @@ import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IPathEditorInput; import org.eclipse.ui.editors.text.TextEditor; @@ -49,6 +52,7 @@ /** * Text editor with markdown support. + * * @author Daniel Winterstein */ public class MarkdownEditor extends TextEditor implements IDocumentListener @@ -71,7 +75,7 @@ public class MarkdownEditor extends TextEditor implements IDocumentListener private ProjectionSupport projectionSupport; private final IPreferenceStore pStore; private IPropertyChangeListener prefChangeListener; - + private ITextListener textListener; public MarkdownEditor() { super(); @@ -91,6 +95,22 @@ public void createPartControl(Composite parent) { projectionSupport.install(); //turn projection mode on viewer.doOperation(ProjectionViewer.TOGGLE); + + textListener = new ITextListener() { + Runnable runnable = new Runnable() { + @Override + public void run() { + if (MarkdownPreview.preview != null) { + MarkdownPreview.preview.update(); + } + } + }; + @Override + public void textChanged(TextEvent event) { + Display.getCurrent().timerExec(500, runnable); + } + }; + viewer.addTextListener(textListener); } } @@ -133,6 +153,9 @@ public void dispose() { if (pStore != null) { pStore.removePropertyChangeListener(prefChangeListener); } + if (textListener != null) { + getSourceViewer().removeTextListener(textListener); + } colorManager.dispose(); super.dispose(); } diff --git a/plugin/src/winterwell/markdown/views/MarkdownPreview.java b/plugin/src/winterwell/markdown/views/MarkdownPreview.java index c103953..aac3a85 100755 --- a/plugin/src/winterwell/markdown/views/MarkdownPreview.java +++ b/plugin/src/winterwell/markdown/views/MarkdownPreview.java @@ -2,34 +2,73 @@ import java.io.File; +import java.net.MalformedURLException; import java.net.URI; +import java.net.URL; import org.eclipse.core.runtime.IPath; import org.eclipse.swt.SWT; import org.eclipse.swt.browser.Browser; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPathEditorInput; import org.eclipse.ui.part.ViewPart; +import winterwell.markdown.Activator; import winterwell.markdown.editors.ActionBarContributor; import winterwell.markdown.editors.MarkdownEditor; import winterwell.markdown.pagemodel.MarkdownPage; +import winterwell.utils.io.FileUtils; public class MarkdownPreview extends ViewPart { + private final Runnable refresh = new Runnable() { + volatile long lastExecution = System.currentTimeMillis(); + final static long WAIT_TIME = 2000L; + + @Override + public synchronized void run() { + try { + if (viewer == null || viewer.isDisposed()) { + return; + } + if (System.currentTimeMillis() - lastExecution < WAIT_TIME) { + return; + } else { + lastExecution = System.currentTimeMillis(); + } + URL fileUrl = previewFile.toURI().toURL(); + URL oldUrl = null; + try { + oldUrl = new URL(viewer.getUrl()); + } catch (MalformedURLException e) { + // Can happen, e.g. browser url is 'about:config' + } + if (fileUrl.equals(oldUrl)) { + viewer.refresh(); + } else { + viewer.setUrl(fileUrl.toString()); + } + } catch (MalformedURLException e) { + // Should not happen since the URL is generated from a file + throw new RuntimeException(e); + } + } + }; + public static MarkdownPreview preview = null; + private File previewFile = null; + private Browser viewer = null; - /** - * The constructor. - */ public MarkdownPreview() { preview = this; + previewFile = Activator.getDefault().getStateLocation().append("markdown.html").toFile(); } /** @@ -41,21 +80,22 @@ public void createPartControl(Composite parent) { viewer = new Browser(parent, SWT.MULTI); // | SWT.H_SCROLL | SWT.V_SCROLL } - - - /** * Passing the focus request to the viewer's control. */ @Override public void setFocus() { - if (viewer==null) return; + if (viewer == null || viewer.isDisposed()) { + return; + } viewer.setFocus(); update(); } public void update() { - if (viewer==null) return; + if (viewer == null || viewer.isDisposed()) { + return; + } try { IEditorPart editor = ActionBarContributor.getActiveEditor(); if (!(editor instanceof MarkdownEditor)) { @@ -64,16 +104,21 @@ public void update() { } MarkdownEditor ed = (MarkdownEditor) editor; MarkdownPage page = ed.getMarkdownPage(); - String html = page.html(); - html = addBaseURL(editor, html); - if (page != null) viewer.setText(html); - else viewer.setText(""); + if (page != null) { + String html = page.html(); + html = addBaseURL(editor, html); + FileUtils.write(previewFile, html); + Display.getCurrent().asyncExec(refresh); + } else { + viewer.setText(""); + } } catch (Exception ex) { // Smother System.out.println(ex); - if (viewer != null && !viewer.isDisposed()) + if (viewer != null && !viewer.isDisposed()) { viewer.setText(ex.getMessage()); + } } }