@@ -13,47 +13,32 @@ import java.util.*
13
13
*/
14
14
object CodeHighlighter {
15
15
16
- private val LT_BRACE = " <" .toRegex()
17
- private const val LT_REGULAR = " <"
18
- private const val LT_TMP = " ^"
19
-
20
- private val parser = PrettifyParser ()
21
-
22
16
/* *
23
17
* Highlight code content.
24
18
*
25
- * @param codeLanguage Programming language
26
- * @param rawSource Code source by one string
27
- * @param colorTheme Color theme (see below)
19
+ * @param language Programming language
20
+ * @param source Source code as single string
21
+ * @param theme Color theme (see below)
28
22
* @return Highlighted code, string with necessary inserted color tags
29
23
*/
30
- fun highlight (codeLanguage : String , rawSource : String , colorTheme : ColorThemeData ): String {
31
- val source = rawSource.escapeLT()
32
- val results = parser.parse(codeLanguage, source)
33
- val colorsMap = buildColorsMap(colorTheme)
34
- val highlighted = StringBuilder ()
35
-
36
- results.forEach {
37
- val color = colorsMap.getColor(it)
38
- val content = parseContent(source, it)
39
- highlighted.append(content.withFontParams(color))
40
- }
41
- return highlighted.toString()
24
+ fun highlight (language : String , source : String , theme : ColorThemeData ): String {
25
+ val colors = buildColorsMap(theme)
26
+
27
+ return PrettifyParser ().parse(language, source)
28
+ .map { source highlight it applyFontParams colors[it] }
29
+ .reduce(String ::plus)
42
30
}
43
31
44
32
// - Helpers
45
33
46
34
/* *
47
- * Parse user input by extracting highlighted content.
35
+ * Parse input by extracting highlighted content.
48
36
*
49
- * @param codeContent Code content
50
37
* @param result Syntax unit
51
- * @return Parsed content to highlight
38
+ * @return Content to highlight
52
39
*/
53
- private fun parseContent (codeContent : String , result : ParseResult ): String {
54
- val length = result.offset + result.length
55
- val content = codeContent.substring(result.offset, length)
56
- return content.expandLT()
40
+ private infix fun String.highlight (result : ParseResult ) = safeLT {
41
+ substring(result.offset, result.offset + result.length)
57
42
}
58
43
59
44
/* *
@@ -62,7 +47,7 @@ object CodeHighlighter {
62
47
* @param result Syntax unit
63
48
* @return Color for syntax unit
64
49
*/
65
- private fun HashMap <String , String >.getColor (result : ParseResult ) =
50
+ private operator fun HashMap <String , String >.get (result : ParseResult ) =
66
51
this [result.styleKeys[0 ]] ? : this [" pln" ]
67
52
68
53
/* *
@@ -71,31 +56,30 @@ object CodeHighlighter {
71
56
* @param colorTheme Color theme
72
57
* @return Colors map built from color theme
73
58
*/
74
- private fun buildColorsMap (colorTheme : ColorThemeData ) =
75
- object : HashMap <String , String >() {
76
- init {
77
- val syntaxColors = colorTheme.syntaxColors
78
-
79
- put(" typ" , syntaxColors.type.hex())
80
- put(" kwd" , syntaxColors.keyword.hex())
81
- put(" lit" , syntaxColors.literal.hex())
82
- put(" com" , syntaxColors.comment.hex())
83
- put(" str" , syntaxColors.string.hex())
84
- put(" pun" , syntaxColors.punctuation.hex())
85
- put(" pln" , syntaxColors.plain.hex())
86
- put(" tag" , syntaxColors.tag.hex())
87
- put(" dec" , syntaxColors.declaration.hex())
88
- put(" src" , syntaxColors.plain.hex())
89
- put(" atn" , syntaxColors.attrName.hex())
90
- put(" atv" , syntaxColors.attrValue.hex())
91
- put(" nocode" , syntaxColors.plain.hex())
92
- }
93
- }
94
-
95
- // - Escaping/extracting "lower then" symbol
96
-
97
- private fun String.escapeLT () = replace(LT_BRACE , LT_TMP )
98
- private fun String.expandLT () = replace(LT_TMP , LT_REGULAR )
59
+ private fun buildColorsMap (theme : ColorThemeData ): HashMap <String , String > {
60
+ fun color (body : SyntaxColors .() -> Int ) =
61
+ theme.syntaxColors.let { body(it).hex() }
62
+ return hashMapOf(
63
+ " typ" to color { type },
64
+ " kwd" to color { keyword },
65
+ " lit" to color { literal },
66
+ " com" to color { comment },
67
+ " str" to color { string },
68
+ " pun" to color { punctuation },
69
+ " pln" to color { plain },
70
+ " tag" to color { tag },
71
+ " dec" to color { declaration },
72
+ " src" to color { plain },
73
+ " atn" to color { attrName },
74
+ " atv" to color { attrValue },
75
+ " nocode" to color { plain })
76
+ }
77
+
78
+ // - Escaping/extracting "less then" symbol
79
+
80
+ private fun String.safeLT (op : String .() -> String ) = escapeLT().op().expandLT()
81
+ private fun String.escapeLT () = replace(" <" , " ^" )
82
+ private fun String.expandLT () = replace(" ^" , " <" )
99
83
}
100
84
101
85
/* *
@@ -222,8 +206,6 @@ enum class Font {
222
206
223
207
// - Helpers
224
208
225
- const val transparent = " #00000000"
226
-
227
209
/* *
228
210
* @return Converted hex int to color by adding alpha-channel
229
211
*/
@@ -242,50 +224,47 @@ fun Int.hex() = "#${Integer.toHexString(this)}"
242
224
* @return Is value equals to found or not condition
243
225
*/
244
226
fun Int.isFound () = this >= 0
245
-
246
227
fun Int.notFound () = this == - 1
247
228
248
229
/* *
249
230
* Apply font params to string.
250
231
*
251
- * @param color Color as formatter string
252
- * @return Formatted string
232
+ * @param color Color
233
+ * @return Parametrized string
253
234
*/
254
- fun String.withFontParams (color : String? ): String {
255
- val parametrizedString = StringBuilder ()
256
-
235
+ infix fun String.applyFontParams (color : String? ): String {
236
+ var parametrizedString = " "
257
237
var idx = 0
258
238
var newIdx = indexOf(" \n " )
259
239
260
240
if (newIdx.notFound()) // covers expected tag coverage (within only one line)
261
- parametrizedString.append( inFontTag(color) )
241
+ parametrizedString + = inFontTag(color)
262
242
else { // may contain multiple lines with line breaks
263
243
264
244
// put tag on the borders (end & start of line, ..., end of tag)
265
245
do { // until closing tag is reached
266
- val part = substring(idx .. newIdx - 1 ).inFontTag(color).plus(" \n " )
267
- parametrizedString.append(part)
246
+ parametrizedString + = (substring(idx .. newIdx - 1 ) inFontTag color) + " \n "
268
247
269
248
idx = newIdx + 1
270
249
newIdx = indexOf(" \n " , idx)
271
250
} while (newIdx.isFound())
272
251
273
252
if (idx != indexOf(" \n " )) // if not replaced only once (for multiline tag coverage)
274
- parametrizedString.append( substring(idx). inFontTag( color))
253
+ parametrizedString + = substring(idx) inFontTag color
275
254
}
276
- return parametrizedString.toString()
255
+ return parametrizedString
277
256
}
278
257
258
+ /* *
259
+ * @return String wrapped in font tag
260
+ */
261
+ private infix fun String.inFontTag (color : String? ) =
262
+ " <font color=\" $color \" >${escLineBreakAtStart()} </font>"
263
+
279
264
/* *
280
265
* @return String with escaped line break at start
281
266
*/
282
267
fun String.escLineBreakAtStart () =
283
268
if (startsWith(" \n " ) && length >= 1 )
284
269
substring(1 )
285
270
else this
286
-
287
- /* *
288
- * @return String surrounded by font tag
289
- */
290
- fun String.inFontTag (color : String? ) =
291
- " <font color=\" $color \" >${escLineBreakAtStart()} </font>"
0 commit comments