<commit_before>package com.fsck.k9.message.html;


import android.text.Editable;
import android.text.Html;
import android.text.Html.TagHandler;
import android.text.Spanned;

import com.fsck.k9.K9;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.xml.sax.XMLReader;

/**
 * Contains common routines to convert html to text and vice versa.
 */
public class HtmlConverter {
    /**
     * When generating previews, Spannable objects that can't be converted into a String are
     * represented as 0xfffc. When displayed, these show up as undisplayed squares. These constants
     * define the object character and the replacement character.
     */
    private static final char PREVIEW_OBJECT_CHARACTER = (char)0xfffc;
    private static final char PREVIEW_OBJECT_REPLACEMENT = (char)0x20;  // space

    /**
     * toHtml() converts non-breaking spaces into the UTF-8 non-breaking space, which doesn't get
     * rendered properly in some clients. Replace it with a simple space.
     */
    private static final char NBSP_CHARACTER = (char)0x00a0;    // utf-8 non-breaking space
    private static final char NBSP_REPLACEMENT = (char)0x20;    // space


    /**
     * Convert an HTML string to a plain text string.
     * @param html HTML string to convert.
     * @return Plain text result.
     */
    public static String htmlToText(final String html) {
        Document document = Jsoup.parse(html);
        return HtmlToPlainText.toPlainText(document.body())
               .replace(PREVIEW_OBJECT_CHARACTER, PREVIEW_OBJECT_REPLACEMENT)
               .replace(NBSP_CHARACTER, NBSP_REPLACEMENT);
    }

    /**
     * Convert a text string into an HTML document.
     *
     * <p>
     * No HTML headers or footers are added to the result.  Headers and footers
     * are added at display time.
     * </p>
     */
    public static String textToHtml(String text) {
        return EmailTextToHtml.convert(text);
    }

    public static String wrapStatusMessage(CharSequence status) {
        return wrapMessageContent("<div style=\"text-align:center; color: grey;\">" + status + "</div>");
    }

    public static String wrapMessageContent(CharSequence messageContent) {
        // Include a meta tag so the WebView will not use a fixed viewport width of 980 px
        return "<html dir=\"auto\"><head><meta name=\"viewport\" content=\"width=device-width\"/>" +
                HtmlConverter.cssStyleTheme() +
                HtmlConverter.cssStylePre() +
                "</head><body>" +
                messageContent +
                "</body></html>";
    }

    static String cssStyleTheme() {
        if (K9.getK9MessageViewTheme() == K9.Theme.DARK)  {
            return "<style type=\"text/css\">" +
                    "* { background: black ! important; color: #F3F3F3 !important }" +
                    ":link, :link * { color: #CCFF33 !important }" +
                    ":visited, :visited * { color: #551A8B !important }</style> ";
        } else {
            return "";
        }
    }

    /**
     * Dynamically generate a CSS style for {@code <pre>} elements.
     *
     *  <p>
     *  The style incorporates the user's current preference
     *  setting for the font family used for plain text messages.
     *  </p>
     *
     * @return
     *      A {@code <style>} element that can be dynamically included in the HTML
     *      {@code <head>} element when messages are displayed.
     */
    static String cssStylePre() {
        final String font = K9.isUseMessageViewFixedWidthFont()
                ? "monospace"
                : "sans-serif";
        return "<style type=\"text/css\"> pre." + EmailTextToHtml.K9MAIL_CSS_CLASS +
                " {white-space: pre-wrap; word-wrap:break-word; " +
                "font-family: " + font + "; margin-top: 0px}</style>";
    }

    /**
     * Convert a plain text string into an HTML fragment.
     */
    public static String textToHtmlFragment(String text) {
        return TextToHtml.toHtmlFragment(text);
    }

    /**
     * Convert HTML to a {@link Spanned} that can be used in a {@link android.widget.TextView}.
     *
     * @param html
     *         The HTML fragment to be converted.
     *
     * @return A {@link Spanned} containing the text in {@code html} formatted using spans.
     */
    public static Spanned htmlToSpanned(String html) {
        return Html.fromHtml(html, null, new ListTagHandler());
    }

    /**
     * {@link TagHandler} that supports unordered lists.
     *
     * @see HtmlConverter#htmlToSpanned(String)
     */
    public static class ListTagHandler implements TagHandler {
        @Override
        public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
            if (tag.equals("ul")) {
                if (opening) {
                    char lastChar = 0;
                    if (output.length() > 0) {
                        lastChar = output.charAt(output.length() - 1);
                    }
                    if (lastChar != '\n') {
                        output.append("\r\n");
                    }
                } else {
                    output.append("\r\n");
                }
            }

            if (tag.equals("li")) {
                if (opening) {
                    output.append("\t•  ");
                } else {
                    output.append("\r\n");
                }
            }
        }
    }
}<commit_msg>Convert 'HtmlConverter' to Kotlin<commit_after>package com.fsck.k9.message.html


import android.text.Editable
import android.text.Html
import android.text.Html.TagHandler
import android.text.Spanned

