@@ -10,21 +10,63 @@ import { getCurrentProject } from "../settings/manager.js";
1010const TELEGRAM_MESSAGE_LIMIT = 4096 ;
1111const MARKDOWN_V2_RESERVED_CHARS = / ( [ _ \* \[ \] \( \) ~ ` > # + \- = | { } . ! \\ ] ) / g;
1212
13- function splitText ( text : string , maxLength : number ) : string [ ] {
14- const parts : string [ ] = [ ] ;
15- let currentIndex = 0 ;
13+ interface SplitTextOptions {
14+ avoidTrailingMarkdownEscape ?: boolean ;
15+ }
1616
17- while ( currentIndex < text . length ) {
18- let endIndex = currentIndex + maxLength ;
17+ function endsWithOddTrailingBackslashes ( text : string , start : number , end : number ) : boolean {
18+ let backslashCount = 0 ;
1919
20- if ( endIndex >= text . length ) {
21- parts . push ( text . slice ( currentIndex ) ) ;
20+ for ( let index = end - 1 ; index >= start ; index -- ) {
21+ if ( text [ index ] !== "\\" ) {
2222 break ;
2323 }
24+ backslashCount += 1 ;
25+ }
26+
27+ return backslashCount % 2 === 1 ;
28+ }
29+
30+ function resolveSplitEndIndex (
31+ text : string ,
32+ currentIndex : number ,
33+ maxLength : number ,
34+ options ?: SplitTextOptions ,
35+ ) : number {
36+ const hardLimit = Math . min ( text . length , currentIndex + maxLength ) ;
37+ if ( hardLimit >= text . length ) {
38+ return text . length ;
39+ }
40+
41+ let endIndex = hardLimit ;
42+ const breakPoint = text . lastIndexOf ( "\n" , endIndex ) ;
43+ if ( breakPoint > currentIndex ) {
44+ endIndex = breakPoint + 1 ;
45+ }
2446
25- const breakPoint = text . lastIndexOf ( "\n" , endIndex ) ;
26- if ( breakPoint > currentIndex ) {
27- endIndex = breakPoint + 1 ;
47+ if ( ! options ?. avoidTrailingMarkdownEscape ) {
48+ return endIndex ;
49+ }
50+
51+ while ( endIndex > currentIndex && endsWithOddTrailingBackslashes ( text , currentIndex , endIndex ) ) {
52+ endIndex -= 1 ;
53+ }
54+
55+ return endIndex > currentIndex ? endIndex : hardLimit ;
56+ }
57+
58+ function splitText ( text : string , maxLength : number , options ?: SplitTextOptions ) : string [ ] {
59+ const parts : string [ ] = [ ] ;
60+ let currentIndex = 0 ;
61+
62+ while ( currentIndex < text . length ) {
63+ const endIndex = resolveSplitEndIndex ( text , currentIndex , maxLength , options ) ;
64+
65+ if ( endIndex <= currentIndex ) {
66+ const fallbackEnd = Math . min ( text . length , currentIndex + 1 ) ;
67+ parts . push ( text . slice ( currentIndex , fallbackEnd ) ) ;
68+ currentIndex = fallbackEnd ;
69+ continue ;
2870 }
2971
3072 parts . push ( text . slice ( currentIndex , endIndex ) ) ;
@@ -252,7 +294,9 @@ export function formatSummaryWithMode(
252294
253295 if ( mode === "markdown" ) {
254296 const converted = formatMarkdownForTelegram ( trimmed ) ;
255- const convertedParts = splitText ( converted , normalizedMaxLength ) ;
297+ const convertedParts = splitText ( converted , normalizedMaxLength , {
298+ avoidTrailingMarkdownEscape : true ,
299+ } ) ;
256300
257301 for ( const convertedPart of convertedParts ) {
258302 const normalizedPart = convertedPart . trim ( ) ;
0 commit comments