@@ -46,7 +46,7 @@ class DiffService {
4646		'info '  => 'ℹ️ ' ,
4747		'success '  => '✅ ' ,
4848		'warn '  => '⚠️ ' ,
49- 		'error '  => '🔴 ' ,
49+ 		'error '  => '❗ ' ,
5050	];
5151
5252	/** 
@@ -426,6 +426,11 @@ private function generateWordLevelDiff(string $oldLine, string $newLine): string
426426			return  $ this  ->generateCalloutBlockDiff ($ oldLine , $ newLine );
427427		}
428428
429+ 		// Check if either line is a quote line 
430+ 		if  ($ this  ->isQuoteLine ($ oldLine ) || $ this  ->isQuoteLine ($ newLine )) {
431+ 			return  $ this  ->generateQuoteDiff ($ oldLine , $ newLine );
432+ 		}
433+ 
429434		// Split lines into words for comparison 
430435		$ oldWords  = $ this  ->splitIntoWords ($ oldLine );
431436		$ newWords  = $ this  ->splitIntoWords ($ newLine );
@@ -515,6 +520,42 @@ private function generateCalloutBlockDiff(string $oldLine, string $newLine): str
515520		return  $ oldEmoji  . '→ '  . $ newEmoji ;
516521	}
517522
523+ 	/** 
524+ 	 * Check if a line is a quote line 
525+ 	 * 
526+ 	 * @param string $line 
527+ 	 * @return bool 
528+ 	 */ 
529+ 	private  function  isQuoteLine (string  $ line ): bool  {
530+ 		return  preg_match (self ::QUOTE_PATTERN , trim ($ line )) === 1 ;
531+ 	}
532+ 
533+ 	/** 
534+ 	 * Generate diff for quote line changes 
535+ 	 * 
536+ 	 * @param string $oldLine 
537+ 	 * @param string $newLine 
538+ 	 * @return string 
539+ 	 */ 
540+ 	private  function  generateQuoteDiff (string  $ oldLine , string  $ newLine ): string  {
541+ 		$ oldText  = preg_replace (self ::QUOTE_PATTERN , '' , $ oldLine );
542+ 		$ newText  = preg_replace (self ::QUOTE_PATTERN , '' , $ newLine );
543+ 
544+ 		// If both are quotes, show the text change 
545+ 		if  ($ this  ->isQuoteLine ($ oldLine ) && $ this  ->isQuoteLine ($ newLine )) {
546+ 			return  '→❞  '  . htmlspecialchars (trim ($ oldText ), ENT_QUOTES , 'UTF-8 ' ) .
547+ 			       '→ '  . htmlspecialchars (trim ($ newText ), ENT_QUOTES , 'UTF-8 ' );
548+ 		}
549+ 
550+ 		// If only new line is a quote 
551+ 		if  ($ this  ->isQuoteLine ($ newLine )) {
552+ 			return  '→❞  '  . htmlspecialchars (trim ($ newText ), ENT_QUOTES , 'UTF-8 ' );
553+ 		}
554+ 
555+ 		// If only old line was a quote 
556+ 		return  '❞→  '  . htmlspecialchars (trim ($ newText ), ENT_QUOTES , 'UTF-8 ' );
557+ 	}
558+ 
518559	/** 
519560	 * Format special lines (code blocks, callouts, quotes) with emojis 
520561	 * 
@@ -531,7 +572,7 @@ private function formatSpecialLine(string $line): ?string {
531572
532573		// Format code block markers 
533574		if  (preg_match (self ::CODE_BLOCK_PATTERN , $ trimmed )) {
534- 			return  '→📝  ' ;
575+ 			return  '→‹›  ' ;
535576		}
536577
537578		// Format callout block markers 
@@ -545,7 +586,7 @@ private function formatSpecialLine(string $line): ?string {
545586		if  (preg_match (self ::QUOTE_PATTERN , $ trimmed )) {
546587			// Remove the > marker and return the quoted text with emoji 
547588			$ quotedText  = preg_replace (self ::QUOTE_PATTERN , '' , $ line );
548- 			return  '→💬   '  . htmlspecialchars ($ quotedText , ENT_QUOTES , 'UTF-8 ' );
589+ 			return  '→❞   '  . htmlspecialchars ($ quotedText , ENT_QUOTES , 'UTF-8 ' );
549590		}
550591
551592		// Return original line if not a special pattern 
@@ -582,31 +623,60 @@ private function splitIntoWords(string $text): array {
582623	 */ 
583624	private  function  renderWordLevelHtml (array  $ operations , array  $ oldWords , array  $ newWords ): string  {
584625		$ html  = '' ;
585- 		$ lastWasDel  = false ;
586- 		
626+ 		$ buffer  = '' ;
627+ 		$ lastType  = null ;
628+ 
587629		foreach  ($ operations  as  $ operation ) {
588- 			switch  ($ operation ['type ' ]) {
630+ 			$ currentType  = $ operation ['type ' ];
631+ 			$ word  = '' ;
632+ 
633+ 			// Get the word for this operation 
634+ 			switch  ($ currentType ) {
589635				case  'add ' :
590636					$ word  = $ newWords [$ operation ['new_line ' ]] ?? '' ;
591- 					// Add arrow if previous operation was a deletion (showing replacement) 
592- 					if  ($ lastWasDel ) {
593- 						$ html  .= '→ '  . htmlspecialchars ($ word , ENT_QUOTES , 'UTF-8 ' );
594- 					} else  {
595- 						$ html  .= htmlspecialchars ($ word , ENT_QUOTES , 'UTF-8 ' );
596- 					}
597- 					$ lastWasDel  = false ;
598637					break ;
599638				case  'remove ' :
600639					$ word  = $ oldWords [$ operation ['old_line ' ]] ?? '' ;
601- 					$ html  .= htmlspecialchars ($ word , ENT_QUOTES , 'UTF-8 ' );
602- 					$ lastWasDel  = true ;
603640					break ;
604641				case  'keep ' :
605642					$ word  = $ oldWords [$ operation ['old_line ' ]] ?? '' ;
606- 					$ html  .= htmlspecialchars ($ word , ENT_QUOTES , 'UTF-8 ' );
607- 					$ lastWasDel  = false ;
608643					break ;
609644			}
645+ 
646+ 			// If current operation is 'keep' and it's only whitespace, and we have a buffer of add/remove, 
647+ 			// then add it to the buffer to merge tags 
648+ 			if  ($ currentType  === 'keep '  && trim ($ word ) === ''  && $ lastType  !== null  && $ lastType  !== 'keep ' ) {
649+ 				$ buffer  .= htmlspecialchars ($ word , ENT_QUOTES , 'UTF-8 ' );
650+ 				// Don't change lastType, so we continue with the same operation type 
651+ 				continue ;
652+ 			}
653+ 
654+ 			// If type changed (and not a whitespace-only keep), flush the buffer with appropriate tags 
655+ 			if  ($ lastType  !== null  && $ lastType  !== $ currentType  && $ buffer  !== '' ) {
656+ 				if  ($ lastType  === 'add ' ) {
657+ 					$ html  .= '<ins> '  . $ buffer  . '</ins> ' ;
658+ 				} elseif  ($ lastType  === 'remove ' ) {
659+ 					$ html  .= '<del> '  . $ buffer  . '</del> ' ;
660+ 				} else  {
661+ 					$ html  .= $ buffer ;
662+ 				}
663+ 				$ buffer  = '' ;
664+ 			}
665+ 
666+ 			// Add current word to buffer 
667+ 			$ buffer  .= htmlspecialchars ($ word , ENT_QUOTES , 'UTF-8 ' );
668+ 			$ lastType  = $ currentType ;
669+ 		}
670+ 
671+ 		// Flush remaining buffer 
672+ 		if  ($ buffer  !== '' ) {
673+ 			if  ($ lastType  === 'add ' ) {
674+ 				$ html  .= '<ins> '  . $ buffer  . '</ins> ' ;
675+ 			} elseif  ($ lastType  === 'remove ' ) {
676+ 				$ html  .= '<del> '  . $ buffer  . '</del> ' ;
677+ 			} else  {
678+ 				$ html  .= $ buffer ;
679+ 			}
610680		}
611681
612682		return  $ html ;
0 commit comments