import com.fsck.k9.K9
import org.jsoup.Jsoup
import org.xml.sax.XMLReader

/**
 * Contains common routines to convert html to text and vice versa.
 */
object HtmlConverter {
    /**
     * When generating previews, Spannable objects that can't be converted into a String are
     * represented as 0xfffc. When displayed, these show up as undisplayed squares. These constants
     * define the object character and the replacement character.
     */
    private const val PREVIEW_OBJECT_CHARACTER = 0xfffc.toChar()
    private const val PREVIEW_OBJECT_REPLACEMENT = 0x20.toChar()  // space

    /**
     * toHtml() converts non-breaking spaces into the UTF-8 non-breaking space, which doesn't get
     * rendered properly in some clients. Replace it with a simple space.
     */
    private const val NBSP_CHARACTER = 0x00a0.toChar()    // utf-8 non-breaking space
    private const val NBSP_REPLACEMENT = 0x20.toChar()    // space


    /**
     * Convert an HTML string to a plain text string.
     */
    @JvmStatic
    fun htmlToText(html: String): String {
        val document = Jsoup.parse(html)
        return HtmlToPlainText.toPlainText(document.body())
                .replace(PREVIEW_OBJECT_CHARACTER, PREVIEW_OBJECT_REPLACEMENT)
                .replace(NBSP_CHARACTER, NBSP_REPLACEMENT)
    }

    /**
     * Convert a text string into an HTML document.
     *
     * No HTML headers or footers are added to the result.  Headers and footers are added at display time.
     */
    @JvmStatic
    fun textToHtml(text: String): String {
        return EmailTextToHtml.convert(text)
    }

    @JvmStatic
    fun wrapStatusMessage(status: CharSequence): String {
        return wrapMessageContent("<div style=\"text-align:center; color: grey;\">$status</div>")
    }

    @JvmStatic
    fun wrapMessageContent(messageContent: CharSequence): String {
        // Include a meta tag so the WebView will not use a fixed viewport width of 980 px
        return "<html dir=\"auto\"><head><meta name=\"viewport\" content=\"width=device-width\"/>" +
                cssStyleTheme() +
                cssStylePre() +
                "</head><body>" +
                messageContent +
                "</body></html>"
    }

    @JvmStatic
    fun cssStyleTheme(): String {
        return if (K9.k9MessageViewTheme === K9.Theme.DARK) {
            "<style type=\"text/css\">" +
                    "* { background: black ! important; color: #F3F3F3 !important }" +
                    ":link, :link * { color: #CCFF33 !important }" +
                    ":visited, :visited * { color: #551A8B !important }</style> "
        } else {
            ""
        }
    }

    /**
     * Dynamically generate a CSS style for `<pre>` elements.
     *
     * The style incorporates the user's current preference setting for the font family used for plain text messages.
     *
     * @return A `<style>` element that can be dynamically included in the HTML `<head>` element when messages are
     * displayed.
     */
    @JvmStatic
    fun cssStylePre(): String {
        val font = if (K9.isUseMessageViewFixedWidthFont) "monospace" else "sans-serif"

        return "<style type=\"text/css\"> pre." + EmailTextToHtml.K9MAIL_CSS_CLASS +
                " {white-space: pre-wrap; word-wrap:break-word; " +
                "font-family: " + font + "; margin-top: 0px}</style>"
    }

    /**
     * Convert a plain text string into an HTML fragment.
     */
    @JvmStatic
    fun textToHtmlFragment(text: String): String {
        return TextToHtml.toHtmlFragment(text)
    }

    /**
     * Convert HTML to a [Spanned] that can be used in a [android.widget.TextView].
     *
     * @param html The HTML fragment to be converted.
     *
     * @return A [Spanned] containing the text in `html` formatted using spans.
     */
    @JvmStatic
    fun htmlToSpanned(html: String): Spanned {
        return Html.fromHtml(html, null, ListTagHandler())
    }

    /**
     * [TagHandler] that supports unordered lists.
     *
     * @see HtmlConverter.htmlToSpanned
     */
    private class ListTagHandler : TagHandler {
        override fun handleTag(opening: Boolean, tag: String, output: Editable, xmlReader: XMLReader) {
            if (tag == "ul") {
                if (opening) {
                    var lastChar: Char = 0.toChar()
                    if (output.length > 0) {
                        lastChar = output[output.length - 1]
                    }
                    if (lastChar != '\n') {
                        output.append("\r\n")
                    }
                } else {
                    output.append("\r\n")
                }
            }

            if (tag == "li") {
                if (opening) {
                    output.append("\t•  ")
                } else {
                    output.append("\r\n")
                }
            }
        }
    }
}
{'fraction_non_alphanumeric': 0.10788224121557455, 'fraction_numerical': 0.007217473884140551, 'mean_word_length': 1.953168816601234, 'pattern_counts': {'":': 4, '<': 39, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7659565', 'n_tokens_mistral': 3073, 'n_tokens_neox': 2905, 'n_words': 852}