1*26ad19fcSEvan Bacon/** 2*26ad19fcSEvan Bacon * Copyright (c) 650 Industries. 3*26ad19fcSEvan Bacon * Copyright (c) Meta Platforms, Inc. and affiliates. 4*26ad19fcSEvan Bacon * 5*26ad19fcSEvan Bacon * This source code is licensed under the MIT license found in the 6*26ad19fcSEvan Bacon * LICENSE file in the root directory of this source tree. 7*26ad19fcSEvan Bacon */ 8*26ad19fcSEvan Baconimport Anser from 'anser'; 9*26ad19fcSEvan Baconimport React from 'react'; 10*26ad19fcSEvan Baconimport { StyleProp, StyleSheet, Text, TextStyle, View } from 'react-native'; 11*26ad19fcSEvan Bacon 12*26ad19fcSEvan Bacon// Afterglow theme from https://iterm2colorschemes.com/ 13*26ad19fcSEvan Baconconst COLORS: Record<string, string> = { 14*26ad19fcSEvan Bacon 'ansi-black': 'rgb(27, 27, 27)', 15*26ad19fcSEvan Bacon 'ansi-red': 'rgb(187, 86, 83)', 16*26ad19fcSEvan Bacon 'ansi-green': 'rgb(144, 157, 98)', 17*26ad19fcSEvan Bacon 'ansi-yellow': 'rgb(234, 193, 121)', 18*26ad19fcSEvan Bacon 'ansi-blue': 'rgb(125, 169, 199)', 19*26ad19fcSEvan Bacon 'ansi-magenta': 'rgb(176, 101, 151)', 20*26ad19fcSEvan Bacon 'ansi-cyan': 'rgb(140, 220, 216)', 21*26ad19fcSEvan Bacon // Instead of white, use the default color provided to the component 22*26ad19fcSEvan Bacon // 'ansi-white': 'rgb(216, 216, 216)', 23*26ad19fcSEvan Bacon 'ansi-bright-black': 'rgb(98, 98, 98)', 24*26ad19fcSEvan Bacon 'ansi-bright-red': 'rgb(187, 86, 83)', 25*26ad19fcSEvan Bacon 'ansi-bright-green': 'rgb(144, 157, 98)', 26*26ad19fcSEvan Bacon 'ansi-bright-yellow': 'rgb(234, 193, 121)', 27*26ad19fcSEvan Bacon 'ansi-bright-blue': 'rgb(125, 169, 199)', 28*26ad19fcSEvan Bacon 'ansi-bright-magenta': 'rgb(176, 101, 151)', 29*26ad19fcSEvan Bacon 'ansi-bright-cyan': 'rgb(140, 220, 216)', 30*26ad19fcSEvan Bacon 'ansi-bright-white': 'rgb(247, 247, 247)', 31*26ad19fcSEvan Bacon}; 32*26ad19fcSEvan Bacon 33*26ad19fcSEvan Baconexport function Ansi({ text, style }: { text: string; style: StyleProp<TextStyle> }) { 34*26ad19fcSEvan Bacon let commonWhitespaceLength = Infinity; 35*26ad19fcSEvan Bacon const parsedLines = text.split(/\n/).map((line) => 36*26ad19fcSEvan Bacon Anser.ansiToJson(line, { 37*26ad19fcSEvan Bacon json: true, 38*26ad19fcSEvan Bacon remove_empty: true, 39*26ad19fcSEvan Bacon use_classes: true, 40*26ad19fcSEvan Bacon }) 41*26ad19fcSEvan Bacon ); 42*26ad19fcSEvan Bacon 43*26ad19fcSEvan Bacon parsedLines.map((lines) => { 44*26ad19fcSEvan Bacon // The third item on each line includes the whitespace of the source code. 45*26ad19fcSEvan Bacon // We are looking for the least amount of common whitespace to trim all lines. 46*26ad19fcSEvan Bacon // Example: Array [" ", " 96 |", " text", ...] 47*26ad19fcSEvan Bacon const match = lines[2] && lines[2]?.content?.match(/^ +/); 48*26ad19fcSEvan Bacon const whitespaceLength = (match && match[0]?.length) || 0; 49*26ad19fcSEvan Bacon if (whitespaceLength < commonWhitespaceLength) { 50*26ad19fcSEvan Bacon commonWhitespaceLength = whitespaceLength; 51*26ad19fcSEvan Bacon } 52*26ad19fcSEvan Bacon }); 53*26ad19fcSEvan Bacon 54*26ad19fcSEvan Bacon const getText = (content: string, key: number) => { 55*26ad19fcSEvan Bacon if (key === 1) { 56*26ad19fcSEvan Bacon // Remove the vertical bar after line numbers 57*26ad19fcSEvan Bacon return content.replace(/\| $/, ' '); 58*26ad19fcSEvan Bacon } else if (key === 2 && commonWhitespaceLength < Infinity) { 59*26ad19fcSEvan Bacon // Remove common whitespace at the beginning of the line 60*26ad19fcSEvan Bacon return content.substr(commonWhitespaceLength); 61*26ad19fcSEvan Bacon } else { 62*26ad19fcSEvan Bacon return content; 63*26ad19fcSEvan Bacon } 64*26ad19fcSEvan Bacon }; 65*26ad19fcSEvan Bacon 66*26ad19fcSEvan Bacon return ( 67*26ad19fcSEvan Bacon <View> 68*26ad19fcSEvan Bacon {parsedLines.map((items, i) => ( 69*26ad19fcSEvan Bacon <View style={styles.line} key={i}> 70*26ad19fcSEvan Bacon {items.map((bundle, key) => { 71*26ad19fcSEvan Bacon const textStyle = 72*26ad19fcSEvan Bacon bundle.fg && COLORS[bundle.fg] 73*26ad19fcSEvan Bacon ? { 74*26ad19fcSEvan Bacon backgroundColor: bundle.bg && COLORS[bundle.bg], 75*26ad19fcSEvan Bacon color: bundle.fg && COLORS[bundle.fg], 76*26ad19fcSEvan Bacon } 77*26ad19fcSEvan Bacon : { 78*26ad19fcSEvan Bacon backgroundColor: bundle.bg && COLORS[bundle.bg], 79*26ad19fcSEvan Bacon }; 80*26ad19fcSEvan Bacon return ( 81*26ad19fcSEvan Bacon <Text style={[style, textStyle]} key={key}> 82*26ad19fcSEvan Bacon {getText(bundle.content, key)} 83*26ad19fcSEvan Bacon </Text> 84*26ad19fcSEvan Bacon ); 85*26ad19fcSEvan Bacon })} 86*26ad19fcSEvan Bacon </View> 87*26ad19fcSEvan Bacon ))} 88*26ad19fcSEvan Bacon </View> 89*26ad19fcSEvan Bacon ); 90*26ad19fcSEvan Bacon} 91*26ad19fcSEvan Bacon 92*26ad19fcSEvan Baconconst styles = StyleSheet.create({ 93*26ad19fcSEvan Bacon line: { 94*26ad19fcSEvan Bacon flexDirection: 'row', 95*26ad19fcSEvan Bacon }, 96*26ad19fcSEvan Bacon}); 97