๐พ Archived View for oppen.digital โบ memex โบ 20211105 captured on 2021-12-04 at 18:04:22. Gemini links have been rewritten to link to archived content
โฌ ๏ธ Previous capture (2021-11-30)
-=-=-=-=-=-=-
I recently became aware of the idea to inline bold text in Gemtext using the MATHEMATICAL_ALPHANUMERIC_SYMBOLS unicode block, I'd seen people doing this on Twitter before of course but this was positioned specifically to get around the lack of inline tags in Gemtext.
I was initally against this from a screen reader accessibility standpoint but Android's TalkBack remaps them to standard characters and reads them without issue.
Users can install any screen reader they like on Android, we can't assume everyone uses TalkBack and not all will have had the resources of Google to develop their software to the point that includes handling these misused blocks (it has been suggested elsewhere (unkindly) that these developers don't understand Unicode, whereas it's merely a question of prioritising other things and time being linear). A further point is legibility for people who have any number of sight issues.
I personally find these characters really irritating, so am going to add a feature to remap them in Ariane. There's a small subset of the available characters below while I test remapping to standard characters using a feature toggle:
They are ๐๐๐๐๐๐ annoying.
๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐
Code block:
๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐
private fun remapBoldUnicode(line: String): String { val unicodeMapper = UnicodeMathematicalSymbolsMapper() val unescaped = StringEscapeUtils.unescapeJava(line) val hasBoldUnicode = unicodeMapper.hasMathematicalAlphanumericSymbols(unescaped) return when { hasBoldUnicode -> unicodeMapper.remap(unescaped) else -> line } }
UnicodeMathematicalSymbolsMapper.kt:
package oppen.gemini.gemtext.processor /** * This class maps characters from the Mathematical Alphanumeric Symbols unicode block to standard A-Z a-z * * @see https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols */ class UnicodeMathematicalSymbolsMapper { private val standard = listOf( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z') private val highSurrogateCode = 55349 //Serif Bold: ๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ private val serifBoldRange = IntRange(56320, 56371) //Serif Italic: ๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป๐ผ๐ฝ๐พ๐ฟ๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐โ๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง private val serifItalicRange = IntRange(56372, 56423) //Serif Italic Bold: ๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป๐ผ๐ฝ๐พ๐ฟ๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ private val serifItalicBoldRange = IntRange(56424, 56475) //Sans Serif Normal: ๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป๐ผ๐ฝ๐พ๐ฟ๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐ private val sansNormalRange = IntRange(56736, 56787) //Sans Serif Bold: ๐๐๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป๐ผ๐ฝ๐พ๐ฟ๐๐๐๐๐๐ ๐๐ private val sansBoldRange = IntRange(56788, 56839) //Sans Serif Italic //๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป private val sansItalicRange = IntRange(56840, 56891) //Sans Serif Italic Bold: ๐ผ๐ฝ๐พ๐ฟ๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ private val sansItalicBoldRange = IntRange(56892, 56943) //Calligraphy Normal: ๐โฌ๐๐โฐโฑ๐ขโโ๐ฅ๐ฆโโณ๐ฉ๐ช๐ซ๐ฌโ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐นโฏ๐ปโ๐ฝ๐พ๐ฟ๐๐๐๐โด๐ ๐๐๐๐๐๐๐๐๐๐ private val calligraphyNormalRange = IntRange(56476, 56527) //Calligraphy Bold: ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป๐ผ๐ฝ๐พ๐ฟ๐๐๐๐ private val calligraphyBoldRange = IntRange(56528, 56579) //Fraktur Normal: ๐๐ โญ๐๐๐๐โโ๐๐๐๐๐๐๐๐โ๐๐๐๐๐๐๐โจ๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท private val frakturNormalRange = IntRange(56580, 56631) //Fraktur Bold: ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป๐ผ๐ฝ๐พ๐ฟ๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ private val frakturBoldRange = IntRange(56684, 56735) //Monospace: ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป๐ผ๐ฝ๐พ๐ฟ๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ private val monospaceRange = IntRange(56944, 56995) //Double Struck: ๐ธ๐นโ๐ป๐ผ๐ฝ๐พโ๐๐๐๐๐โ๐โโโ๐๐๐๐๐๐๐โค๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ private val doubleStruckRange = IntRange(56632, 56683) fun hasMathematicalAlphanumericSymbols(text: String): Boolean = text.codePoints().anyMatch { codePoint -> Character.UnicodeBlock.of(codePoint) == Character.UnicodeBlock.MATHEMATICAL_ALPHANUMERIC_SYMBOLS } fun remap(text: String): String { val remappedChars = mutableListOf<Char>() var highSurrogateCode = -1 text.chars().forEach { code -> var char = Character.valueOf(Char(code)) val isSurrogate = char.isSurrogate() when { isSurrogate -> { when { char.isHighSurrogate() -> highSurrogateCode = code char.isLowSurrogate() -> { if (highSurrogateCode == this.highSurrogateCode) { when { serifBoldRange.contains(code) -> char = standard[code - serifBoldRange.first] serifItalicRange.contains(code) -> char = standard[code - serifItalicRange.first] serifItalicBoldRange.contains(code) -> char = standard[code - serifItalicBoldRange.first] sansNormalRange.contains(code) -> char = standard[code - sansNormalRange.first] sansBoldRange.contains(code) -> char = standard[code - sansBoldRange.first] sansItalicRange.contains(code) -> char = standard[code - sansItalicRange.first] sansItalicBoldRange.contains(code) -> char = standard[code - sansItalicBoldRange.first] calligraphyNormalRange.contains(code) -> char = standard[code - calligraphyNormalRange.first] calligraphyBoldRange.contains(code) -> char = standard[code - calligraphyBoldRange.first] frakturNormalRange.contains(code) -> char = standard[code - frakturNormalRange.first] frakturBoldRange.contains(code) -> char = standard[code - frakturBoldRange.first] monospaceRange.contains(code) -> char = standard[code - monospaceRange.first] doubleStruckRange.contains(code) -> char = standard[code - doubleStruckRange.first] } } remappedChars.add(char) } } } else -> { remappedChars.add(char) } } } return String(remappedChars.toCharArray()) } }