diff --git a/src/components/SourceViewer/SourceViewer.tsx b/src/components/SourceViewer/SourceViewer.tsx index a05d11a..5be1d70 100644 --- a/src/components/SourceViewer/SourceViewer.tsx +++ b/src/components/SourceViewer/SourceViewer.tsx @@ -1,7 +1,147 @@ import React from "react"; import Highlight, { defaultProps } from "prism-react-renderer"; +import { + TgetLineProps, + TgetTokenProps, + StyleObj, + Token, +} from "../../types/prism-types"; + import { sourceMapping } from "../../logic/sourceMapping"; +import { + completionMapping, + ICompletionDetail, +} from "../../logic/completionMapping"; + +function getCompletionFromSourceToken( + matcheeToken: Token +): ICompletionDetail | null { + const matchingSourceDetails = sourceMapping.mappingArray.find( + ({ token: tmpToken }) => matcheeToken === tmpToken + ); + if (matchingSourceDetails === undefined) { + return null; + } + + const { start: sourceStart, end: sourceEnd } = matchingSourceDetails; + + let closestCompletion: ICompletionDetail | null = null; + let closestMatchScore = -Infinity; + + completionMapping.completionDetails.forEach((tmpCompletionDetails) => { + const { start: compStart, end: compEnd } = tmpCompletionDetails; + const sourceLen = sourceEnd - sourceStart; + const compLen = compEnd - compStart; + + // If not intersecting at all, ignore + if (compEnd < sourceStart || compStart > sourceEnd) { + return; + } + + const intersectionStart = Math.max(sourceStart, compStart); + const intersectionEnd = Math.min(sourceEnd, compEnd); + + const intersectionDistance = intersectionEnd - intersectionStart; + // Exclusion = Total Len - (2 * intersection) + const exclusionDistance = sourceLen + compLen - intersectionDistance; + + const score = intersectionDistance - exclusionDistance; + if (score >= closestMatchScore) { + closestCompletion = tmpCompletionDetails; + closestMatchScore = score; + } + }); + + return closestCompletion; +} + +interface IPreRendererProps { + className: string; + style: StyleObj; + tokens: Token[][]; + getLineProps: TgetLineProps; + getTokenProps: TgetTokenProps; +} +function PreRenderer({ + className, + style, + tokens, + getLineProps, + getTokenProps, +}: IPreRendererProps) { + sourceMapping.reset(); + return ( +
+      {tokens.map((line, i) => (
+        
+      ))}
+    
+ ); +} + +interface ILineRendererProps { + line: Token[]; + getLineProps: TgetLineProps; + getTokenProps: TgetTokenProps; +} +function LineRenderer({ + line, + getLineProps, + getTokenProps, +}: ILineRendererProps) { + return ( +
+ {/* Refactor into TokenRenderer */} + {line.map((token, i) => ( + + ))} +
+ ); +} + +interface ITokenRendererProps { + token: Token; + isLastTokenInLine: boolean; + getTokenProps: TgetTokenProps; +} +function TokenRenderer({ + token, + isLastTokenInLine, + getTokenProps, +}: ITokenRendererProps) { + const refFn = sourceMapping.registerToken(token); + if (isLastTokenInLine) { + sourceMapping.registerLineEnd(); + } + + const onClickToken = (tmpToken: Token) => { + const matchingCompletion = getCompletionFromSourceToken(tmpToken); + if (matchingCompletion !== null) { + console.log( + `Clicked: ${tmpToken.content} => Completion (${matchingCompletion.completionType},${matchingCompletion.completionValueString})` + ); + } + }; + + return ( + onClickToken(token)} + /> + ); +} interface ISourceViewerProps { code: string; @@ -10,6 +150,7 @@ interface ISourceViewerProps { export function SourceViewer(props: ISourceViewerProps) { const { code } = props; + return (
{/* Title of code section */} @@ -17,26 +158,9 @@ export function SourceViewer(props: ISourceViewerProps) { {/* Code viewer */} {({ className, style, tokens, getLineProps, getTokenProps }) => ( - // eslint-disable-next-line no-sequences - sourceMapping.reset(), - ( -
-              {tokens.map((line, i) => (
-                
- {line.map(function (token, key) { - const refFn = sourceMapping.registerToken(token); - return ( - - ); - })} - {(sourceMapping.registerLineEnd(), null)} -
- ))} -
- ) + )}