Skip to content

Commit

Permalink
feat: add syntax highlighting to terminal commands
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller committed Oct 14, 2020
1 parent 08afb77 commit d71b44d
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 39 deletions.
127 changes: 127 additions & 0 deletions src/components/Terminal/SyntaxHighlighter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/core';
import Highlight from 'prism-react-renderer';
import Prism from 'prismjs';

const WHITESPACE = /^\s*$/;
const MULTILINE_COMMAND = /\\\s*$/;

const SyntaxHighlighter = ({ code }) => (
<Highlight Prism={Prism} code={code} language="shell">
{({ tokens, getLineProps, getTokenProps }) => (
<pre
css={css`
${nordTheme};
color: var(--color-nord-6);
display: block;
overflow: auto;
white-space: pre;
word-spacing: normal;
word-break: normal;
tab-size: 2;
hyphens: none;
text-shadow: none;
.token-line {
display: grid;
grid-template-columns: 1ch 1fr;
grid-gap: 1rem;
}
`}
>
<code
css={css`
display: table;
width: 100%;
padding: 0;
background: none;
`}
>
{tokens.map((line, idx) => {
const previousLine = collapse(tokens[idx - 1] || [])
.map((token) => token.content)
.join(' ');
const isMultiline = MULTILINE_COMMAND.test(previousLine);

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;
`}
>
<span
css={css`
color: var(--color-nord-10);
user-select: none;
`}
>
{isMultiline ? '>' : '$'}
</span>
<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>
);
})}
</code>
</pre>
)}
</Highlight>
);

const nordTheme = css`
.namespace {
opacity: 0.7;
}
.token {
&.plain:empty {
display: inline-block;
}
&.comment {
color: var(--color-nord-3);
}
&.punctuation,
&.operator {
color: var(--color-nord-9);
}
&.constant {
color: var(--color-nord-15);
}
&.string {
color: var(--color-nord-14);
}
}
`;

const collapse = (line) => {
return line.filter(
(token) =>
!WHITESPACE.test(token.content) && !token.types.includes('comment')
);
};

SyntaxHighlighter.propTypes = {
className: PropTypes.string,
code: PropTypes.string.isRequired,
};

export default SyntaxHighlighter;
41 changes: 2 additions & 39 deletions src/components/Terminal/Terminal.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/core';
import { Button, useClipboard } from '@newrelic/gatsby-theme-newrelic';

const MULTILINE_COMMAND = /\\\s*$/;
import SyntaxHighlighter from './SyntaxHighlighter';

const Terminal = ({ children }) => {
const [copied, copy] = useClipboard();
Expand Down Expand Up @@ -66,17 +65,7 @@ const Terminal = ({ children }) => {
border-bottom-right-radius: var(--border-radius);
`}
>
{children
.trim()
.split('\n')
.map((line, idx, lines) => (
<Line
key={idx}
multiline={MULTILINE_COMMAND.test(lines[idx - 1] || '')}
>
{line}
</Line>
))}
<SyntaxHighlighter code={children.trim()} />
</div>
</div>
);
Expand All @@ -97,32 +86,6 @@ FrameButton.propTypes = {
color: PropTypes.string,
};

const Line = ({ children, multiline }) => (
<div
css={css`
display: flex;
`}
>
<span
css={css`
color: var(--color-nord-10);
user-select: none;
margin-right: 1ch;
`}
>
{multiline ? '>' : '$'}
</span>
<div
css={css`
color: #fafafa;
white-space: pre;
`}
>
{children}
</div>
</div>
);

Terminal.propTypes = {
children: PropTypes.string,
};
Expand Down

0 comments on commit d71b44d

Please sign in to comment.