diff src/name/blackcap/clipman/Troff.kt @ 56:22725d4d7849

An attempt to get it to troff-ize styled text.
author David Barts <n5jrn@me.com>
date Sat, 19 Mar 2022 23:04:40 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/name/blackcap/clipman/Troff.kt	Sat Mar 19 23:04:40 2022 -0700
@@ -0,0 +1,78 @@
+/*
+ * Coercion to troff input.
+ */
+package name.blackcap.clipman
+
+import org.jsoup.Jsoup
+import org.jsoup.nodes.*
+import org.jsoup.select.NodeVisitor
+
+class Troffizer: NodeVisitor {
+    private enum class Typeface(val pos: Int) {
+        ROMAN(1),
+        ITALIC(2),
+        BOLD(3)
+    }
+
+    private val tfStack = mutableListOf<Typeface>(Typeface.ROMAN);
+
+    private val TF_TAGS = mapOf<String, Typeface>(
+        "em" to Typeface.ITALIC,
+        "i" to Typeface.ITALIC,
+        "b" to Typeface.BOLD,
+        "strong" to Typeface.BOLD)
+
+    private val accum = StringBuilder();
+
+    override fun head(node: Node, depth: Int): Unit {
+        when (node) {
+            is TextNode -> accum.append(node.text())
+            is Element -> enterElement(node)
+        }
+    }
+
+    override fun tail(node: Node, depth: Int): Unit {
+        if (node is Element) {
+            leaveElement(node)
+        }
+    }
+
+    private fun enterElement(element: Element) {
+        var newFace = TF_TAGS[element.normalName()]
+        if (newFace != null) {
+            tfStack.add(newFace)
+            accum.append("\\f")
+            accum.append(newFace.pos)
+        }
+    }
+
+    private fun leaveElement(element: Element) {
+        if (element.normalName() in TF_TAGS) {
+            tfStack.removeLast()
+            accum.append("\\f")
+            accum.append(tfStack.lastOrNull()?.pos ?: Typeface.ROMAN.pos)
+        }
+    }
+
+    fun getTroff(): String = accum.toString()
+}
+
+private fun _troffize(html: String): String {
+    val troffizer = Troffizer()
+    Jsoup.parse(html).traverse(troffizer)
+    return troffizer.getTroff()
+}
+
+fun troffize(item: PasteboardItem): Unit {
+    val (plain, html) = when (item) {
+        is PasteboardItem.Plain ->
+            Pair(item.plain, null)
+        is PasteboardItem.HTML ->
+            Pair(item.plain, item.html)
+        is PasteboardItem.RTF ->
+            Pair(item.plain, item.html)
+    }
+    PasteboardItem.write(
+        PasteboardItem.Plain(
+            if (html == null) { plain } else { _troffize(html) }))
+}