All files / src/components/common CodeBlock.tsx

32.87% Statements 24/73
100% Branches 0/0
0% Functions 0/1
32.87% Lines 24/73

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 1671x 1x 1x 1x 1x 1x   1x   1x   1x 1x 1x                             1x 1x               1x     1x     1x                                             1x                   1x                                             1x   1x         1x                   1x   1x                                                                                             1x  
import { memo, useEffect } from "react"
import { useRemark } from "react-remark"
import rehypeHighlight, { Options } from "rehype-highlight"
import styled from "styled-components"
import { visit } from "unist-util-visit"
import "./codeblock-parser.css"
 
export const CODE_BLOCK_BG_COLOR = "var(--ai-hydro-surface, var(--vscode-editor-background, rgb(30 41 59)))"
 
export const TERMINAL_CODE_BLOCK_BG_COLOR = "var(--ai-hydro-background, var(--vscode-editor-background, rgb(15 23 42)))"
 
// Theme-aware background colors for expanded/collapsed states
export const CHAT_ROW_EXPANDED_BG_COLOR = "var(--ai-hydro-surface, var(--vscode-editor-background))"
export const CHAT_ROW_COLLAPSED_BG_COLOR = "var(--ai-hydro-background, var(--vscode-sideBar-background))"
 
/*
overflowX: auto + inner div with padding results in an issue where the top/left/bottom padding renders but the right padding inside does not count as overflow as the width of the element is not exceeded. Once the inner div is outside the boundaries of the parent it counts as overflow.
https://stackoverflow.com/questions/60778406/why-is-padding-right-clipped-with-overflowscroll/77292459#77292459
this fixes the issue of right padding clipped off 
"ideal" size in a given axis when given infinite available space--allows the syntax highlighter to grow to largest possible width including its padding
minWidth: "max-content",
*/
 
interface CodeBlockProps {
	source?: string
	forceWrap?: boolean
}
 
const StyledMarkdown = styled.div<{ forceWrap: boolean }>`
	${({ forceWrap }) =>
		forceWrap &&
		`
    pre, code {
      white-space: pre-wrap;
      word-break: break-all;
      overflow-wrap: anywhere;
    }
  `}
 
	pre {
		background-color: ${CODE_BLOCK_BG_COLOR};
		border-radius: 5px;
		margin: 0;
		min-width: ${({ forceWrap }) => (forceWrap ? "auto" : "max-content")};
		padding: 10px 10px;
	}
 
	pre > code {
		.hljs-deletion {
			background-color: var(--vscode-diffEditor-removedTextBackground);
			display: inline-block;
			width: 100%;
		}
		.hljs-addition {
			background-color: var(--vscode-diffEditor-insertedTextBackground);
			display: inline-block;
			width: 100%;
		}
	}
 
	code {
		span.line:empty {
			display: none;
		}
		word-wrap: break-word;
		border-radius: 5px;
		background-color: ${CODE_BLOCK_BG_COLOR};
		font-size: var(--vscode-editor-font-size, var(--vscode-font-size, 12px));
		font-family: var(--vscode-editor-font-family);
	}
 
	code:not(pre > code) {
		font-family: var(--vscode-editor-font-family);
		color: #f78383;
	}
 
	background-color: ${CODE_BLOCK_BG_COLOR};
	font-family:
		var(--vscode-font-family),
		system-ui,
		-apple-system,
		BlinkMacSystemFont,
		"Segoe UI",
		Roboto,
		Oxygen,
		Ubuntu,
		Cantarell,
		"Open Sans",
		"Helvetica Neue",
		sans-serif;
	font-size: var(--vscode-editor-font-size, var(--vscode-font-size, 12px));
	color: var(--vscode-editor-foreground, #fff);
 
	p,
	li,
	ol,
	ul {
		line-height: 1.5;
	}
`
 
const StyledPre = styled.pre<{ theme: any }>`
	& .hljs {
		color: var(--vscode-editor-foreground, #fff);
	}
 
	${(props) =>
		Object.keys(props.theme)
			.map((key, _index) => {
				return `
      & ${key} {
        color: ${props.theme[key]};
      }
    `
			})
			.join("")}
`
 
const CodeBlock = memo(({ source, forceWrap = false }: CodeBlockProps) => {
	const [reactContent, setMarkdownSource] = useRemark({
		remarkPlugins: [
			() => {
				return (tree) => {
					visit(tree, "code", (node: any) => {
						if (!node.lang) {
							node.lang = "javascript"
						} else if (node.lang.includes(".")) {
							// if the language is a file, get the extension
							node.lang = node.lang.split(".").slice(-1)[0]
						}
					})
				}
			},
		],
		rehypePlugins: [
			rehypeHighlight as any,
			{
				// languages: {},
			} as Options,
		],
		rehypeReactOptions: {
			components: {
				pre: ({ node, ...preProps }: any) => <StyledPre {...preProps} />,
			},
		},
	})
 
	useEffect(() => {
		setMarkdownSource(source || "")
	}, [source, setMarkdownSource])
 
	return (
		<div
			style={{
				overflowY: forceWrap ? "visible" : "auto",
				maxHeight: forceWrap ? "none" : "100%",
				backgroundColor: CODE_BLOCK_BG_COLOR,
			}}>
			<StyledMarkdown className="ph-no-capture" forceWrap={forceWrap}>
				{reactContent}
			</StyledMarkdown>
		</div>
	)
})
 
export default CodeBlock