Files
react-native/Libraries/LogBox/UI/AnsiHighlight.js
T
Rick Hanlon 64bc400c77 LogBox - Fix code frame whitespace trimming
Summary:
This diff fixes whitespace trimming in codeframes by setting the whitespace size to 0 instead of infinity for lines that's don't have whitespace. This fixes a bug in frames where lines with 0 whitespace would not be considered.

So frames like this, where the common whitespace should be 0:

```
  217 | function Hi(a?: String) {
> 218 |   return Platform.OS === 'android' ? obj.die() : obj.die();
      |                                                  ^
  219 | }
  220 |
  221 | export default CrashReactApp;
```

Are instead trimmed at the second most common whitespace, which is 2. That's because line 217 has a whitespace length of 0, but we consider it as Infinity. When we get to line 218, we set the whitespace to 2. Then on line 19 we consider if 2 < Infinity and decide that the common whitespace is 2 resulting in:

```
  217 | nction Hi(a?: String) {
> 218 | return Platform.OS === 'android' ? obj.die() : obj.die();
      |                                                ^
  219 |
  220 |
  221 | port default CrashReactApp;
```

By setting the whitespace per line to 0 when there's no whitespace match, lines without whitespace can accurately report their size and move the pointer back to the 0 position.

Changelog: [Internal]

Reviewed By: cpojer

Differential Revision: D20030301

fbshipit-source-id: f1dec8cc57479f37ffa8128f93f7c8b3c6baaf91
2020-02-21 10:23:31 -08:00

104 lines
3.1 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import {ansiToJson} from 'anser';
import Text from '../../Text/Text';
import View from '../../Components/View/View';
import * as React from 'react';
import type {TextStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet';
// Afterglow theme from https://iterm2colorschemes.com/
const COLORS = {
'ansi-black': 'rgb(27, 27, 27)',
'ansi-red': 'rgb(187, 86, 83)',
'ansi-green': 'rgb(144, 157, 98)',
'ansi-yellow': 'rgb(234, 193, 121)',
'ansi-blue': 'rgb(125, 169, 199)',
'ansi-magenta': 'rgb(176, 101, 151)',
'ansi-cyan': 'rgb(140, 220, 216)',
// Instead of white, use the default color provided to the component
// 'ansi-white': 'rgb(216, 216, 216)',
'ansi-bright-black': 'rgb(98, 98, 98)',
'ansi-bright-red': 'rgb(187, 86, 83)',
'ansi-bright-green': 'rgb(144, 157, 98)',
'ansi-bright-yellow': 'rgb(234, 193, 121)',
'ansi-bright-blue': 'rgb(125, 169, 199)',
'ansi-bright-magenta': 'rgb(176, 101, 151)',
'ansi-bright-cyan': 'rgb(140, 220, 216)',
'ansi-bright-white': 'rgb(247, 247, 247)',
};
export default function Ansi({
text,
style,
}: {
text: string,
style: TextStyleProp,
...
}): React.Node {
let commonWhitespaceLength = Infinity;
const parsedLines = text.split(/\n/).map(line =>
ansiToJson(line, {
json: true,
remove_empty: true,
use_classes: true,
}),
);
parsedLines.map(lines => {
// The third item on each line includes the whitespace of the source code.
// We are looking for the least amount of common whitespace to trim all lines.
// Example: Array [" ", " 96 |", " text", ...]
const match = lines[2] && lines[2]?.content?.match(/^ +/);
const whitespaceLength = (match && match[0]?.length) || 0;
if (whitespaceLength < commonWhitespaceLength) {
commonWhitespaceLength = whitespaceLength;
}
});
const getText = (content, key) => {
if (key === 1) {
// Remove the vertical bar after line numbers
return content.replace(/\| $/, ' ');
} else if (key === 2 && commonWhitespaceLength < Infinity) {
// Remove common whitespace at the beginning of the line
return content.substr(commonWhitespaceLength);
} else {
return content;
}
};
return (
<View style={{flexDirection: 'column'}}>
{parsedLines.map((items, i) => (
<View style={{flexDirection: 'row'}} key={i}>
{items.map((bundle, key) => {
const textStyle =
bundle.fg && COLORS[bundle.fg]
? {
backgroundColor: bundle.bg && COLORS[bundle.bg],
color: bundle.fg && COLORS[bundle.fg],
}
: {
backgroundColor: bundle.bg && COLORS[bundle.bg],
};
return (
<Text style={[style, textStyle]} key={key}>
{getText(bundle.content, key)}
</Text>
);
})}
</View>
))}
</View>
);
}