1
1
import Markdown
2
2
3
3
extension String {
4
- /// Formats markdown in a way that looks nice on Discord, but still good on GitHub .
4
+ /// Formats markdown in a way that looks decent on both Discord and GitHub at the same time .
5
5
///
6
6
/// If you want to know why something is being done, comment out those lines and run the tests.
7
+ ///
8
+ /// Or, better yet, nag the code author to add more comments to things that are complicated and confusing.
7
9
func formatMarkdown(
8
10
maxVisualLength: Int ,
9
11
hardLimit: Int ,
10
12
trailingTextMinLength: Int
11
13
) -> String {
12
- assert ( maxVisualLength > 0 , " Can't request a non-positive maximum ." )
13
- assert ( hardLimit > 0 , " Can't use a non-positive maximum ." )
14
+ assert ( maxVisualLength > 0 , " Maximum visual length must be greater than zero (got \( maxVisualLength ) ) ." )
15
+ assert ( hardLimit > 0 , " Hard length limit must be greater than zero (got \( hardLimit ) ) ." )
14
16
assert ( hardLimit >= maxVisualLength, " maxVisualLength ' \( maxVisualLength) ' can't be more than hardLimit ' \( hardLimit) '. " )
15
17
18
+ /// Remove all HTML elements and all links lacking a destination; they don't look good in Discord.
16
19
let document1 = Document ( parsing: self )
17
20
var htmlRemover = HTMLAndImageRemover ( )
18
21
guard let markup1 = htmlRemover. visit ( document1) else { return " " }
19
22
var emptyLinksRemover = EmptyLinksRemover ( )
20
23
guard var markup2 = emptyLinksRemover. visit ( markup1) else { return " " }
21
24
25
+ var didRemoveMarkdownElement = false
22
26
var ( remaining, prefixed) = markup2
23
27
. format ( options: . default)
24
28
. trimmingForMarkdown ( )
25
29
. markdownUnicodesPrefix ( maxVisualLength)
30
+
31
+ /// Remove the last paragraph if it's too small to be useful.
26
32
if remaining == 0 {
27
33
let document2 = Document ( parsing: prefixed)
28
34
var paragraphCounter = ParagraphCounter ( )
29
35
paragraphCounter. visit ( document2)
30
36
let paragraphCount = paragraphCounter. count
31
- if ! [ 0 , 1 ] . contains ( paragraphCount ) {
37
+ if paragraphCount > 1 {
32
38
var paragraphRemover = ParagraphRemover (
33
39
atCount: paragraphCount,
34
40
ifShorterThan: trailingTextMinLength
35
41
)
36
42
if let markup = paragraphRemover. visit ( document2) {
43
+ /// the `||` doesn't do anything as of now, but it might prevent some headache
44
+ /// if someone changes something in the code in the future.
45
+ didRemoveMarkdownElement = didRemoveMarkdownElement || paragraphRemover. didModify
37
46
markup2 = markup
38
47
/// Update `prefixed`
39
48
prefixed = markup2
@@ -44,16 +53,23 @@ extension String {
44
53
}
45
54
}
46
55
56
+ /// If the final block element is a heading, remove it (cosmetics again)
47
57
var document3 = Document ( parsing: prefixed)
48
- if let last = Array ( document3. blockChildren) . last ,
58
+ if let last = document3. blockChildren. suffix ( 1 ) . first ,
49
59
last is Heading {
60
+ didRemoveMarkdownElement = true
50
61
document3 = Document ( document3. blockChildren. dropLast ( ) )
51
62
prefixed = document3
52
63
. format ( options: . default)
53
64
. trimmingForMarkdown ( )
54
65
. markdownUnicodesPrefix ( maxVisualLength)
55
66
}
56
67
68
+ if didRemoveMarkdownElement {
69
+ /// Append a new line + dots at the end to suggest that the text has not ended.
70
+ prefixed += " \n \u{2026} "
71
+ }
72
+
57
73
return prefixed. unicodesPrefix ( hardLimit)
58
74
}
59
75
@@ -148,6 +164,7 @@ private struct ParagraphRemover: MarkupRewriter {
148
164
let atCount : Int
149
165
let ifShorterThan : Int
150
166
var count = 0
167
+ var didModify = false
151
168
152
169
init ( atCount: Int , ifShorterThan: Int ) {
153
170
self . atCount = atCount
@@ -161,6 +178,7 @@ private struct ParagraphRemover: MarkupRewriter {
161
178
var lengthCounter = MarkupLengthCounter ( )
162
179
lengthCounter. visit ( paragraph)
163
180
if lengthCounter. length < ifShorterThan {
181
+ self . didModify = true
164
182
return nil
165
183
} else {
166
184
return paragraph
0 commit comments