Skip to content

Commit 4e46f7d

Browse files
authored
More dots when markdown text is truncated (#158)
* more dots when markdown text is truncated * document better * disable some flags so nightly tests succeed
1 parent eb9a571 commit 4e46f7d

File tree

3 files changed

+32
-10
lines changed

3 files changed

+32
-10
lines changed

Lambdas/GHHooks/Extensions/String+Document.swift

+23-5
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,48 @@
11
import Markdown
22

33
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.
55
///
66
/// 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.
79
func formatMarkdown(
810
maxVisualLength: Int,
911
hardLimit: Int,
1012
trailingTextMinLength: Int
1113
) -> 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)).")
1416
assert(hardLimit >= maxVisualLength, "maxVisualLength '\(maxVisualLength)' can't be more than hardLimit '\(hardLimit)'.")
1517

18+
/// Remove all HTML elements and all links lacking a destination; they don't look good in Discord.
1619
let document1 = Document(parsing: self)
1720
var htmlRemover = HTMLAndImageRemover()
1821
guard let markup1 = htmlRemover.visit(document1) else { return "" }
1922
var emptyLinksRemover = EmptyLinksRemover()
2023
guard var markup2 = emptyLinksRemover.visit(markup1) else { return "" }
2124

25+
var didRemoveMarkdownElement = false
2226
var (remaining, prefixed) = markup2
2327
.format(options: .default)
2428
.trimmingForMarkdown()
2529
.markdownUnicodesPrefix(maxVisualLength)
30+
31+
/// Remove the last paragraph if it's too small to be useful.
2632
if remaining == 0 {
2733
let document2 = Document(parsing: prefixed)
2834
var paragraphCounter = ParagraphCounter()
2935
paragraphCounter.visit(document2)
3036
let paragraphCount = paragraphCounter.count
31-
if ![0, 1].contains(paragraphCount) {
37+
if paragraphCount > 1 {
3238
var paragraphRemover = ParagraphRemover(
3339
atCount: paragraphCount,
3440
ifShorterThan: trailingTextMinLength
3541
)
3642
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
3746
markup2 = markup
3847
/// Update `prefixed`
3948
prefixed = markup2
@@ -44,16 +53,23 @@ extension String {
4453
}
4554
}
4655

56+
/// If the final block element is a heading, remove it (cosmetics again)
4757
var document3 = Document(parsing: prefixed)
48-
if let last = Array(document3.blockChildren).last,
58+
if let last = document3.blockChildren.suffix(1).first,
4959
last is Heading {
60+
didRemoveMarkdownElement = true
5061
document3 = Document(document3.blockChildren.dropLast())
5162
prefixed = document3
5263
.format(options: .default)
5364
.trimmingForMarkdown()
5465
.markdownUnicodesPrefix(maxVisualLength)
5566
}
5667

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+
5773
return prefixed.unicodesPrefix(hardLimit)
5874
}
5975

@@ -148,6 +164,7 @@ private struct ParagraphRemover: MarkupRewriter {
148164
let atCount: Int
149165
let ifShorterThan: Int
150166
var count = 0
167+
var didModify = false
151168

152169
init(atCount: Int, ifShorterThan: Int) {
153170
self.atCount = atCount
@@ -161,6 +178,7 @@ private struct ParagraphRemover: MarkupRewriter {
161178
var lengthCounter = MarkupLengthCounter()
162179
lengthCounter.visit(paragraph)
163180
if lengthCounter.length < ifShorterThan {
181+
self.didModify = true
164182
return nil
165183
} else {
166184
return paragraph

Package.swift

+5-4
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,22 @@ let upcomingFeaturesSwiftSettings: [SwiftSetting] = [
3131
/// Objc, which we don't use.
3232
.enableUpcomingFeature("ImportObjcForwardDeclarations"),
3333

34+
/// These currently cause errors on nightlies sometimes. We'll reenable them later:
35+
3436
/// https://github.com/apple/swift-evolution/blob/main/proposals/0409-access-level-on-imports.md
35-
/// Currently causes errors on nightlies. We'll reenable it later.
3637
/// .enableUpcomingFeature("InternalImportsByDefault"),
3738

3839
/// https://github.com/apple/swift-evolution/blob/main/proposals/0411-isolated-default-values.md
3940
/// Data-race-free initial values for stored properties.
40-
.enableUpcomingFeature("IsolatedDefaultValues"),
41+
/// .enableUpcomingFeature("IsolatedDefaultValues"),
4142

4243
/// https://github.com/apple/swift-evolution/blob/main/proposals/0412-strict-concurrency-for-global-variables.md
4344
/// Enable automatic safety features for global (and some local) variables.
44-
.enableUpcomingFeature("GlobalConcurrency"),
45+
/// .enableUpcomingFeature("GlobalConcurrency"),
4546

4647
/// https://github.com/apple/swift-evolution/blob/main/proposals/0413-typed-throws.md
4748
/// Enable the full potential of typed throws.
48-
.enableUpcomingFeature("FullTypedThrows")
49+
/// .enableUpcomingFeature("FullTypedThrows")
4950
]
5051

5152
let targetsSwiftSettings: [SwiftSetting] = upcomingFeaturesSwiftSettings + [

Tests/PennyTests/GHHooksTests.swift

+4-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ class GHHooksTests: XCTestCase {
287287
hardLimit: 2_048,
288288
trailingTextMinLength: 64
289289
)
290-
XCTAssertMultilineStringsEqual(formatted, scalars_206)
290+
XCTAssertMultilineStringsEqual(formatted, scalars_206 + "\n\(dots)")
291291
}
292292

293293
/// Remove html and images + length limits.
@@ -405,6 +405,7 @@ class GHHooksTests: XCTestCase {
405405
Bumps [sass](https://github.com/sass/dart-sass) from 1.63.6 to 1.64.0.
406406
407407
Dependabot will resolve any conflicts with this PR as long as you don’t alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
408+
\(dots)
408409
""")
409410
}
410411

@@ -436,6 +437,7 @@ class GHHooksTests: XCTestCase {
436437
### To Reproduce
437438
438439
1.
440+
\(dots)
439441
""")
440442
}
441443

@@ -478,6 +480,7 @@ class GHHooksTests: XCTestCase {
478480
### Expected behavior
479481
480482
Expect some contrast between the text and the background.
483+
\(dots)
481484
""")
482485
}
483486

0 commit comments

Comments
 (0)