char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
92d1bb0c9
char/aliceai-t5-moe
1/** 2* Line-level unified diff for tool result rendering. 3* 4* Pure functions: no DOM, no Svelte, no highlight.js dependency. The 5* returned `DiffLine[]` carries enough information both to render a 6* custom diff block (per-entry kind/text) and to fold back into a 7* unified-diff-format string for off-the-shelf highlighter languages 8* (`renderUnifiedDiff`). 9* 10* Algorithm: LCS dynamic programming with a soft "remove before add" 11* tiebreak so the resulting diff reads `(old -> new)` left to right. 12* O(m*n) time/space which is fine for the handful of lines an 13* `edit_file` snippet typically carries. 14*/ 15 16import { DiffLineKind } from '$lib/enums' ; 17 18export interface DiffLine { 19kind :DiffLineKind ; 20text :string ; 21/** 1-indexed line number in the OLD content. Undefined for `add` lines. */ 22oldLine ?:number ; 23/** 1-indexed line number in the NEW content. Undefined for `remove` lines. */ 24newLine ?:number ; 25} 26 27export function computeLineDiff ( oldText :string , newText :string ) :DiffLine [] { 28const oldLines = splitLines ( oldText ); 29const newLines = splitLines ( newText ); 30const m = oldLines . length ; 31const n = newLines . length ; 32 33if ( m === 0 && n === 0 ) return []; 34 35if ( m === 0 ) return newLines . map (( t , k ) => ({ kind :DiffLineKind . ADD , newLine :k + 1 , text :t })); 36 37if ( n === 0 ) 38return oldLines . map (( t , k ) => ({ kind :DiffLineKind . REMOVE , oldLine :k + 1 , text :t })); 39 40const lcs :number [][] = Array . from ({ length :m + 1 }, () => new Array ( n + 1 ). fill ( 0 )); 41 42for ( let i = 1 ; i <= m ; i ++ ) { 43for ( let j = 1 ; j <= n ; j ++ ) { 44if ( oldLines [ i - 1 ] === newLines [ j - 1 ]) { 45lcs [ i ][ j ] = lcs [ i - 1 ][ j - 1 ] + 1 ; 46} else { 47lcs [ i ][ j ] = Math . max ( lcs [ i - 1 ][ j ], lcs [ i ][ j - 1 ]); 48} 49} 50} 51 52const result :DiffLine [] = []; 53 54let i = m ; 55let j = n ; 56 57while ( i > 0 && j > 0 ) { 58if ( oldLines [ i - 1 ] === newLines [ j - 1 ]) { 59result . push ({ 60kind :DiffLineKind . CONTEXT , 61newLine :j , 62oldLine :i , 63text :oldLines [ i - 1 ] 64}); 65i -- ; 66j -- ; 67} else if ( lcs [ i - 1 ][ j ] >= lcs [ i ][ j - 1 ]) { 68result . push ({ kind :DiffLineKind . REMOVE , oldLine :i , text :oldLines [ i - 1 ] }); 69i -- ; 70} else { 71result . push ({ kind :DiffLineKind . ADD , newLine :j , text :newLines [ j - 1 ] }); 72j -- ; 73} 74} 75while ( i > 0 ) { 76result . push ({ kind :DiffLineKind . REMOVE , oldLine :i , text :oldLines [ i - 1 ] }); 77i -- ; 78} 79while ( j > 0 ) { 80result . push ({ kind :DiffLineKind . ADD , newLine :j , text :newLines [ j - 1 ] }); 81j -- ; 82} 83 84result . reverse (); 85 86return result ; 87} 88 89/** Folds `DiffLine[]` into a unified-diff-format text (`` ` ``/`+`/`-` prefixes). 90* Pass to a diff-aware highlighter (e.g., SyntaxHighlightedCode with 91* `language="diff"`) for colorization. 92*/ 93export function renderUnifiedDiff ( lines :DiffLine []) :string { 94if ( lines . length === 0 ) return '' ; 95 96return lines . map (( l ) => prefixFor ( l . kind ) + l . text ). join ( '\n' ); 97} 98 99/** Column-1 marker for a `DiffLine`: ` `, `+`, or `-`. */ 100export function prefixFor ( kind :DiffLineKind ) :string { 101if ( kind === DiffLineKind . ADD ) return '+' ; 102 103if ( kind === DiffLineKind . REMOVE ) return '-' ; 104 105return ' ' ; 106} 107 108function splitLines ( text :string ) :string [] { 109if ( text === '' ) return []; 110 111const parts = text . split ( '\n' ); 112 113if ( parts [ parts . length - 1 ] === '' ) parts . pop (); 114 115return parts . map (( l ) => ( l . endsWith ( '\r' ) ?l . slice ( 0 , - 1 ) :l )); 116}