package com.thoughtworks.gauge.markdownPreview; import com.intellij.codeHighlighting.BackgroundEditorHighlighter; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorLocation; import com.intellij.openapi.fileEditor.FileEditorState; import com.intellij.openapi.fileEditor.FileEditorStateLevel; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.ui.components.JBScrollPane; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.pegdown.PegDownProcessor; import javax.swing.*; import javax.swing.text.DefaultCaret; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; import java.awt.*; import java.beans.PropertyChangeListener; public class MarkdownPreviewEditor extends UserDataHolderBase implements FileEditor { private Document document; private boolean previewIsObsolete = true; protected final JEditorPane jEditorPane = new JEditorPane(); private final JScrollPane scrollPane = new JBScrollPane(jEditorPane); private PegDownProcessor processor; private PegDownProcessor initProcessor() { MarkdownExtensions markdownExtensions = new MarkdownExtensions(); return new PegDownProcessor(markdownExtensions.getExtensionsValue(), markdownExtensions.getParsingTimeout()); } public MarkdownPreviewEditor(@NotNull Project project, @NotNull Document document) { this.document = document; this.processor = initProcessor(); this.document.addDocumentListener(new DocumentAdapter() { @Override public void documentChanged(DocumentEvent e) { previewIsObsolete = true; } }); final HTMLEditorKit kit = new HTMLPreviewEditor(document); StyleSheet styleSheet = new StyleSheet(); styleSheet.importStyleSheet(MarkdownPreviewEditor.class.getResource("/preview.css")); kit.setStyleSheet(styleSheet); jEditorPane.setEditorKit(kit); jEditorPane.setEditable(false); jEditorPane.setText(document.getText()); jEditorPane.getCaret().setMagicCaretPosition(new Point(0, 0)); ((DefaultCaret) jEditorPane.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE); jEditorPane.addHyperlinkListener(new MarkdownLinkListener(jEditorPane, project, document)); } @NotNull @Override public JComponent getComponent() { return scrollPane; } @Nullable @Override public JComponent getPreferredFocusedComponent() { return scrollPane; } @NotNull @Override public String getName() { return "HTML Preview"; } @NotNull @Override public FileEditorState getState(@NotNull FileEditorStateLevel fileEditorStateLevel) { return FileEditorState.INSTANCE; } @Override public void setState(@NotNull FileEditorState fileEditorState) { } @Override public boolean isModified() { return false; } @Override public boolean isValid() { return document.getText() != null; } @Override public void selectNotify() { if (previewIsObsolete) { try { jEditorPane.setText(String.format("<div id=\"markdown-preview\">%s</div>", processor.markdownToHtml(Formatter.format(document.getText())))); previewIsObsolete = false; } catch (Exception e) { e.printStackTrace(); } } } @Override public void deselectNotify() { } @Override public void addPropertyChangeListener(@NotNull PropertyChangeListener propertyChangeListener) { } @Override public void removePropertyChangeListener(@NotNull PropertyChangeListener propertyChangeListener) { } @Nullable @Override public BackgroundEditorHighlighter getBackgroundHighlighter() { return null; } @Nullable @Override public FileEditorLocation getCurrentLocation() { return null; } @Nullable @Override public StructureViewBuilder getStructureViewBuilder() { return null; } @Override public void dispose() { Disposer.dispose(this); } }