view 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 source

/*
 * 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) }))
}