From 3f4b0ef27ddca9d0d5459bbfcdff9226817d344f Mon Sep 17 00:00:00 2001 From: Bogdan Haidu Date: Fri, 27 Feb 2026 20:01:49 +0200 Subject: [PATCH] markdown document preview improvements Closes #6652 - bump java release version to 17 - custom
tag renderer - added flexmark strikethrough extension - update vscode regex for striketrhough detection - updated mime type to the latest official text/markdown - created new mime type for preview - using a default skeleton css code for margin, paddings ... - added font configs for markdown preview - link coloring and font size customization css to font config settings --- .../nbproject/project.xml | 1 + ide/libs.flexmark/external/binaries-list | 1 + .../external/flexmark-0.64.8-license.txt | 2 +- ide/libs.flexmark/manifest.mf | 2 +- .../nbproject/project.properties | 1 + ide/libs.flexmark/nbproject/project.xml | 4 + ide/markdown/licenseinfo.xml | 7 +- ide/markdown/manifest.mf | 1 + ide/markdown/nbproject/project.xml | 27 +++ .../modules/markdown/MarkdownDataObject.java | 6 +- .../markdown/MarkdownViewerElement.java | 56 +++++- .../modules/markdown/markdown.tmLanguage.json | 4 +- .../markdown/resources/Bundle.properties | 33 ++++ .../modules/markdown/resources/Coloring.md | 7 + .../resources/FontAndColors-bluetheme.xml | 50 +++++ .../resources/FontAndColors-citylights.xml | 50 +++++ .../resources/FontAndColors-earth.xml | 50 +++++ .../resources/FontAndColors-flatlafdark.xml | 50 +++++ .../markdown/resources/FontAndColors.xml | 50 +++++ .../modules/markdown/resources/layer.xml | 82 +++++++++ .../ui/preview/MarkdownEditorKit.java | 29 ++- .../ui/preview/views/HorizontalRuleView.java | 55 ++++++ .../ui/preview/views/MarkdownViewFactory.java | 3 +- .../modules/markdown/utils/Bundle.properties | 27 +++ .../modules/markdown/utils/StyleUtils.java | 174 ++++++++++++++++++ 25 files changed, 756 insertions(+), 16 deletions(-) create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/resources/Bundle.properties create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/resources/Coloring.md create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-bluetheme.xml create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-citylights.xml create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-earth.xml create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-flatlafdark.xml create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors.xml create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/resources/layer.xml create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/ui/preview/views/HorizontalRuleView.java create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/utils/Bundle.properties create mode 100644 ide/markdown/src/org/netbeans/modules/markdown/utils/StyleUtils.java diff --git a/ide/editor.settings.storage/nbproject/project.xml b/ide/editor.settings.storage/nbproject/project.xml index 83a372138070..762c7fc295de 100644 --- a/ide/editor.settings.storage/nbproject/project.xml +++ b/ide/editor.settings.storage/nbproject/project.xml @@ -175,6 +175,7 @@ org.netbeans.modules.gsf org.netbeans.modules.jvi org.netbeans.modules.languages + org.netbeans.modules.markdown org.netbeans.modules.options.editor org.netbeans.modules.editor.fold org.netbeans.modules.editor.fold.nbui diff --git a/ide/libs.flexmark/external/binaries-list b/ide/libs.flexmark/external/binaries-list index 76b2667dc273..9fba964a4608 100644 --- a/ide/libs.flexmark/external/binaries-list +++ b/ide/libs.flexmark/external/binaries-list @@ -30,4 +30,5 @@ A3F92ABD0ACBB4D1F12DFD3D6128F73D245D6BA9 com.vladsch.flexmark:flexmark-util-data 985913246DF64FE7E768EB0664B45DEDEA7536CF com.vladsch.flexmark:flexmark-util-sequence:0.64.8 A8178BA6DFD7A958353A60B3A51FE7EDB1578B49 com.vladsch.flexmark:flexmark-util-visitor:0.64.8 4ADC75ADA3D870908BDBFFB76650D19305250D3C com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.64.8 +1851E124C6D85C5C7F3FDBBE066D30A76AD6BE44 com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.64.8 CD56EB47DCD4590EF6451F87E5EC33BDDD1A9A51 org.jsoup:jsoup:1.15.4 diff --git a/ide/libs.flexmark/external/flexmark-0.64.8-license.txt b/ide/libs.flexmark/external/flexmark-0.64.8-license.txt index 454986f6a8b7..3613e9233a19 100644 --- a/ide/libs.flexmark/external/flexmark-0.64.8-license.txt +++ b/ide/libs.flexmark/external/flexmark-0.64.8-license.txt @@ -3,7 +3,7 @@ Version: 0.64.8 License: BSD-flexmark Description: FlexMark library Origin: https://github.com/vsch/flexmark-java -Files: flexmark-0.64.8.jar flexmark-ext-anchorlink-0.64.8.jar flexmark-ext-emoji-0.64.8.jar flexmark-ext-tables-0.64.8.jar flexmark-html2md-converter-0.64.8.jar flexmark-util-ast-0.64.8.jar flexmark-util-builder-0.64.8.jar flexmark-util-collection-0.64.8.jar flexmark-util-data-0.64.8.jar flexmark-util-dependency-0.64.8.jar flexmark-util-format-0.64.8.jar flexmark-util-html-0.64.8.jar flexmark-util-misc-0.64.8.jar flexmark-util-sequence-0.64.8.jar flexmark-util-visitor-0.64.8.jar flexmark-ext-gfm-tasklist-0.64.8.jar +Files: flexmark-0.64.8.jar flexmark-ext-anchorlink-0.64.8.jar flexmark-ext-emoji-0.64.8.jar flexmark-ext-tables-0.64.8.jar flexmark-html2md-converter-0.64.8.jar flexmark-util-ast-0.64.8.jar flexmark-util-builder-0.64.8.jar flexmark-util-collection-0.64.8.jar flexmark-util-data-0.64.8.jar flexmark-util-dependency-0.64.8.jar flexmark-util-format-0.64.8.jar flexmark-util-html-0.64.8.jar flexmark-util-misc-0.64.8.jar flexmark-util-sequence-0.64.8.jar flexmark-util-visitor-0.64.8.jar flexmark-ext-gfm-tasklist-0.64.8.jar flexmark-ext-gfm-strikethrough-0.64.8.jar Copyright (c) 2015-2016, Atlassian Pty Ltd All rights reserved. diff --git a/ide/libs.flexmark/manifest.mf b/ide/libs.flexmark/manifest.mf index 4f6866796a25..78acbb9fc942 100644 --- a/ide/libs.flexmark/manifest.mf +++ b/ide/libs.flexmark/manifest.mf @@ -2,5 +2,5 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.netbeans.libs.flexmark OpenIDE-Module-Localizing-Bundle: org/netbeans/libs/flexmark/Bundle.properties -OpenIDE-Module-Specification-Version: 1.25 +OpenIDE-Module-Specification-Version: 1.26 diff --git a/ide/libs.flexmark/nbproject/project.properties b/ide/libs.flexmark/nbproject/project.properties index a5b37dfe8353..3eaf3b253be5 100644 --- a/ide/libs.flexmark/nbproject/project.properties +++ b/ide/libs.flexmark/nbproject/project.properties @@ -33,6 +33,7 @@ release.external/flexmark-ext-emoji-0.64.8.jar=modules/ext/flexmark-ext-emoji-0. release.external/flexmark-ext-anchorlink-0.64.8.jar=modules/ext/flexmark-ext-anchorlink-0.64.8.jar release.external/flexmark-ext-tables-0.64.8.jar=modules/ext/flexmark-ext-tables-0.64.8.jar release.external/flexmark-ext-gfm-tasklist-0.64.8.jar=modules/ext/flexmark-ext-gfm-tasklist-0.64.8.jar +release.external/flexmark-ext-gfm-strikethrough-0.64.8.jar=modules/ext/flexmark-ext-gfm-strikethrough-0.64.8.jar release.external/jsoup-1.15.4.jar=modules/ext/jsoup-1.15.4.jar # Sigtest seems to have issues with some Java 11 class files, better to disable it. diff --git a/ide/libs.flexmark/nbproject/project.xml b/ide/libs.flexmark/nbproject/project.xml index d2d8e0ca6227..41103fefe664 100644 --- a/ide/libs.flexmark/nbproject/project.xml +++ b/ide/libs.flexmark/nbproject/project.xml @@ -97,6 +97,10 @@ ext/flexmark-ext-gfm-tasklist-0.64.8.jar external/flexmark-ext-gfm-tasklist-0.64.8.jar + + ext/flexmark-ext-gfm-strikethrough-0.64.8.jar + external/flexmark-ext-gfm-strikethrough-0.64.8.jar + diff --git a/ide/markdown/licenseinfo.xml b/ide/markdown/licenseinfo.xml index 0c60cbe82bf3..775ccedd758d 100644 --- a/ide/markdown/licenseinfo.xml +++ b/ide/markdown/licenseinfo.xml @@ -34,5 +34,10 @@ src/org/netbeans/modules/markdown/resources/Template.md - + + + src/org/netbeans/modules/markdown/resources/Coloring.md + + + diff --git a/ide/markdown/manifest.mf b/ide/markdown/manifest.mf index fe00e45399b8..44aa92cd5218 100644 --- a/ide/markdown/manifest.mf +++ b/ide/markdown/manifest.mf @@ -1,6 +1,7 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.netbeans.modules.markdown +OpenIDE-Module-Layer: org/netbeans/modules/markdown/resources/layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/markdown/Bundle.properties OpenIDE-Module-Specification-Version: 1.20 diff --git a/ide/markdown/nbproject/project.xml b/ide/markdown/nbproject/project.xml index 2634c03dc1fd..ab3649a59c34 100644 --- a/ide/markdown/nbproject/project.xml +++ b/ide/markdown/nbproject/project.xml @@ -50,6 +50,33 @@ 1.15 + + org.netbeans.modules.editor.mimelookup + + + + 1 + 1.72 + + + + org.netbeans.modules.editor.settings + + + + 1 + 1.89 + + + + org.netbeans.modules.editor.settings.storage + + + + 1 + 1.84 + + org.netbeans.modules.textmate.lexer diff --git a/ide/markdown/src/org/netbeans/modules/markdown/MarkdownDataObject.java b/ide/markdown/src/org/netbeans/modules/markdown/MarkdownDataObject.java index 8629433abec4..a536cf30696a 100644 --- a/ide/markdown/src/org/netbeans/modules/markdown/MarkdownDataObject.java +++ b/ide/markdown/src/org/netbeans/modules/markdown/MarkdownDataObject.java @@ -105,11 +105,11 @@ @GrammarRegistration(mimeType=MarkdownDataObject.MIME_TYPE, grammar="markdown.tmLanguage.json") public class MarkdownDataObject extends MultiDataObject { - public static final String MIME_TYPE = "text/x-markdown-nb"; + public static final String MIME_TYPE = "text/markdown"; public MarkdownDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException { super(pf, loader); - registerEditor("text/x-markdown", true); + registerEditor(MIME_TYPE, true); } @Override @@ -120,7 +120,7 @@ protected int associateLookup() { @MultiViewElement.Registration( displayName = "#LBL_Markdown_EDITOR", iconBase = "org/netbeans/modules/markdown/markdown.png", - mimeType = "text/x-markdown", + mimeType = "text/markdown", persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED, preferredID = "Markdown", position = 1000 diff --git a/ide/markdown/src/org/netbeans/modules/markdown/MarkdownViewerElement.java b/ide/markdown/src/org/netbeans/modules/markdown/MarkdownViewerElement.java index db65b2a5d9e9..d4d07fa525cd 100644 --- a/ide/markdown/src/org/netbeans/modules/markdown/MarkdownViewerElement.java +++ b/ide/markdown/src/org/netbeans/modules/markdown/MarkdownViewerElement.java @@ -19,6 +19,7 @@ package org.netbeans.modules.markdown; import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension; +import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension; import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension; import com.vladsch.flexmark.ext.tables.TablesExtension; import com.vladsch.flexmark.html.HtmlRenderer; @@ -26,7 +27,10 @@ import com.vladsch.flexmark.util.data.DataHolder; import com.vladsch.flexmark.util.data.MutableDataSet; import java.awt.BorderLayout; +import java.awt.Cursor; import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.Reader; import java.io.StringReader; @@ -49,6 +53,8 @@ import org.netbeans.core.spi.multiview.CloseOperationState; import org.netbeans.core.spi.multiview.MultiViewElement; import org.netbeans.core.spi.multiview.MultiViewElementCallback; +import org.netbeans.modules.editor.settings.storage.api.EditorSettings; +import static org.netbeans.modules.markdown.MarkdownDataObject.MIME_TYPE; import org.netbeans.modules.markdown.ui.preview.MarkdownEditorKit; import org.openide.awt.HtmlBrowser; import org.openide.awt.UndoRedo; @@ -62,16 +68,18 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.RequestProcessor; import org.openide.util.RequestProcessor.Task; +import org.openide.util.WeakListeners; import org.openide.windows.TopComponent; /** * * @author lkishalmi */ + @MultiViewElement.Registration( displayName = "#LBL_MarkdownViewer", iconBase = "org/netbeans/modules/markdown/markdown.png", - mimeType = "text/x-markdown", + mimeType = MIME_TYPE, persistenceType = TopComponent.PERSISTENCE_NEVER, preferredID = "MarkdownViewer", position = 2000 @@ -79,6 +87,7 @@ @Messages("LBL_MarkdownViewer=Preview") public class MarkdownViewerElement implements MultiViewElement { + public static final String MIME_TYPE_PREVIEW = "text/x-markdown-nb-preview"; private static final Logger LOG = Logger.getLogger(MarkdownViewerElement.class.getName()); private static final RequestProcessor RP = new RequestProcessor(MarkdownViewerElement.class); private static final int UPDATE_DELAY = 500; @@ -94,16 +103,17 @@ public class MarkdownViewerElement implements MultiViewElement { .set(Parser.EXTENSIONS, Arrays.asList( AnchorLinkExtension.create(), TablesExtension.create(), - TaskListExtension.create() + TaskListExtension.create(), + StrikethroughExtension.create() )) .set(HtmlRenderer.INDENT_SIZE, 2) .set(HtmlRenderer.RENDER_HEADER_ID, true) - .set(HtmlRenderer.FENCED_CODE_LANGUAGE_CLASS_PREFIX, "") + .set(HtmlRenderer.FENCED_CODE_LANGUAGE_CLASS_PREFIX, "") //NOI18N // JEditorPane search for the name attribute .set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true) .set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false) - .set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "") - .set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "") + .set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "") //NOI18N + .set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "") //NOI18N // Make the table generation SWING Friendly .set(TablesExtension.COLUMN_SPANS, false) .set(TablesExtension.MIN_HEADER_ROWS, 1) @@ -111,6 +121,9 @@ public class MarkdownViewerElement implements MultiViewElement { .set(TablesExtension.APPEND_MISSING_COLUMNS, true) .set(TablesExtension.DISCARD_EXTRA_COLUMNS, true) .set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true) + // Strikethrough change from del to s tag + .set(StrikethroughExtension.STRIKETHROUGH_STYLE_HTML_OPEN, "") //NOI18N + .set(StrikethroughExtension.STRIKETHROUGH_STYLE_HTML_CLOSE, "") //NOI18N .toImmutable(); final Parser parser = Parser.builder(OPTIONS).build(); @@ -134,8 +147,12 @@ public void changedUpdate(DocumentEvent e) { }; private final Task updater = RP.create(MarkdownViewerElement.this::updateView); + private StyledDocument source; + //Font config update listener + private final PropertyChangeListener pcl = this::colorProfileChange; + public MarkdownViewerElement(Lookup lookup) { dataObject = lookup.lookup(MarkdownDataObject.class); } @@ -143,10 +160,13 @@ public MarkdownViewerElement(Lookup lookup) { @Override public JComponent getVisualRepresentation() { if (component == null) { + EditorSettings.getDefault().addPropertyChangeListener(WeakListeners.propertyChange(pcl, this)); viewer = new JEditorPane(); viewer.setEditorKit(new MarkdownEditorKit()); viewer.setEditable(false); viewer.addHyperlinkListener(this::linkHandler); + Cursor textCursor = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR); + viewer.setCursor(textCursor); JPanel panel = new JPanel(new BorderLayout()); panel.add(new JScrollPane(viewer), BorderLayout.CENTER); @@ -250,7 +270,6 @@ public void updateView() { kit.read(htmlReader, doc, 0); viewer.scrollRectToVisible(vis); - } catch (IOException ex) { viewer.setText(Bundle.TXT_MarkdownViewerElement_Error()); LOG.log(Level.WARNING, "Could not parse markdown!", ex); //NOI18N @@ -289,4 +308,29 @@ private void linkHandler(HyperlinkEvent evt) { } } } + + /** + * redraw document if profile changes or font setting changes + * @param evt + */ + public void colorProfileChange(PropertyChangeEvent evt) { + if (viewer == null) { + return; + } + + String newValue = evt.getNewValue() instanceof String value ? value : ""; // NOI18N + boolean fontChanged = false; + //patch for triggering font update + if ("fontColors".equals(evt.getPropertyName()) // NOI18N + && evt.getOldValue() != null + && !newValue.startsWith("test") // NOI18N + ) { + fontChanged = true; + } + + if (fontChanged || EditorSettings.PROP_CURRENT_FONT_COLOR_PROFILE.equals(evt.getPropertyName())) { + viewer.setEditorKit(new MarkdownEditorKit()); + updateView(); + } + } } diff --git a/ide/markdown/src/org/netbeans/modules/markdown/markdown.tmLanguage.json b/ide/markdown/src/org/netbeans/modules/markdown/markdown.tmLanguage.json index 463a3fbbbdec..f28917c770af 100644 --- a/ide/markdown/src/org/netbeans/modules/markdown/markdown.tmLanguage.json +++ b/ide/markdown/src/org/netbeans/modules/markdown/markdown.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/7418dd20d76c72e82fadee2909e03239e9973b35", + "version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/548ccb91ef58ba40ac745b400d889933ccd5eb4d", "name": "Markdown", "scopeName": "text.html.markdown", "patterns": [ @@ -3084,7 +3084,7 @@ "name": "punctuation.definition.strikethrough.markdown" } }, - "match": "(? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-citylights.xml b/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-citylights.xml new file mode 100644 index 000000000000..452c9a83dbaf --- /dev/null +++ b/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-citylights.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-earth.xml b/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-earth.xml new file mode 100644 index 000000000000..452c9a83dbaf --- /dev/null +++ b/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-earth.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-flatlafdark.xml b/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-flatlafdark.xml new file mode 100644 index 000000000000..2501c4055114 --- /dev/null +++ b/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors-flatlafdark.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors.xml b/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors.xml new file mode 100644 index 000000000000..5aad74897724 --- /dev/null +++ b/ide/markdown/src/org/netbeans/modules/markdown/resources/FontAndColors.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ide/markdown/src/org/netbeans/modules/markdown/resources/layer.xml b/ide/markdown/src/org/netbeans/modules/markdown/resources/layer.xml new file mode 100644 index 000000000000..ce8cd46c12c5 --- /dev/null +++ b/ide/markdown/src/org/netbeans/modules/markdown/resources/layer.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/MarkdownEditorKit.java b/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/MarkdownEditorKit.java index cf6523fb06f5..f0b1242d9655 100644 --- a/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/MarkdownEditorKit.java +++ b/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/MarkdownEditorKit.java @@ -18,9 +18,13 @@ */ package org.netbeans.modules.markdown.ui.preview; +import javax.swing.text.Document; import org.netbeans.modules.markdown.ui.preview.views.MarkdownViewFactory; import javax.swing.text.ViewFactory; +import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.StyleSheet; +import org.netbeans.modules.markdown.utils.StyleUtils; /** * @@ -29,14 +33,37 @@ public class MarkdownEditorKit extends HTMLEditorKit { private final transient ViewFactory viewFactory; - + public MarkdownEditorKit() { super(); this.viewFactory = new MarkdownViewFactory(); } + /** + * copy/paste from the original HTMLEditorKit method but with custom styling overriding + * @see HTMLEditorKit.createDefaultDocument + * + * @return + */ + @Override + public Document createDefaultDocument() { + StyleSheet styles = getStyleSheet(); + StyleSheet ss = new StyleSheet(); + + //default style override + ss.addStyleSheet(styles); + StyleUtils.addNbSyles(ss); + + HTMLDocument doc = new HTMLDocument(ss); + doc.setParser(getParser()); + doc.setAsynchronousLoadPriority(4); + doc.setTokenThreshold(100); + return doc; + } + @Override public ViewFactory getViewFactory() { return viewFactory; } + } diff --git a/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/views/HorizontalRuleView.java b/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/views/HorizontalRuleView.java new file mode 100644 index 000000000000..bbc27641886c --- /dev/null +++ b/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/views/HorizontalRuleView.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.markdown.ui.preview.views; + +import java.awt.Color; +import java.awt.Component; +import java.awt.GridLayout; +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.border.EmptyBorder; +import javax.swing.text.ComponentView; +import javax.swing.text.Element; + +/** + * + * hr tags don't have any customization from CSS using swing html renderer + * + * Render patch to have controlled display + */ +public class HorizontalRuleView extends ComponentView { + + public HorizontalRuleView(Element elem) { + super(elem); + } + + @Override + protected Component createComponent() { + JPanel panel = new JPanel(); + panel.setOpaque(false); + JSeparator component = new JSeparator(); + component.setOrientation(HORIZONTAL); + component.setBorder(BorderFactory.createLineBorder(new Color(209, 217, 224), 2)); + panel.add(component); + panel.setBorder(new EmptyBorder(20, 0, 20, 0)); + panel.setLayout(new GridLayout(0,1)); + return panel; + } +} diff --git a/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/views/MarkdownViewFactory.java b/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/views/MarkdownViewFactory.java index a1c426e88b99..5d92a0bec9fb 100644 --- a/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/views/MarkdownViewFactory.java +++ b/ide/markdown/src/org/netbeans/modules/markdown/ui/preview/views/MarkdownViewFactory.java @@ -38,9 +38,10 @@ public class MarkdownViewFactory extends HTMLEditorKit.HTMLFactory { @Override public View create(Element elem) { - if (isElementOfTag(elem, HTML.Tag.INPUT)) { return new CheckboxView(elem); + } else if (isElementOfTag(elem, HTML.Tag.HR)) { + return new HorizontalRuleView(elem); } return super.create(elem); diff --git a/ide/markdown/src/org/netbeans/modules/markdown/utils/Bundle.properties b/ide/markdown/src/org/netbeans/modules/markdown/utils/Bundle.properties new file mode 100644 index 000000000000..fdd2c1d3ff1f --- /dev/null +++ b/ide/markdown/src/org/netbeans/modules/markdown/utils/Bundle.properties @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +CSS_DEFAULT=body {padding:10px 25px;}\ +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {font-size:inherit;}\ +ul, li ul {margin-left: 20px;margin-bottom: 0px;}\ +li {margin-bottom: 3px;padding-left:5px;}\ +table {border-spacing:0;}\ +th, td {border:1px solid rgb(209, 217, 224); padding:10px;}\ +code {padding:2px 0px;}\ +pre {padding:16px;margin-bottom:10px;}\ +blockquote {padding: 0 16px; margin: 0px; margin-bottom:10px; border-left: 2px solid rgb(209, 217, 224);}\ +li blockquote {margin-bottom: 0px;} table {margin-top:6px;margin-bottom:6px;} \ No newline at end of file diff --git a/ide/markdown/src/org/netbeans/modules/markdown/utils/StyleUtils.java b/ide/markdown/src/org/netbeans/modules/markdown/utils/StyleUtils.java new file mode 100644 index 000000000000..e23d07ec505e --- /dev/null +++ b/ide/markdown/src/org/netbeans/modules/markdown/utils/StyleUtils.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.markdown.utils; + +import java.awt.Color; +import java.util.Iterator; +import java.util.Map; +import javax.swing.text.AttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.html.StyleSheet; +import org.netbeans.api.editor.mimelookup.MimeLookup; +import org.netbeans.api.editor.mimelookup.MimePath; +import org.netbeans.modules.editor.settings.storage.api.EditorSettings; +import org.netbeans.api.editor.settings.FontColorSettings; +import org.netbeans.modules.editor.settings.storage.api.FontColorSettingsFactory; +import static org.netbeans.modules.markdown.MarkdownViewerElement.MIME_TYPE_PREVIEW; +import org.openide.util.NbBundle; + +/** + * + * @author bhaidu + */ +public class StyleUtils { + + private static final Map fontConfig2tagMapping = Map.ofEntries( + Map.entry("anchor", "a"), // NOI18N + Map.entry("body", "body"), // NOI18N + Map.entry("code", "code"), // NOI18N + Map.entry("pre", "pre"), // NOI18N + Map.entry("blockquote", "blockquote p"), // NOI18N + Map.entry("heading1", "h1, h1 a"), // NOI18N + Map.entry("heading2", "h2, h2 a"), // NOI18N + Map.entry("heading3", "h3, h3 a"), // NOI18N + Map.entry("heading4", "h4, h4 a"), // NOI18N + Map.entry("heading5", "h5, h5 a"), // NOI18N + Map.entry("heading6", "h6, h6 a") // NOI18N + ); + + public static void addNbSyles(StyleSheet ss) { + + //main css + appendDefaultMarkdownCssRules(ss); + + //coloring & font settings + appendColoringCssRulesFromFontConfigs(ss); + } + + public static void addRule(StyleSheet ss, AttributeSet attributeSet, AttributeSet defaultAttributes) { + String nameAttr = (String) attributeSet.getAttribute(StyleConstants.NameAttribute); + + String htmlTag = fontConfig2tagMapping.get(nameAttr); + + if (htmlTag == null) { + return; + } + + StringBuilder cssRule = new StringBuilder(); + cssRule.append(htmlTag); + cssRule.append(" {"); // NOI18N + cssRule.append(rgbStyling("color", getThemeColor(attributeSet, defaultAttributes, StyleConstants.ColorConstants.Foreground))); // NOI18N + cssRule.append(rgbStyling("background-color", getThemeColor(attributeSet, defaultAttributes, StyleConstants.ColorConstants.Background))); // NOI18N + cssRule.append(fontSizeStyling(getFontSize(attributeSet))); + cssRule.append(fontStyling("font-family", getFontStyleConfig(attributeSet, StyleConstants.ColorConstants.FontFamily))); + cssRule.append("}"); // NOI18N + ss.addRule(cssRule.toString()); + } + + public static Color getThemeColor(AttributeSet attributeSet, AttributeSet defaultAttributes, Object constant) { + Color color = (Color) attributeSet.getAttribute(constant); + if (color == null && defaultAttributes != null) { + color = (Color) defaultAttributes.getAttribute(constant); + } + return color; + } + + public static int getFontSize(AttributeSet attributeSet) { + Object fontSizeConfig = attributeSet.getAttribute(StyleConstants.ColorConstants.FontSize); + if (fontSizeConfig == null) { + return 0; + } + int fontSize = (int) fontSizeConfig; + return fontSize; + } + + public static String rgbStyling(String property, Color color) { + if (color == null) { + return ""; // NOI18N + } + + StringBuilder cssRule = new StringBuilder(); + cssRule.append(property); + cssRule.append(":rgb("); // NOI18N + cssRule.append(color.getRed()); + cssRule.append(","); // NOI18N + cssRule.append(color.getGreen()); + cssRule.append(","); // NOI18N + cssRule.append(color.getBlue()); + cssRule.append(");"); // NOI18N + return cssRule.toString(); + } + + public static String fontSizeStyling(int size) { + if (size == 0 ) { + return ""; + } + + StringBuilder cssRule = new StringBuilder(); + cssRule.append("font-size:"); // NOI18N + cssRule.append(Integer.toString(size)); + cssRule.append(";"); // NOI18N + return cssRule.toString(); + } + + public static String fontStyling(String property, String value) { + if (value == null) { + return ""; // NOI18N + } + + StringBuilder cssRule = new StringBuilder(); + cssRule.append(property); + cssRule.append(":"); // NOI18N + cssRule.append(value); + cssRule.append(";"); // NOI18N + return cssRule.toString(); + } + + public static String getFontStyleConfig(AttributeSet attributeSet, Object option) { + return (String) attributeSet.getAttribute(option); + } + + private static void appendDefaultMarkdownCssRules(StyleSheet ss) { + String defaultRules = NbBundle.getMessage(StyleUtils.class, "CSS_DEFAULT"); // NOI18N + ss.addRule(defaultRules); + } + + private static Iterator loadCustomizedMarkdownFontAttributes() { + String profile = EditorSettings.getDefault().getCurrentFontColorProfile(); + FontColorSettingsFactory fcsf = EditorSettings.getDefault().getFontColorSettings(new String[]{MIME_TYPE_PREVIEW}); + return fcsf.getAllFontColors(profile).iterator(); + } + + private static AttributeSet loadDefaultNbMarkdownFontAttributes() { + FontColorSettings fcs = (MimeLookup.getLookup(MimePath.get(MIME_TYPE_PREVIEW)).lookup(FontColorSettings.class)); + return fcs.getFontColors("default"); // NOI18N + } + + private static void appendColoringCssRulesFromFontConfigs(StyleSheet ss) { + //contains the default / fallback values of fontConfigs + AttributeSet defaultAttributes = loadDefaultNbMarkdownFontAttributes(); + + //contains the full list of fontConfigs but populated only with custom values + Iterator attributesIt = loadCustomizedMarkdownFontAttributes(); + while (attributesIt.hasNext()) { + AttributeSet attributeSet = attributesIt.next(); + addRule(ss, attributeSet, defaultAttributes); + } + } +}