From db872f362580ddb4633fa19030cfe750a9dc253f Mon Sep 17 00:00:00 2001 From: Alexander Schwartz Date: Mon, 2 Sep 2019 18:55:07 +0200 Subject: [PATCH] pass prepended config via plugin instead of adding it to the content (#325) --- CHANGELOG.adoc | 4 +++ .../java/org/asciidoc/intellij/AsciiDoc.java | 27 ++++++++++++------- .../actions/asciidoc/CreatePdfAction.java | 5 ++-- .../AsciiDocAnnotationResultType.java | 8 +----- .../intellij/annotator/AsciiDocInfoType.java | 22 +++++++-------- .../intellij/annotator/ExternalAnnotator.java | 13 ++++----- .../intellij/asciidoc/PrependConfig.java | 26 ++++++++++++++++++ .../intellij/editor/AsciiDocHtmlPanel.java | 2 +- .../editor/AsciiDocPreviewEditor.java | 13 +++++---- .../intellij/editor/browser/BrowserPanel.java | 7 +++-- .../editor/javafx/JavaFxHtmlPanel.java | 5 ++-- .../editor/jeditor/JeditorHtmlPanel.java | 27 +++++++++---------- .../intellij/editor/javafx/scrollToElement.js | 9 +++---- .../org/asciidoc/intellij/AsciiDocTest.java | 2 +- 14 files changed, 94 insertions(+), 76 deletions(-) create mode 100644 src/main/java/org/asciidoc/intellij/asciidoc/PrependConfig.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 9190b30aa..cf5fae85a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -7,6 +7,10 @@ This document provides a high-level view of the changes introduced by release. [[releasenotes]] == Release notes +=== 0.30.1 (work in progress) + +- support .asciidoctorconfig for PDF creation (#325) + === 0.30.1 (preview, available from Github releases) - fix 'unable to read file' when creating a PDF and working with extensions (#325) diff --git a/src/main/java/org/asciidoc/intellij/AsciiDoc.java b/src/main/java/org/asciidoc/intellij/AsciiDoc.java index 9f7707579..232bd98c9 100644 --- a/src/main/java/org/asciidoc/intellij/AsciiDoc.java +++ b/src/main/java/org/asciidoc/intellij/AsciiDoc.java @@ -26,6 +26,7 @@ import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.geronimo.gshell.io.SystemOutputHijacker; import org.asciidoc.intellij.actions.asciidoc.AsciiDocAction; +import org.asciidoc.intellij.asciidoc.PrependConfig; import org.asciidoc.intellij.editor.AsciiDocPreviewEditor; import org.asciidoc.intellij.editor.javafx.JavaFxHtmlPanelProvider; import org.asciidoc.intellij.settings.AsciiDocApplicationSettings; @@ -61,7 +62,6 @@ import java.util.List; import java.util.Map; import java.util.ServiceConfigurationError; -import java.util.function.IntConsumer; import java.util.logging.Logger; /** @@ -71,6 +71,8 @@ public class AsciiDoc { private static Asciidoctor asciidoctor; + private static PrependConfig prependConfig; + private com.intellij.openapi.diagnostic.Logger log = com.intellij.openapi.diagnostic.Logger.getInstance(AsciiDoc.class); @@ -144,6 +146,8 @@ private void initWithExtensions(List extensions) { try { asciidoctor = Asciidoctor.Factory.create(); asciidoctor.registerLogHandler(logHandler); + prependConfig = new PrependConfig(); + asciidoctor.javaExtensionRegistry().preprocessor(prependConfig); // disable JUL logging of captured messages // https://github.com/asciidoctor/asciidoctorj/issues/669 Logger.getLogger("asciidoctor").setUseParentHandlers(false); @@ -255,8 +259,6 @@ private void notify(ByteArrayOutputStream boasOut, ByteArrayOutputStream boasErr } StringBuilder message = new StringBuilder(); message.append("Error during rendering ").append(name).append("; ").append(logRecord.getSeverity().name()).append(" "); - // TODO: for the current file there will be line numbers, but no file name. - // before we log the line numbers of the current file, they would need to be adjusted be the offset prefix if (logRecord.getCursor() != null && logRecord.getCursor().getFile() != null) { message.append(logRecord.getCursor().getFile()).append(":").append(logRecord.getCursor().getLineNumber()); } @@ -298,7 +300,7 @@ public static Path tempImagesPath() { } @NotNull - public static String prependConfig(Document document, Project project, IntConsumer offset) { + public static String config(Document document, Project project) { VirtualFile currentFile = FileDocumentManager.getInstance().getFile(document); StringBuilder tempContent = new StringBuilder(); if (currentFile != null) { @@ -329,9 +331,6 @@ public static String prependConfig(Document document, Project project, IntConsum } } } - int offsetLineNo = (int) tempContent.chars().filter(i -> i == '\n').count(); - tempContent.append(document.getText()); - offset.accept(offsetLineNo); return tempContent.toString(); } @@ -362,10 +361,14 @@ public interface Notifier { } public String render(String text, List extensions) { - return render(text, extensions, this::notify); + return render(text, "", extensions, this::notify); + } + + public String render(String text, String config, List extensions) { + return render(text, config, extensions, this::notify); } - public String render(String text, List extensions, Notifier notifier) { + public String render(String text, String config, List extensions, Notifier notifier) { synchronized (AsciiDoc.class) { CollectingLogHandler logHandler = new CollectingLogHandler(); ClassLoader old = Thread.currentThread().getContextClassLoader(); @@ -376,9 +379,11 @@ public String render(String text, List extensions, Notifier notifier) { try { initWithExtensions(extensions); asciidoctor.registerLogHandler(logHandler); + prependConfig.setConfig(config); try { return "
\n" + asciidoctor.convert(text, getDefaultOptions("html5")) + "\n
"; } finally { + prependConfig.setConfig(""); asciidoctor.unregisterLogHandler(logHandler); } } catch (Exception | ServiceConfigurationError ex) { @@ -408,7 +413,7 @@ public String render(String text, List extensions, Notifier notifier) { } } - public void renderPdf(File file, List extensions) { + public void renderPdf(File file, String config, List extensions) { Notifier notifier = this::notifyAlways; synchronized (AsciiDoc.class) { CollectingLogHandler logHandler = new CollectingLogHandler(); @@ -419,10 +424,12 @@ public void renderPdf(File file, List extensions) { Thread.currentThread().setContextClassLoader(AsciiDocAction.class.getClassLoader()); try { initWithExtensions(extensions); + prependConfig.setConfig(config); asciidoctor.registerLogHandler(logHandler); try { asciidoctor.convertFile(file, getDefaultOptions("pdf")); } finally { + prependConfig.setConfig(""); asciidoctor.unregisterLogHandler(logHandler); } } catch (Exception | ServiceConfigurationError ex) { diff --git a/src/main/java/org/asciidoc/intellij/actions/asciidoc/CreatePdfAction.java b/src/main/java/org/asciidoc/intellij/actions/asciidoc/CreatePdfAction.java index e9b7971d3..78e88aa57 100644 --- a/src/main/java/org/asciidoc/intellij/actions/asciidoc/CreatePdfAction.java +++ b/src/main/java/org/asciidoc/intellij/actions/asciidoc/CreatePdfAction.java @@ -66,10 +66,9 @@ public void actionPerformed(AnActionEvent event) { try { AsciiDoc asciiDoc = new AsciiDoc(project.getBasePath(), fileBaseDir, tempImagesPath, file.getName()); - /* TODO: content from .asciidoctorconfig not included, needing more experiments and ideas - how to include this into a file on disk. Maybe convert it to an extension? */ List extensions = AsciiDoc.getExtensions(project); - asciiDoc.renderPdf(new File(file.getCanonicalPath()), extensions); + String config = AsciiDoc.config(editor.getDocument(), project); + asciiDoc.renderPdf(new File(file.getCanonicalPath()), config, extensions); VirtualFile virtualFile = VirtualFileManager.getInstance() .refreshAndFindFileByUrl(file.getUrl().replaceAll("\\.(adoc|asciidoc|ad)$", ".pdf")); updateProjectView(virtualFile != null ? virtualFile : parent); diff --git a/src/main/java/org/asciidoc/intellij/annotator/AsciiDocAnnotationResultType.java b/src/main/java/org/asciidoc/intellij/annotator/AsciiDocAnnotationResultType.java index 90f46eb35..86fe4f5be 100644 --- a/src/main/java/org/asciidoc/intellij/annotator/AsciiDocAnnotationResultType.java +++ b/src/main/java/org/asciidoc/intellij/annotator/AsciiDocAnnotationResultType.java @@ -10,12 +10,10 @@ public class AsciiDocAnnotationResultType { private final Document document; - private final int offsetLineNo; private List logRecords; - public AsciiDocAnnotationResultType(Document document, int offsetLineNo) { + public AsciiDocAnnotationResultType(Document document) { this.document = document; - this.offsetLineNo = offsetLineNo; } public Document getDocument() { @@ -26,10 +24,6 @@ public List getLogRecords() { return logRecords; } - public int getOffsetLineNo() { - return offsetLineNo; - } - public static class Message { private final HighlightSeverity severity; private final Integer line; diff --git a/src/main/java/org/asciidoc/intellij/annotator/AsciiDocInfoType.java b/src/main/java/org/asciidoc/intellij/annotator/AsciiDocInfoType.java index 8b4998f3e..f9cc8fda1 100644 --- a/src/main/java/org/asciidoc/intellij/annotator/AsciiDocInfoType.java +++ b/src/main/java/org/asciidoc/intellij/annotator/AsciiDocInfoType.java @@ -8,16 +8,16 @@ public class AsciiDocInfoType { private final PsiFile file; private final Editor editor; - private final String contentWithConfig; + private final String content; + private final String config; private final List extensions; - private final int offsetLineNo; - public AsciiDocInfoType(PsiFile file, Editor editor, String contentWithConfig, List extensions, int offsetLineNo) { + public AsciiDocInfoType(PsiFile file, Editor editor, String content, String config, List extensions) { this.file = file; this.editor = editor; - this.contentWithConfig = contentWithConfig; + this.content = content; + this.config = config; this.extensions = extensions; - this.offsetLineNo = offsetLineNo; } public PsiFile getFile() { @@ -28,15 +28,15 @@ public Editor getEditor() { return editor; } - public String getContentWithConfig() { - return contentWithConfig; + public String getContent() { + return content; } - public List getExtensions() { - return extensions; + public String getConfig() { + return config; } - public int getOffsetLineNo() { - return offsetLineNo; + public List getExtensions() { + return extensions; } } diff --git a/src/main/java/org/asciidoc/intellij/annotator/ExternalAnnotator.java b/src/main/java/org/asciidoc/intellij/annotator/ExternalAnnotator.java index 6ac759bfb..15faffa0e 100644 --- a/src/main/java/org/asciidoc/intellij/annotator/ExternalAnnotator.java +++ b/src/main/java/org/asciidoc/intellij/annotator/ExternalAnnotator.java @@ -28,7 +28,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; /** * Run Asciidoc and use the warnings and errors as annotations in the file. @@ -41,10 +40,9 @@ public class ExternalAnnotator extends com.intellij.lang.annotation.ExternalAnno @Nullable @Override public AsciiDocInfoType collectInformation(@NotNull PsiFile file, @NotNull Editor editor, boolean hasErrors) { - AtomicInteger offsetLineNo = new AtomicInteger(0); - final String contentWithConfig = AsciiDoc.prependConfig(editor.getDocument(), file.getProject(), offsetLineNo::set); + final String config = AsciiDoc.config(editor.getDocument(), file.getProject()); List extensions = AsciiDoc.getExtensions(file.getProject()); - return new AsciiDocInfoType(file, editor, contentWithConfig, extensions, offsetLineNo.get()); + return new AsciiDocInfoType(file, editor, editor.getDocument().getText(), config, extensions); } @Nullable @@ -64,8 +62,7 @@ public AsciiDocAnnotationResultType doAnnotate(AsciiDocInfoType collectedInfo) { } } - AsciiDocAnnotationResultType asciidocAnnotationResultType = new AsciiDocAnnotationResultType(editor.getDocument(), - collectedInfo.getOffsetLineNo()); + AsciiDocAnnotationResultType asciidocAnnotationResultType = new AsciiDocAnnotationResultType(editor.getDocument()); if (!AsciiDocApplicationSettings.getInstance().getAsciiDocPreviewSettings().isShowAsciiDocWarningsAndErrorsInEditor()) { asciidocAnnotationResultType.setLogRecords(Collections.emptyList()); @@ -76,7 +73,7 @@ public AsciiDocAnnotationResultType doAnnotate(AsciiDocInfoType collectedInfo) { try { AsciiDoc asciiDoc = new AsciiDoc(file.getProject().getBasePath(), fileBaseDir, tempImagesPath, name); - asciiDoc.render(collectedInfo.getContentWithConfig(), collectedInfo.getExtensions(), (boasOut, boasErr, logRecords) + asciiDoc.render(collectedInfo.getContent(), collectedInfo.getConfig(), collectedInfo.getExtensions(), (boasOut, boasErr, logRecords) -> asciidocAnnotationResultType.setLogRecords(logRecords)); } finally { if (tempImagesPath != null) { @@ -110,7 +107,7 @@ public void apply(@NotNull PsiFile file, AsciiDocAnnotationResultType annotation // the line number used for creating the annotation (starting with 0) int lineNumberForAnnotation = 0; if (logRecord.getCursor() != null && logRecord.getCursor().getFile() == null && logRecord.getCursor().getLineNumber() >= 0) { - lineNumber = logRecord.getCursor().getLineNumber() - annotationResult.getOffsetLineNo(); + lineNumber = logRecord.getCursor().getLineNumber(); lineNumberForAnnotation = lineNumber - 1; if (lineNumberForAnnotation < 0) { // logRecords created in the prepended .asciidoctorconfig elements - will be shown on line zero diff --git a/src/main/java/org/asciidoc/intellij/asciidoc/PrependConfig.java b/src/main/java/org/asciidoc/intellij/asciidoc/PrependConfig.java new file mode 100644 index 000000000..0871f0f07 --- /dev/null +++ b/src/main/java/org/asciidoc/intellij/asciidoc/PrependConfig.java @@ -0,0 +1,26 @@ +package org.asciidoc.intellij.asciidoc; + +import org.asciidoctor.ast.Document; +import org.asciidoctor.extension.Preprocessor; +import org.asciidoctor.extension.PreprocessorReader; + +import java.util.Arrays; + +/** + * Prepend a configuration before a file. + * This will push back the configuration lines at the beginning. + * This will not change the line original numbers in the file. + * If messages are reported for the configuration lines, they will receive negative numbers. + */ +public class PrependConfig extends Preprocessor { + private String config = ""; + + @Override + public void process(Document document, PreprocessorReader reader) { + reader.restoreLines(Arrays.asList(config.split("\n"))); + } + + public void setConfig(String config) { + this.config = config; + } +} diff --git a/src/main/java/org/asciidoc/intellij/editor/AsciiDocHtmlPanel.java b/src/main/java/org/asciidoc/intellij/editor/AsciiDocHtmlPanel.java index a0810c57f..3472f9ce1 100644 --- a/src/main/java/org/asciidoc/intellij/editor/AsciiDocHtmlPanel.java +++ b/src/main/java/org/asciidoc/intellij/editor/AsciiDocHtmlPanel.java @@ -28,7 +28,7 @@ protected static String getCssLines(@Nullable String inlineCss) { return result.toString(); } - public abstract void scrollToLine(int line, int lineCount, int offsetLineNo); + public abstract void scrollToLine(int line, int lineCount); public Editor getEditor() { return editor; diff --git a/src/main/java/org/asciidoc/intellij/editor/AsciiDocPreviewEditor.java b/src/main/java/org/asciidoc/intellij/editor/AsciiDocPreviewEditor.java index b1dfe59e5..5beb65910 100644 --- a/src/main/java/org/asciidoc/intellij/editor/AsciiDocPreviewEditor.java +++ b/src/main/java/org/asciidoc/intellij/editor/AsciiDocPreviewEditor.java @@ -86,7 +86,6 @@ public class AsciiDocPreviewEditor extends UserDataHolderBase implements FileEdi private transient String currentContent = null; private transient int targetLineNo = 0; - private transient int offsetLineNo = 0; private transient int currentLineNo = 0; /** @@ -130,22 +129,22 @@ public AsciiDoc call() { }); private void render() { - final String contentWithConfig = AsciiDoc.prependConfig(document, project, o -> offsetLineNo = o); + final String config = AsciiDoc.config(document, project); + final String content = document.getText(); List extensions = AsciiDoc.getExtensions(project); lazyExecutor.execute(() -> { try { - if (!contentWithConfig.equals(currentContent)) { - currentContent = contentWithConfig; - - String markup = asciidoc.get().render(contentWithConfig, extensions); + if (!(config + content).equals(currentContent)) { + currentContent = config + content; + String markup = asciidoc.get().render(content, config, extensions); if (markup != null) { myPanel.setHtml(markup); } } if (currentLineNo != targetLineNo) { currentLineNo = targetLineNo; - myPanel.scrollToLine(targetLineNo, document.getLineCount(), offsetLineNo); + myPanel.scrollToLine(targetLineNo, document.getLineCount()); } ApplicationManager.getApplication().invokeLater(myHtmlPanelWrapper::repaint); } catch (InterruptedException e) { diff --git a/src/main/java/org/asciidoc/intellij/editor/browser/BrowserPanel.java b/src/main/java/org/asciidoc/intellij/editor/browser/BrowserPanel.java index b2d9db0f0..3e895816a 100644 --- a/src/main/java/org/asciidoc/intellij/editor/browser/BrowserPanel.java +++ b/src/main/java/org/asciidoc/intellij/editor/browser/BrowserPanel.java @@ -34,7 +34,6 @@ import java.util.List; import java.util.Objects; import java.util.Properties; -import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -137,13 +136,13 @@ private boolean isDarcula() { @NotNull public String getHtml(@NotNull VirtualFile file, @NotNull Project project) { Document document = FileDocumentManager.getInstance().getDocument(file); - AtomicInteger offsetLineNo = new AtomicInteger(); - final String contentWithConfig = AsciiDoc.prependConfig(document, project, offsetLineNo::set); + Objects.requireNonNull(document); + final String config = AsciiDoc.config(document, project); List extensions = AsciiDoc.getExtensions(project); Objects.requireNonNull(file.getParent().getCanonicalPath(), "we will have files, these will always have a parent directory"); AsciiDoc asciiDoc = new AsciiDoc(project.getBasePath(), new File(file.getParent().getCanonicalPath()), imagesPath, file.getName()); - String html = asciiDoc.render(contentWithConfig, extensions); + String html = asciiDoc.render(document.getText(), config, extensions); if (file.getParent() != null) { // parent will be null if we use Language Injection and Fragment Editor base = file.getParent().getPath(); diff --git a/src/main/java/org/asciidoc/intellij/editor/javafx/JavaFxHtmlPanel.java b/src/main/java/org/asciidoc/intellij/editor/javafx/JavaFxHtmlPanel.java index 1a6eec7ef..8886e8c34 100644 --- a/src/main/java/org/asciidoc/intellij/editor/javafx/JavaFxHtmlPanel.java +++ b/src/main/java/org/asciidoc/intellij/editor/javafx/JavaFxHtmlPanel.java @@ -547,13 +547,12 @@ public void render() { } @Override - public void scrollToLine(final int line, final int lineCount, int offsetLineNo) { + public void scrollToLine(final int line, final int lineCount) { this.lineCount = lineCount; - this.offset = offsetLineNo; runInPlatformWhenAvailable(() -> { JavaFxHtmlPanel.this.getWebViewGuaranteed().getEngine().executeScript( "if ('__IntelliJTools' in window) " + - "__IntelliJTools.scrollToLine(" + line + ", " + lineCount + ", " + offsetLineNo + ");" + "__IntelliJTools.scrollToLine(" + line + ", " + lineCount + ");" ); final Object result = JavaFxHtmlPanel.this.getWebViewGuaranteed().getEngine().executeScript( "document.documentElement.scrollTop || document.body.scrollTop"); diff --git a/src/main/java/org/asciidoc/intellij/editor/jeditor/JeditorHtmlPanel.java b/src/main/java/org/asciidoc/intellij/editor/jeditor/JeditorHtmlPanel.java index c3e0060a3..6d080b073 100644 --- a/src/main/java/org/asciidoc/intellij/editor/jeditor/JeditorHtmlPanel.java +++ b/src/main/java/org/asciidoc/intellij/editor/jeditor/JeditorHtmlPanel.java @@ -45,10 +45,13 @@ final class JeditorHtmlPanel extends AsciiDocHtmlPanel { scrollPane = new JBScrollPane(jEditorPane); // Setup the editor pane for rendering HTML. File baseDir = new File(""); - VirtualFile parent = FileDocumentManager.getInstance().getFile(document).getParent(); - if (parent != null) { - // parent will be null if we use Language Injection and Fragment Editor - baseDir = new File(parent.getCanonicalPath()); + VirtualFile file = FileDocumentManager.getInstance().getFile(document); + if (file != null) { + VirtualFile parent = file.getParent(); + if (parent != null && parent.getCanonicalPath() != null) { + // parent will be null if we use Language Injection and Fragment Editor + baseDir = new File(parent.getCanonicalPath()); + } } final HTMLEditorKit kit = new AsciiDocEditorKit(baseDir); @@ -115,13 +118,10 @@ private void updatePreviewOnEDT(final javax.swing.text.Document doc) { * * @see http://en.wikipedia.org/wiki/Event_dispatching_thread) */ - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - jEditorPane.setDocument(doc); - Rectangle d = jEditorPane.getVisibleRect(); - jEditorPane.setSize((int) d.getWidth(), (int) jEditorPane.getSize().getHeight()); - } + UIUtil.invokeAndWaitIfNeeded((Runnable) () -> { + jEditorPane.setDocument(doc); + Rectangle d = jEditorPane.getVisibleRect(); + jEditorPane.setSize((int) d.getWidth(), (int) jEditorPane.getSize().getHeight()); }); } @@ -131,13 +131,10 @@ public void render() { } @Override - public void scrollToLine(int line, int lineCount, int offsetLineNo) { + public void scrollToLine(int line, int lineCount) { // NOOP } - private void adjustBrowserSize() { - } - @Override public void dispose() { diff --git a/src/main/resources/org/asciidoc/intellij/editor/javafx/scrollToElement.js b/src/main/resources/org/asciidoc/intellij/editor/javafx/scrollToElement.js index 52a2c5573..226324261 100644 --- a/src/main/resources/org/asciidoc/intellij/editor/javafx/scrollToElement.js +++ b/src/main/resources/org/asciidoc/intellij/editor/javafx/scrollToElement.js @@ -31,15 +31,12 @@ window.__IntelliJTools.scrollToLine = (function () { return offset } - var scrollToLine = function (newLineToScroll, lineCount, offsetLineNo) { - - newLineToScroll += offsetLineNo; - lineCount += offsetLineNo; + var scrollToLine = function (newLineToScroll, lineCount) { // the sourcelines will be as CSS class elements that also have class has-source-line var blocks = document.getElementsByClassName('has-source-line'); var startY = 0; - var startLine = offsetLineNo; + var startLine = 0; var endY; var endLine = lineCount; @@ -62,7 +59,7 @@ window.__IntelliJTools.scrollToLine = (function () { var resultY = startY // interpolate the relative position inside the current block - if (newLineToScroll === offsetLineNo) { + if (newLineToScroll === 0) { resultY = 0; } else if (endY !== undefined && newLineToScroll !== startLine) { resultY += (newLineToScroll - startLine) / (endLine - startLine) * (endY - startY) diff --git a/src/test/java/org/asciidoc/intellij/AsciiDocTest.java b/src/test/java/org/asciidoc/intellij/AsciiDocTest.java index e015b377a..6d6e7db68 100644 --- a/src/test/java/org/asciidoc/intellij/AsciiDocTest.java +++ b/src/test/java/org/asciidoc/intellij/AsciiDocTest.java @@ -52,7 +52,7 @@ public void testShouldRenderPdf() throws IOException { fw.close(); // when... - this.asciidoc.renderPdf(asciidoc, new ArrayList<>()); + this.asciidoc.renderPdf(asciidoc, "", new ArrayList<>()); // then... Assert.assertTrue(pdf.exists());