@@ -8,6 +8,8 @@ interface CodePreviewProps {
88 maxHeight ?: number ;
99 startLine ?: number ;
1010 language ?: string ;
11+ diffLanguage ?: string ;
12+ showLineNumbers ?: boolean ;
1113}
1214
1315type TokenKind =
@@ -160,12 +162,25 @@ function tokenizeGeneric(line: string): Segment[] {
160162 return [ { text : line || " " , kind : "plain" } ] ;
161163}
162164
163- function tokenizeDiff ( line : string ) : Segment [ ] {
165+ function tintSegments ( segments : Segment [ ] , kind : TokenKind ) : Segment [ ] {
166+ return segments . map ( ( segment ) =>
167+ segment . kind === "plain" || segment . kind === "punctuation" ? { ...segment , kind } : segment ,
168+ ) ;
169+ }
170+
171+ function tokenizeDiff ( line : string , diffLanguage ?: string ) : Segment [ ] {
164172 if ( line . startsWith ( "@@" ) || line . startsWith ( "diff " ) || line . startsWith ( "index " ) ) {
165173 return [ { text : line || " " , kind : "diffMeta" } ] ;
166174 }
167- if ( line . startsWith ( "+" ) ) return [ { text : line || " " , kind : "diffAdd" } ] ;
168- if ( line . startsWith ( "-" ) ) return [ { text : line || " " , kind : "diffRemove" } ] ;
175+ if ( line . startsWith ( "+" ) ) {
176+ return [ { text : "+" , kind : "diffAdd" } , ...tintSegments ( tokenizeLine ( line . slice ( 1 ) , diffLanguage ) , "diffAdd" ) ] ;
177+ }
178+ if ( line . startsWith ( "-" ) ) {
179+ return [ { text : "-" , kind : "diffRemove" } , ...tintSegments ( tokenizeLine ( line . slice ( 1 ) , diffLanguage ) , "diffRemove" ) ] ;
180+ }
181+ if ( line . startsWith ( " " ) ) {
182+ return [ { text : " " , kind : "plain" } , ...tokenizeLine ( line . slice ( 1 ) , diffLanguage ) ] ;
183+ }
169184 return tokenizeGeneric ( line ) ;
170185}
171186
@@ -252,6 +267,21 @@ function tokenizeBash(line: string): Segment[] {
252267 ) ;
253268}
254269
270+ function tokenizeYaml ( line : string ) : Segment [ ] {
271+ return tokenizeWithPattern (
272+ line ,
273+ / ( # .* $ | " (?: [ ^ " \\ ] | \\ .) * " | ' (?: [ ^ ' \\ ] | \\ .) * ' | \b \d + (?: \. \d + ) ? \b | \b t r u e \b | \b f a l s e \b | \b n u l l \b | \b [ A - Z a - z 0 - 9 _ . - ] + (? = \s * : ) | [ { } \[ \] , : - ] ) / g,
274+ ( value ) => {
275+ if ( value . startsWith ( "#" ) ) return "comment" ;
276+ if ( value . startsWith ( '"' ) || value . startsWith ( "'" ) ) return "string" ;
277+ if ( / ^ \d / . test ( value ) ) return "number" ;
278+ if ( / ^ ( t r u e | f a l s e | n u l l ) $ / . test ( value ) ) return "keyword" ;
279+ if ( / ^ [ A - Z a - z 0 - 9 _ . - ] + $ / . test ( value ) ) return "property" ;
280+ return "punctuation" ;
281+ } ,
282+ ) ;
283+ }
284+
255285function tokenizeMarkup ( line : string ) : Segment [ ] {
256286 return tokenizeWithPattern (
257287 line ,
@@ -268,7 +298,7 @@ function tokenizeMarkup(line: string): Segment[] {
268298 ) ;
269299}
270300
271- function tokenizeLine ( line : string , language ?: string ) : Segment [ ] {
301+ function tokenizeLine ( line : string , language ?: string , diffLanguage ?: string ) : Segment [ ] {
272302 const lang = normalizeLanguage ( language ) ;
273303
274304 if ( [ "ts" , "tsx" , "js" , "jsx" , "typescript" , "javascript" ] . includes ( lang ) ) {
@@ -277,8 +307,9 @@ function tokenizeLine(line: string, language?: string): Segment[] {
277307 if ( lang === "json" ) return tokenizeJson ( line ) ;
278308 if ( [ "py" , "python" ] . includes ( lang ) ) return tokenizePython ( line ) ;
279309 if ( [ "bash" , "sh" , "shell" , "zsh" ] . includes ( lang ) ) return tokenizeBash ( line ) ;
310+ if ( [ "yaml" , "yml" ] . includes ( lang ) ) return tokenizeYaml ( line ) ;
280311 if ( [ "html" , "htm" , "xml" , "xhtml" , "svg" ] . includes ( lang ) ) return tokenizeMarkup ( line ) ;
281- if ( [ "diff" , "patch" ] . includes ( lang ) ) return tokenizeDiff ( line ) ;
312+ if ( [ "diff" , "patch" ] . includes ( lang ) ) return tokenizeDiff ( line , diffLanguage ) ;
282313 return tokenizeGeneric ( line ) ;
283314}
284315
@@ -288,13 +319,15 @@ export const CodePreview = memo(function CodePreview({
288319 maxHeight,
289320 startLine = 1 ,
290321 language,
322+ diffLanguage,
323+ showLineNumbers = true ,
291324} : CodePreviewProps ) {
292325 const colors = isDark ? Colors . dark : Colors . light ;
293326 const tokenColors = useMemo ( ( ) => createTokenColors ( isDark ) , [ isDark ] ) ;
294327 const lines = useMemo ( ( ) => code . split ( "\n" ) , [ code ] ) ;
295328
296329 return (
297- < View style = { [ styles . container , { backgroundColor : colors . surfaceRaised , borderColor : colors . border } ] } >
330+ < View style = { [ styles . container , { backgroundColor : colors . surfaceRaised , borderColor : colors . border } ] } >
298331 < ScrollView
299332 style = { maxHeight ? { maxHeight } : undefined }
300333 nestedScrollEnabled
@@ -303,15 +336,17 @@ export const CodePreview = memo(function CodePreview({
303336 < ScrollView horizontal showsHorizontalScrollIndicator = { false } >
304337 < View >
305338 { lines . map ( ( line , i ) => {
306- const segments = tokenizeLine ( line , language ) ;
339+ const segments = tokenizeLine ( line , language , diffLanguage ) ;
307340 return (
308341 < View key = { i } style = { styles . row } >
309- < View style = { [ styles . lineNoCol , { borderRightColor : colors . border } ] } >
310- < Text style = { [ styles . lineNo , { color : colors . textTertiary } ] } >
311- { startLine + i }
312- </ Text >
313- </ View >
314- < Text style = { [ styles . lineText , { color : tokenColors . plain } ] } >
342+ { showLineNumbers ? (
343+ < View style = { [ styles . lineNoCol , { borderRightColor : colors . border } ] } >
344+ < Text style = { [ styles . lineNo , { color : colors . textTertiary } ] } >
345+ { startLine + i }
346+ </ Text >
347+ </ View >
348+ ) : null }
349+ < Text style = { [ styles . lineText , ! showLineNumbers && styles . lineTextNoGutter , { color : tokenColors . plain } ] } >
315350 { segments . length ? segments . map ( ( segment , idx ) => (
316351 < Text key = { `${ i } -${ idx } ` } style = { { color : tokenColors [ segment . kind ] } } >
317352 { segment . text || ( idx === 0 ? " " : "" ) }
@@ -357,4 +392,7 @@ const styles = StyleSheet.create({
357392 paddingHorizontal : 8 ,
358393 paddingVertical : 1 ,
359394 } ,
395+ lineTextNoGutter : {
396+ paddingLeft : 10 ,
397+ } ,
360398} ) ;
0 commit comments