summaryrefslogtreecommitdiff
path: root/extension/react-app/src/components/CodeMultiselect.tsx
diff options
context:
space:
mode:
authorNate Sesti <sestinj@gmail.com>2023-05-23 23:45:12 -0400
committerNate Sesti <sestinj@gmail.com>2023-05-23 23:45:12 -0400
commitf53768612b1e2268697b5444e502032ef9f3fb3c (patch)
tree4ed49b73e6bd3c2f8fceffa9643973033f87af95 /extension/react-app/src/components/CodeMultiselect.tsx
downloadsncontinue-f53768612b1e2268697b5444e502032ef9f3fb3c.tar.gz
sncontinue-f53768612b1e2268697b5444e502032ef9f3fb3c.tar.bz2
sncontinue-f53768612b1e2268697b5444e502032ef9f3fb3c.zip
copying from old repo
Diffstat (limited to 'extension/react-app/src/components/CodeMultiselect.tsx')
-rw-r--r--extension/react-app/src/components/CodeMultiselect.tsx276
1 files changed, 276 insertions, 0 deletions
diff --git a/extension/react-app/src/components/CodeMultiselect.tsx b/extension/react-app/src/components/CodeMultiselect.tsx
new file mode 100644
index 00000000..626ae42f
--- /dev/null
+++ b/extension/react-app/src/components/CodeMultiselect.tsx
@@ -0,0 +1,276 @@
+import React, { useEffect, useState } from "react";
+import styled from "styled-components";
+import { Button, buttonColor, defaultBorderRadius, secondaryDark } from ".";
+import { useSelector } from "react-redux";
+import {
+ selectDebugContext,
+ selectAllRangesInFiles,
+ selectRangesMask,
+} from "../redux/selectors/debugContextSelectors";
+import "../highlight/dark.min.css";
+import hljs from "highlight.js";
+import { postVscMessage } from "../vscode";
+import { RootStore } from "../redux/store";
+import { useDispatch } from "react-redux";
+import {
+ addRangeInFile,
+ deleteRangeInFileAt,
+ toggleSelectionAt,
+ updateFileSystem,
+} from "../redux/slices/debugContexSlice";
+import { RangeInFile } from "../../../src/client";
+import { readRangeInVirtualFileSystem } from "../util";
+
+//#region Styled Components
+
+const MultiSelectContainer = styled.div`
+ border-radius: ${defaultBorderRadius};
+ padding: 4px;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+`;
+
+const MultiSelectHeader = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: left;
+ border-bottom: 1px solid gray;
+ padding-left: 4px;
+ padding-right: 4px;
+ & p {
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ -ms-wrap-flow: break-word;
+ overflow: hidden;
+ }
+`;
+
+const MultiSelectOption = styled.div`
+ border-radius: ${defaultBorderRadius};
+ padding-top: 4px;
+ cursor: pointer;
+ background-color: ${secondaryDark};
+`;
+
+const DeleteSelectedRangeButton = styled(Button)`
+ align-self: right;
+ padding: 0px;
+ margin-top: 0;
+ aspect-ratio: 1/1;
+ height: 28px;
+`;
+
+const ToggleHighlightButton = styled(Button)`
+ display: grid;
+ justify-content: center;
+ align-items: center;
+ grid-template-columns: 30px 1fr;
+ margin-left: 20px;
+ order: 1;
+ width: fit-content;
+`;
+
+//#endregion
+
+//#region Path Formatting
+
+const filenameToLanguageMap: any = {
+ py: "python",
+ js: "javascript",
+ ts: "typescript",
+ html: "html",
+ css: "css",
+ java: "java",
+ c: "c",
+ cpp: "cpp",
+ cs: "csharp",
+ go: "go",
+ rb: "ruby",
+ rs: "rust",
+ swift: "swift",
+ php: "php",
+ scala: "scala",
+ kt: "kotlin",
+ dart: "dart",
+ hs: "haskell",
+ lua: "lua",
+ pl: "perl",
+ r: "r",
+ sql: "sql",
+ vb: "vb",
+ xml: "xml",
+ yaml: "yaml",
+};
+
+function filenameToLanguage(filename: string): string {
+ const extension = filename.split(".").pop();
+ if (extension === undefined) {
+ return "";
+ }
+ return filenameToLanguageMap[extension] || "";
+}
+
+function formatPathRelativeToWorkspace(
+ path: string,
+ workspacePath: string | undefined
+) {
+ if (workspacePath === undefined) {
+ return path;
+ }
+ if (path.startsWith(workspacePath)) {
+ return path.substring(workspacePath.length + 1);
+ } else {
+ return path;
+ }
+}
+
+function formatFileRange(
+ rangeInFile: RangeInFile,
+ workspacePath: string | undefined
+) {
+ return `${formatPathRelativeToWorkspace(
+ rangeInFile.filepath,
+ workspacePath
+ )} (lines ${rangeInFile.range.start.line + 1}-${
+ rangeInFile.range.end.line + 1
+ })`;
+ // +1 because VSCode Ranges are 0-indexed
+}
+
+//#endregion
+
+function CodeMultiselect(props: {}) {
+ // State
+ const [highlightLocked, setHighlightLocked] = useState(true);
+
+ // Redux
+ const dispatch = useDispatch();
+ const workspacePath = useSelector(
+ (state: RootStore) => state.config.workspacePath
+ );
+ const debugContext = useSelector(selectDebugContext);
+ const rangesInFiles = useSelector(selectAllRangesInFiles);
+ const rangesInFilesMask = useSelector(selectRangesMask);
+
+ useEffect(() => {
+ let eventListener = (event: any) => {
+ switch (event.data.type) {
+ case "highlightedCode":
+ if (!highlightLocked) {
+ dispatch(
+ addRangeInFile({
+ rangeInFile: event.data.rangeInFile,
+ canUpdateLast: true,
+ })
+ );
+ dispatch(updateFileSystem(event.data.filesystem));
+ }
+ break;
+ case "findSuspiciousCode":
+ for (let c of event.data.codeLocations) {
+ dispatch(addRangeInFile({ rangeInFile: c, canUpdateLast: false }));
+ }
+ dispatch(updateFileSystem(event.data.filesystem));
+ postVscMessage("listTenThings", { debugContext });
+ break;
+ }
+ };
+ window.addEventListener("message", eventListener);
+ return () => window.removeEventListener("message", eventListener);
+ }, [debugContext, highlightLocked]);
+
+ useEffect(() => {
+ hljs.highlightAll();
+ }, [rangesInFiles]);
+
+ return (
+ <MultiSelectContainer>
+ {rangesInFiles.map((range: RangeInFile, index: number) => {
+ return (
+ <MultiSelectOption
+ key={index}
+ style={{
+ border: `1px solid ${
+ rangesInFilesMask[index] ? buttonColor : "gray"
+ }`,
+ }}
+ onClick={() => {
+ dispatch(toggleSelectionAt(index));
+ }}
+ >
+ <MultiSelectHeader>
+ <p style={{ margin: "4px" }}>
+ {formatFileRange(range, workspacePath)}
+ </p>
+ <DeleteSelectedRangeButton
+ onClick={() => dispatch(deleteRangeInFileAt(index))}
+ >
+ x
+ </DeleteSelectedRangeButton>
+ </MultiSelectHeader>
+ <pre>
+ <code
+ className={"language-" + filenameToLanguage(range.filepath)}
+ >
+ {readRangeInVirtualFileSystem(range, debugContext.filesystem)}
+ </code>
+ </pre>
+ </MultiSelectOption>
+ );
+ })}
+ {rangesInFiles.length === 0 && (
+ <>
+ <p>Highlight relevant code in the editor.</p>
+ </>
+ )}
+ <ToggleHighlightButton
+ onClick={() => {
+ setHighlightLocked(!highlightLocked);
+ }}
+ >
+ {highlightLocked ? (
+ <>
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="20px"
+ fill="none"
+ viewBox="0 0 24 24"
+ strokeWidth="1.5"
+ stroke="currentColor"
+ className="w-6 h-6"
+ >
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z"
+ />
+ </svg>{" "}
+ Enable Highlight
+ </>
+ ) : (
+ <>
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="20px"
+ fill="none"
+ viewBox="0 0 24 24"
+ strokeWidth="1.5"
+ stroke="currentColor"
+ className="w-6 h-6"
+ >
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ d="M13.5 10.5V6.75a4.5 4.5 0 119 0v3.75M3.75 21.75h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H3.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z"
+ />
+ </svg>{" "}
+ Disable Highlight
+ </>
+ )}
+ </ToggleHighlightButton>
+ </MultiSelectContainer>
+ );
+}
+
+export default CodeMultiselect;