Skip to content

Commit 8fd8c6e

Browse files
committed
fix: strip trailing whitespace from sent messages
1 parent 1761bf1 commit 8fd8c6e

1 file changed

Lines changed: 43 additions & 28 deletions

File tree

src/lib/components/common/RichTextInput.svelte

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@
3737
});
3838
turndownService.escape = (string) => string;
3939
40+
// Turndown serializes each <br> as a Markdown " \n" hard break, leaving
41+
// invisible trailing spaces at line breaks and on blank lines. Strip that
42+
// trailing whitespace, except inside fenced code blocks where it can be significant.
43+
const stripTrailingWhitespace = (md: string): string =>
44+
md
45+
.split(/(```[\s\S]*?```|~~~[\s\S]*?~~~)/g)
46+
.map((part, i) => (i % 2 ? part : part.replace(/[ \t]+$/gm, '')))
47+
.join('');
48+
4049
// Produce single newlines between paragraphs instead of double.
4150
// TipTap wraps every line in <p> tags; the default Turndown rule emits
4251
// \n\n around each paragraph which then required a destructive
@@ -711,7 +720,7 @@
711720
try {
712721
// Try parsing the value
713722
return marked.parse(value.replaceAll(`\n<br/>`, `<br/>`), {
714-
breaks: false
723+
breaks: true
715724
});
716725
} catch (error) {
717726
// If no attempts remain, fallback to plain text
@@ -885,26 +894,30 @@
885894
jsonValue = editor.getJSON();
886895
887896
if (richText) {
888-
mdValue = turndownService
889-
.turndown(
890-
htmlValue
891-
.replace(/<p><\/p>/g, '<br/>')
892-
.replace(/ {2,}/g, (m) => m.replace(/ /g, '\u00a0'))
893-
)
894-
.replace(/\u00a0/g, ' ');
897+
mdValue = stripTrailingWhitespace(
898+
turndownService
899+
.turndown(
900+
htmlValue
901+
.replace(/<p><\/p>/g, '<br/>')
902+
.replace(/ {2,}/g, (m) => m.replace(/ /g, '\u00a0'))
903+
)
904+
.replace(/\u00a0/g, ' ')
905+
);
895906
} else {
896-
mdValue = turndownService
897-
.turndown(
898-
htmlValue
899-
// Replace empty paragraphs with line breaks
900-
.replace(/<p><\/p>/g, '<br/>')
901-
// Replace multiple spaces with non-breaking spaces
902-
.replace(/ {2,}/g, (m) => m.replace(/ /g, '\u00a0'))
903-
// Replace tabs with non-breaking spaces (preserve indentation)
904-
.replace(/\t/g, '\u00a0\u00a0\u00a0\u00a0') // 1 tab = 4 spaces
905-
)
906-
// Convert non-breaking spaces back to regular spaces for markdown
907-
.replace(/\u00a0/g, ' ');
907+
mdValue = stripTrailingWhitespace(
908+
turndownService
909+
.turndown(
910+
htmlValue
911+
// Replace empty paragraphs with line breaks
912+
.replace(/<p><\/p>/g, '<br/>')
913+
// Replace multiple spaces with non-breaking spaces
914+
.replace(/ {2,}/g, (m) => m.replace(/ /g, '\u00a0'))
915+
// Replace tabs with non-breaking spaces (preserve indentation)
916+
.replace(/\t/g, '\u00a0\u00a0\u00a0\u00a0') // 1 tab = 4 spaces
917+
)
918+
// Convert non-breaking spaces back to regular spaces for markdown
919+
.replace(/\u00a0/g, ' ')
920+
);
908921
}
909922
910923
onChange({
@@ -1267,14 +1280,16 @@
12671280
12681281
const jsonValue = editor.getJSON();
12691282
const htmlValue = editor.getHTML();
1270-
let mdValue = turndownService
1271-
.turndown(
1272-
(preserveBreaks ? htmlValue.replace(/<p><\/p>/g, '<br/>') : htmlValue).replace(
1273-
/ {2,}/g,
1274-
(m) => m.replace(/ /g, '\u00a0')
1283+
let mdValue = stripTrailingWhitespace(
1284+
turndownService
1285+
.turndown(
1286+
(preserveBreaks ? htmlValue.replace(/<p><\/p>/g, '<br/>') : htmlValue).replace(
1287+
/ {2,}/g,
1288+
(m) => m.replace(/ /g, '\u00a0')
1289+
)
12751290
)
1276-
)
1277-
.replace(/\u00a0/g, ' ');
1291+
.replace(/\u00a0/g, ' ')
1292+
);
12781293
12791294
if (value === '') {
12801295
editor.commands.clearContent(); // Clear content if value is empty
@@ -1300,7 +1315,7 @@
13001315
preserveBreaks
13011316
? value
13021317
: marked.parse(value.replaceAll(`\n<br/>`, `<br/>`), {
1303-
breaks: false
1318+
breaks: true
13041319
})
13051320
);
13061321

0 commit comments

Comments
 (0)