Skip to content

Commit

Permalink
feat: add output coloring for each output line
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller committed Oct 15, 2020
1 parent c5241bb commit 0ed5a72
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 29 deletions.
35 changes: 35 additions & 0 deletions src/components/Terminal/Command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import Prompt from './Prompt';
import { css } from '@emotion/core';

const Command = ({ line, prompt, getTokenProps }) => (
<div
css={css`
display: grid;
grid-template-columns: 1ch 1fr;
grid-gap: 1ch;
`}
>
<Prompt character={prompt} />
<div
css={css`
color: #fafafa;
white-space: pre;
`}
>
{line.map((token, key) => (
// eslint-disable-next-line react/jsx-key
<span {...getTokenProps({ token, key })} />
))}
</div>
</div>
);

Command.propTypes = {
line: PropTypes.arrayOf(PropTypes.object).isRequired,
getTokenProps: PropTypes.func.isRequired,
prompt: PropTypes.oneOf(['$', '>']),
};

export default Command;
43 changes: 43 additions & 0 deletions src/components/Terminal/Output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/core';

const Output = ({ line }) => (
<div
css={css`
color: #fafafa;
white-space: pre;
`}
>
{line.map((token, key) => (
<span
key={key}
css={css`
color: ${OUTPUT_COLORS[token.color] || OUTPUT_COLORS.plain};
`}
>
{token.text}
</span>
))}
</div>
);

const OUTPUT_COLORS = {
plain: 'currentColor',
green: 'var(--color-nord-14)',
red: 'var(--color-nord-11)',
muted: 'var(--color-nord-3)',
purple: 'var(--color-nord-15)',
blue: 'var(--color-nord-9)',
};

OUTPUT_COLORS.timestamp = OUTPUT_COLORS.muted;
OUTPUT_COLORS.variable = OUTPUT_COLORS.purple;
OUTPUT_COLORS.success = OUTPUT_COLORS.green;
OUTPUT_COLORS.error = OUTPUT_COLORS.red;

Output.propTypes = {
line: PropTypes.arrayOf(PropTypes.object).isRequired,
};

export default Output;
48 changes: 19 additions & 29 deletions src/components/Terminal/SyntaxHighlighter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,35 @@ import PropTypes from 'prop-types';
import { css } from '@emotion/core';
import Highlight from 'prism-react-renderer';
import Prism from 'prismjs';
import Prompt from './Prompt';
import Command from './Command';
import Output from './Output';

const MULTILINE_COMMAND = /\\\s*$/;
const OUTPUT_TAG = /^\[output\]\s/;
const OUTPUT_COLOR_TOKENS = /{([a-z]+)}(.*?(?={|$))/g;

const SyntaxHighlighter = ({ code }) => (
<Highlight Prism={Prism} code={code} language="shell">
{({ tokens, getLineProps, getTokenProps }) => {
{({ tokens, getTokenProps }) => {
const commands = rollupIntoCommands(tokens, code);

return tokens.map((line, idx) => {
const previousLine = collapse(tokens[idx - 1] || []);
const isMultiline = MULTILINE_COMMAND.test(previousLine);

return commands.map(({ lines, output }, commandIdx) => {
return (
// eslint-disable-next-line react/jsx-key
<div {...getLineProps({ line, key: idx })}>
<div
css={css`
display: grid;
grid-template-columns: 1ch 1fr;
grid-gap: 1ch;
`}
>
<Prompt character={isMultiline ? '>' : '$'} />
<div
css={css`
color: #fafafa;
white-space: pre;
`}
>
{line.map((token, key) => (
// eslint-disable-next-line react/jsx-key
<span {...getTokenProps({ token, key })} />
))}
</div>
</div>
</div>
<>
{lines.map((line, idx) => {
return (
<Command
key={`${commandIdx}-${idx}`}
line={line}
prompt={idx > 0 ? '>' : '$'}
getTokenProps={getTokenProps}
/>
);
})}
{output.map((line, idx) => (
<Output key={`${commandIdx}-${idx}`} line={line} />
))}
</>
);
});
}}
Expand Down

0 comments on commit 0ed5a72

Please sign in to comment.