comparison src/main/kotlin/name/blackcap/passman/See.kt @ 3:eafa3779aef8

More bug fixes, quote strings in diagnostics.
author David Barts <n5jrn@me.com>
date Sun, 11 Sep 2022 20:36:06 -0700
parents a6cfdffcaa94
children 02b101422726
comparison
equal deleted inserted replaced
2:3c792ad36b3d 3:eafa3779aef8
1 package name.blackcap.passman 1 package name.blackcap.passman
2
3 /* Would be nice if there was a more programmatic and comprehensive way of
4 doing this, but alas. Even the oft-recommended StringEscapeUtils does
5 something cruder than the below. Le sigh. */
2 6
3 import java.util.Formatter 7 import java.util.Formatter
4 8
5 private val UNPRINTABLE = setOf<Character.UnicodeBlock>( 9 private const val DELIM = '"'
6 Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS,
7 Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS_EXTENDED,
8 Character.UnicodeBlock.COMBINING_HALF_MARKS,
9 Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS_SUPPLEMENT,
10 Character.UnicodeBlock.COMBINING_MARKS_FOR_SYMBOLS,
11 Character.UnicodeBlock.HIGH_PRIVATE_USE_SURROGATES,
12 Character.UnicodeBlock.HIGH_SURROGATES,
13 Character.UnicodeBlock.LOW_SURROGATES,
14 Character.UnicodeBlock.PRIVATE_USE_AREA,
15 Character.UnicodeBlock.SPECIALS,
16 10
17 ) 11 private val STD_ESC_MAP = mapOf<Char, Char>('\t' to 't', '\b' to 'b', '\n' to 'n',
12 '\r' to 'r', '\u000c' to 'f', '\"' to '"', '\\' to '\\')
13 private const val MIN_ASCII = ' '
14 private const val MAX_ASCII = '~'
15 private const val MIN_8859 = '\u00a1'
16 private const val MAX_8859 = '\u00ff'
17 private const val SHY = '\u00ad'
18 18
19 private val DELIM = '"' 19 fun see(input: String, simple: Boolean = false): String =
20 if (simple) seeSimple(input) else seeAggressive(input)
20 21
21 private val EXEMPT = setOf<Char>(' ') 22 private fun seeSimple(input: String): String = StringBuilder().run {
22 private val PREFIXED = setOf<Char>(DELIM, '\\') 23 append(DELIM)
24 append(input)
25 append(DELIM)
26 toString()
27 }
23 28
24 fun see(input: String): String { 29 private fun seeAggressive(input: String): String {
25 val accum = StringBuilder() 30 val accum = Formatter()
26 val formatter = Formatter(accum) 31 accum.format("%c", DELIM)
27 accum.append(DELIM)
28 for (ch in input) { 32 for (ch in input) {
29 val block = Character.UnicodeBlock.of(ch) 33 if ((ch in MIN_ASCII..MAX_ASCII) || ((ch != SHY) && (ch in MIN_8859 .. MAX_8859))) {
30 if (ch in EXEMPT) { 34 accum.format("%c", ch)
31 accum.append(ch) 35 continue
32 } else if (block == null || block in UNPRINTABLE || Character.isSpaceChar(ch) || Character.isWhitespace(ch)) { 36 }
33 formatter.format("\\u%04x", ch.code) 37 val mapped = STD_ESC_MAP[ch]
34 } else if (ch in PREFIXED) { 38 if (mapped != null) {
35 accum.append('\\') 39 accum.format("\\%c", mapped)
36 accum.append(ch)
37 } else { 40 } else {
38 accum.append(ch) 41 accum.format("\\u%04x", ch.code)
39 } 42 }
40 } 43 }
41 accum.append(DELIM) 44 accum.format("%c", DELIM)
42 return accum.toString() 45 return accum.toString()
43 } 46 }
44
45 fun dump(input: String): String {
46 val accum = StringBuilder()
47 var needSpace = false
48 for (ch in input) {
49 if (needSpace) {
50 accum.append(' ')
51 }
52 accum.append(ch.code)
53 needSpace = true
54 }
55 return accum.toString()
56 }