From c4e8cf7fce118f48c68d5835291e0439f6ea57c6 Mon Sep 17 00:00:00 2001 From: bendtherules Date: Mon, 5 Oct 2020 20:45:19 +0530 Subject: [PATCH] refactor(source): SourceViewer - Break highlight nested children into separate components Add separate component for
, line and token renderer. Hierarchy is Pre > Line > Token
---
 src/components/SourceViewer/SourceViewer.tsx | 164 ++++++++++++++++---
 1 file changed, 144 insertions(+), 20 deletions(-)

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)} -
- ))} -
- ) + )}