From c5241bbca0dac5c7b04a9cc1da05358e1180f70e Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 14 Oct 2020 21:49:31 -0700 Subject: [PATCH] chore: roll up lines into commands --- src/components/Terminal/SyntaxHighlighter.js | 63 +++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/src/components/Terminal/SyntaxHighlighter.js b/src/components/Terminal/SyntaxHighlighter.js index 394fe51fd..bc76b4ec3 100644 --- a/src/components/Terminal/SyntaxHighlighter.js +++ b/src/components/Terminal/SyntaxHighlighter.js @@ -5,17 +5,17 @@ import Highlight from 'prism-react-renderer'; import Prism from 'prismjs'; import Prompt from './Prompt'; -const WHITESPACE = /^\s*$/; const MULTILINE_COMMAND = /\\\s*$/; +const OUTPUT_TAG = /^\[output\]\s/; +const OUTPUT_COLOR_TOKENS = /{([a-z]+)}(.*?(?={|$))/g; const SyntaxHighlighter = ({ code }) => ( {({ tokens, getLineProps, getTokenProps }) => { - console.log(tokens); + const commands = rollupIntoCommands(tokens, code); + return tokens.map((line, idx) => { - const previousLine = collapse(tokens[idx - 1] || []) - .map((token) => token.content) - .join(' '); + const previousLine = collapse(tokens[idx - 1] || []); const isMultiline = MULTILINE_COMMAND.test(previousLine); return ( @@ -49,10 +49,57 @@ const SyntaxHighlighter = ({ code }) => ( ); const collapse = (line) => { - return line.filter( - (token) => - !WHITESPACE.test(token.content) && !token.types.includes('comment') + return line + .filter((token) => !token.types.includes('comment')) + .map((token) => token.content) + .join(''); +}; + +const rollupIntoCommands = (lines, code) => { + const rawLines = code.split('\n'); + + const { commands } = lines.reduce( + ({ commands, terminated }, line, idx) => { + const command = collapse(line); + const updateIdx = terminated ? commands.length : commands.length - 1; + const data = commands[updateIdx] || { lines: [], output: [] }; + const nextCommand = collapse(lines[idx + 1] || []); + const continues = + OUTPUT_TAG.test(nextCommand) || MULTILINE_COMMAND.test(command); + + if (OUTPUT_TAG.test(command)) { + commands[updateIdx] = { + ...data, + output: [...data.output, tokenizeOutputLine(rawLines[idx])], + }; + } else { + commands[updateIdx] = { ...data, lines: [...data.lines, line] }; + } + + return { commands, terminated: !continues }; + }, + { commands: [{ lines: [], output: [] }], terminated: false } ); + + return commands; +}; + +const tokenizeOutputLine = (line) => { + const text = line.replace(OUTPUT_TAG, ''); + const tokens = Array.from(text.matchAll(OUTPUT_COLOR_TOKENS)); + + if (tokens.length === 0) { + return [{ color: 'plain', text }]; + } + + const startOfColorIdx = text.indexOf('{'); + const coloredTokens = tokens.map(([, color, text]) => ({ color, text })); + + return startOfColorIdx === 0 + ? coloredTokens + : [{ color: 'plain', text: text.slice(0, startOfColorIdx) }].concat( + coloredTokens + ); }; SyntaxHighlighter.propTypes = {