Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Use insertion-order list for ligatures

AuthorDaveJarvis <email>
Date2020-08-22 20:35:52 GMT-0700
Commitea027df7b01249483d1837c98da9630c895359cc
Parentfd689a2
src/main/java/com/scrivenvar/processors/markdown/LigatureExtension.java
import com.vladsch.flexmark.ast.Text;
-import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.html.HtmlWriter;
import com.vladsch.flexmark.html.renderer.NodeRenderer;
import com.vladsch.flexmark.html.renderer.NodeRendererContext;
import com.vladsch.flexmark.html.renderer.NodeRendererFactory;
import com.vladsch.flexmark.html.renderer.NodeRenderingHandler;
-import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.ast.TextCollectingVisitor;
import com.vladsch.flexmark.util.data.DataHolder;
import com.vladsch.flexmark.util.data.MutableDataHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import static com.scrivenvar.processors.text.TextReplacementFactory.replace;
+import static com.vladsch.flexmark.html.HtmlRenderer.Builder;
+import static com.vladsch.flexmark.html.HtmlRenderer.HtmlRendererExtension;
/**
* Responsible for substituting multi-codepoint glyphs with single codepoint
* glyphs. The text is adorned with ligatures prior to rendering as HTML.
* This requires a font that supports ligatures.
* <p>
* TODO: I18N https://github.com/DaveJarvis/scrivenvar/issues/81
* </p>
*/
-public class LigatureExtension
- implements HtmlRenderer.HtmlRendererExtension {
- private final static Map<String, String> LIGATURES_SHORT = Map.of(
+public class LigatureExtension implements HtmlRendererExtension {
+ /**
+ * Retain insertion order so that ligature substitution uses longer ligatures
+ * ahead of shorter ligatures. The word "ruffian" should use the "ffi"
+ * ligature, not the "ff" ligature.
+ */
+ private final static Map<String, String> LIGATURES = new LinkedHashMap<>();
+
+ static {
+ LIGATURES.put( "ffi", "\uFB03" );
+ LIGATURES.put( "ffl", "\uFB04" );
+ LIGATURES.put( "ff", "\uFB00" );
+ LIGATURES.put( "fi", "\uFB01" );
+ LIGATURES.put( "fl", "\uFB02" );
+ LIGATURES.put( "ft", "\uFB05" );
+ LIGATURES.put( "AE", "\u00C6" );
+ LIGATURES.put( "OE", "\u0152" );
// "ae", "\u00E6",
// "oe", "\u0153",
- "AE", "\u00C6",
- "OE", "\u0152",
- "ff", "\uFB00",
- "fi", "\uFB01",
- "fl", "\uFB02",
- "ft", "\uFB05"
- );
-
- private final static Map<String, String> LIGATURES_LONG = Map.of(
- "ffi", "\uFB03",
- "ffl", "\uFB04"
- );
+ }
private static class LigatureRenderer implements NodeRenderer {
-
private final TextCollectingVisitor mVisitor = new TextCollectingVisitor();
}
- private <N extends Node> void render(
- @NotNull final N n,
- @NotNull final NodeRendererContext nodeRendererContext,
+ /**
+ * This will pick the fastest string replacement algorithm based on the
+ * text length. The insertion order of the {@link #LIGATURES} is
+ * important to give precedence to longer ligatures.
+ *
+ * @param textNode The text node containing text to replace with ligatures.
+ * @param context Not used.
+ * @param html Where to write the text adorned with ligatures.
+ */
+ private void render(
+ @NotNull final Text textNode,
+ @NotNull final NodeRendererContext context,
@NotNull final HtmlWriter html ) {
- final var text = mVisitor.collectAndGetText( n );
- html.text( replace( replace( text, LIGATURES_LONG ), LIGATURES_SHORT ) );
+ final var text = mVisitor.collectAndGetText( textNode );
+ html.text( replace( text, LIGATURES ) );
}
}
- public static class Factory implements NodeRendererFactory {
+ private static class Factory implements NodeRendererFactory {
@NotNull
@Override
@Override
- public void extend( @NotNull final HtmlRenderer.Builder builder,
+ public void extend( @NotNull final Builder builder,
@NotNull final String rendererType ) {
if( "HTML".equalsIgnoreCase( rendererType ) ) {
Delta37 lines added, 25 lines removed, 12-line increase