Buckets:
NaTo1000/termux-app-bucket / termux-shared /src /main /java /com /termux /shared /markdown /MarkdownUtils.java
| package com.termux.shared.markdown; | |
| import android.content.Context; | |
| import android.graphics.Typeface; | |
| import android.text.Spanned; | |
| import android.text.style.AbsoluteSizeSpan; | |
| import android.text.style.BackgroundColorSpan; | |
| import android.text.style.BulletSpan; | |
| import android.text.style.QuoteSpan; | |
| import android.text.style.StrikethroughSpan; | |
| import android.text.style.StyleSpan; | |
| import android.text.style.TypefaceSpan; | |
| import android.text.util.Linkify; | |
| import androidx.annotation.NonNull; | |
| import androidx.core.content.ContextCompat; | |
| import com.google.common.base.Strings; | |
| import com.termux.shared.R; | |
| import com.termux.shared.theme.ThemeUtils; | |
| import org.commonmark.ext.gfm.strikethrough.Strikethrough; | |
| import org.commonmark.node.BlockQuote; | |
| import org.commonmark.node.Code; | |
| import org.commonmark.node.Emphasis; | |
| import org.commonmark.node.FencedCodeBlock; | |
| import org.commonmark.node.ListItem; | |
| import org.commonmark.node.StrongEmphasis; | |
| import java.util.regex.Matcher; | |
| import java.util.regex.Pattern; | |
| import io.noties.markwon.AbstractMarkwonPlugin; | |
| import io.noties.markwon.Markwon; | |
| import io.noties.markwon.MarkwonSpansFactory; | |
| import io.noties.markwon.MarkwonVisitor; | |
| import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; | |
| import io.noties.markwon.linkify.LinkifyPlugin; | |
| public class MarkdownUtils { | |
| public static final String backtick = "`"; | |
| public static final Pattern backticksPattern = Pattern.compile("(" + backtick + "+)"); | |
| /** | |
| * Get the markdown code {@link String} for a {@link String}. This ensures all backticks "`" are | |
| * properly escaped so that markdown does not break. | |
| * | |
| * @param string The {@link String} to convert. | |
| * @param codeBlock If the {@link String} is to be converted to a code block or inline code. | |
| * @return Returns the markdown code {@link String}. | |
| */ | |
| public static String getMarkdownCodeForString(String string, boolean codeBlock) { | |
| if (string == null) return null; | |
| if (string.isEmpty()) return ""; | |
| int maxConsecutiveBackTicksCount = getMaxConsecutiveBackTicksCount(string); | |
| // markdown requires surrounding backticks count to be at least one more than the count | |
| // of consecutive ticks in the string itself | |
| int backticksCountToUse; | |
| if (codeBlock) | |
| backticksCountToUse = maxConsecutiveBackTicksCount + 3; | |
| else | |
| backticksCountToUse = maxConsecutiveBackTicksCount + 1; | |
| // create a string with n backticks where n==backticksCountToUse | |
| String backticksToUse = Strings.repeat(backtick, backticksCountToUse); | |
| if (codeBlock) | |
| return backticksToUse + "\n" + string + "\n" + backticksToUse; | |
| else { | |
| // add a space to any prefixed or suffixed backtick characters | |
| if (string.startsWith(backtick)) | |
| string = " " + string; | |
| if (string.endsWith(backtick)) | |
| string = string + " "; | |
| return backticksToUse + string + backticksToUse; | |
| } | |
| } | |
| /** | |
| * Get the max consecutive backticks "`" in a {@link String}. | |
| * | |
| * @param string The {@link String} to check. | |
| * @return Returns the max consecutive backticks count. | |
| */ | |
| public static int getMaxConsecutiveBackTicksCount(String string) { | |
| if (string == null || string.isEmpty()) return 0; | |
| int maxCount = 0; | |
| int matchCount; | |
| String match; | |
| Matcher matcher = backticksPattern.matcher(string); | |
| while(matcher.find()) { | |
| match = matcher.group(1); | |
| matchCount = match != null ? match.length() : 0; | |
| if (matchCount > maxCount) | |
| maxCount = matchCount; | |
| } | |
| return maxCount; | |
| } | |
| public static String getLiteralSingleLineMarkdownStringEntry(String label, Object object, String def) { | |
| return "**" + label + "**: " + (object != null ? object.toString() : def) + " "; | |
| } | |
| public static String getSingleLineMarkdownStringEntry(String label, Object object, String def) { | |
| if (object != null) | |
| return "**" + label + "**: " + getMarkdownCodeForString(object.toString(), false) + " "; | |
| else | |
| return "**" + label + "**: " + def + " "; | |
| } | |
| public static String getMultiLineMarkdownStringEntry(String label, Object object, String def) { | |
| if (object != null) | |
| return "**" + label + "**:\n" + getMarkdownCodeForString(object.toString(), true) + "\n"; | |
| else | |
| return "**" + label + "**: " + def + "\n"; | |
| } | |
| public static String getLinkMarkdownString(String label, String url) { | |
| if (url != null) | |
| return "[" + label.replaceAll("]", "\\\\]") + "](" + url.replaceAll("\\)", "\\\\)") + ")"; | |
| else | |
| return label; | |
| } | |
| /** Check following for more info: | |
| * https://github.com/noties/Markwon/tree/v4.6.2/app-sample | |
| * https://noties.io/Markwon/docs/v4/recycler/ | |
| * https://github.com/noties/Markwon/blob/v4.6.2/app-sample/src/main/java/io/noties/markwon/app/readme/ReadMeActivity.kt | |
| */ | |
| public static Markwon getRecyclerMarkwonBuilder(Context context) { | |
| return Markwon.builder(context) | |
| .usePlugin(LinkifyPlugin.create(Linkify.EMAIL_ADDRESSES | Linkify.WEB_URLS)) | |
| .usePlugin(new AbstractMarkwonPlugin() { | |
| public void configureVisitor( MarkwonVisitor.Builder builder) { | |
| builder.on(FencedCodeBlock.class, (visitor, fencedCodeBlock) -> { | |
| // we actually won't be applying code spans here, as our custom xml view will | |
| // draw background and apply mono typeface | |
| // | |
| // NB the `trim` operation on literal (as code will have a new line at the end) | |
| final CharSequence code = visitor.configuration() | |
| .syntaxHighlight() | |
| .highlight(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral().trim()); | |
| visitor.builder().append(code); | |
| }); | |
| } | |
| public void configureSpansFactory( MarkwonSpansFactory.Builder builder) { | |
| // Do not change color for night themes | |
| if (!ThemeUtils.isNightModeEnabled(context)) { | |
| builder | |
| // set color for inline code | |
| .setFactory(Code.class, (configuration, props) -> new Object[]{ | |
| new BackgroundColorSpan(ContextCompat.getColor(context, R.color.background_markdown_code_inline)), | |
| }); | |
| } | |
| } | |
| }) | |
| .build(); | |
| } | |
| /** Check following for more info: | |
| * https://github.com/noties/Markwon/tree/v4.6.2/app-sample | |
| * https://github.com/noties/Markwon/blob/v4.6.2/app-sample/src/main/java/io/noties/markwon/app/samples/notification/NotificationSample.java | |
| */ | |
| public static Markwon getSpannedMarkwonBuilder(Context context) { | |
| return Markwon.builder(context) | |
| .usePlugin(StrikethroughPlugin.create()) | |
| .usePlugin(new AbstractMarkwonPlugin() { | |
| public void configureSpansFactory( MarkwonSpansFactory.Builder builder) { | |
| builder | |
| .setFactory(Emphasis.class, (configuration, props) -> new StyleSpan(Typeface.ITALIC)) | |
| .setFactory(StrongEmphasis.class, (configuration, props) -> new StyleSpan(Typeface.BOLD)) | |
| .setFactory(BlockQuote.class, (configuration, props) -> new QuoteSpan()) | |
| .setFactory(Strikethrough.class, (configuration, props) -> new StrikethroughSpan()) | |
| // NB! notification does not handle background color | |
| .setFactory(Code.class, (configuration, props) -> new Object[]{ | |
| new BackgroundColorSpan(ContextCompat.getColor(context, R.color.background_markdown_code_inline)), | |
| new TypefaceSpan("monospace"), | |
| new AbsoluteSizeSpan(48) | |
| }) | |
| // NB! both ordered and bullet list items | |
| .setFactory(ListItem.class, (configuration, props) -> new BulletSpan()); | |
| } | |
| }) | |
| .build(); | |
| } | |
| public static Spanned getSpannedMarkdownText(Context context, String string) { | |
| if (context == null || string == null) return null; | |
| final Markwon markwon = getSpannedMarkwonBuilder(context); | |
| return markwon.toMarkdown(string); | |
| } | |
| } | |
Xet Storage Details
- Size:
- 8.92 kB
- Xet hash:
- ece7bf93c0be8a88b1f47c50b9a41a869328a7ae07d62ed0755b68144d60762d
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.