Skip to content

Commit

Permalink
Merge pull request #45 from githubnext/aw/edit-block
Browse files Browse the repository at this point in the history
add edit code block
  • Loading branch information
Wattenberger authored Apr 20, 2022
2 parents 7554114 + 1939238 commit 30404b6
Show file tree
Hide file tree
Showing 4 changed files with 357 additions and 3 deletions.
19 changes: 18 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,21 @@
],
"example_path": "https://github.com/mattdesl/canvas-sketch/blob/master/lib/save.js"
},
{
"type": "file",
"id": "edit-block",
"title": "Edit code",
"description": "Edit code by prompting a Machine Learning model",
"sandbox": false,
"entry": "/src/blocks/file-blocks/edit/index.tsx",
"extensions": [
"*"
],
"matches": [
"*"
],
"example_path": "https://github.com/githubnext/blocks-tutorial/blob/main/processing-sketch.js"
},
{
"type": "folder",
"id": "minimap-block",
Expand Down Expand Up @@ -424,6 +439,7 @@
"p5": "^1.4.1",
"papaparse": "^5.3.1",
"react": "^17.0.0",
"react-diff-view": "^2.4.8",
"react-dom": "^17.0.0",
"react-error-boundary": "^3.1.4",
"react-image-annotation": "^0.9.10",
Expand All @@ -436,7 +452,8 @@
"recharts": "^2.1.6",
"rlayers": "^1.3.2",
"styled-components": "^5.3.3",
"three": "^0.134.0"
"three": "^0.134.0",
"unidiff": "^1.0.2"
},
"resolutions": {
"react": "17.0.0",
Expand Down
114 changes: 114 additions & 0 deletions src/blocks/file-blocks/edit/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
.hljs {
color: #24292e;
background: #ffffff;
}

.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
/* prettylights-syntax-keyword */
color: #d73a49;
}

.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
/* prettylights-syntax-entity */
color: #6f42c1;
}

.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-variable,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id {
/* prettylights-syntax-constant */
color: #005cc5;
}

.hljs-regexp,
.hljs-string,
.hljs-meta .hljs-string {
/* prettylights-syntax-string */
color: #032f62;
}

.hljs-built_in,
.hljs-symbol {
/* prettylights-syntax-variable */
color: #e36209;
}

.hljs-comment,
.hljs-code,
.hljs-formula {
/* prettylights-syntax-comment */
color: #6a737d;
}

.hljs-name,
.hljs-quote,
.hljs-selector-tag,
.hljs-selector-pseudo {
/* prettylights-syntax-entity-tag */
color: #22863a;
}

.hljs-subst {
/* prettylights-syntax-storage-modifier-import */
color: #24292e;
}

.hljs-section {
/* prettylights-syntax-markup-heading */
color: #005cc5;
font-weight: bold;
}

.hljs-bullet {
/* prettylights-syntax-markup-list */
color: #735c0f;
}

.hljs-emphasis {
/* prettylights-syntax-markup-italic */
color: #24292e;
font-style: italic;
}

.hljs-strong {
/* prettylights-syntax-markup-bold */
color: #24292e;
font-weight: bold;
}

.hljs-addition {
/* prettylights-syntax-markup-inserted */
color: #22863a;
background-color: #f0fff4;
}

.hljs-deletion {
/* prettylights-syntax-markup-deleted */
color: #b31d28;
background-color: #ffeef0;
}

.hljs-char.escape_,
.hljs-link,
.hljs-params,
.hljs-property,
.hljs-punctuation,
.hljs-tag {
/* purposely ignored */
}
191 changes: 191 additions & 0 deletions src/blocks/file-blocks/edit/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { FileBlockProps, getLanguageFromFilename } from "@githubnext/utils";
import { RocketIcon } from "@primer/octicons-react";
import axios from "axios";
import { useMemo, useState } from "react";
import { Hunk, parseDiff } from "react-diff-view";
import "react-diff-view/style/index.css";
import SyntaxHighlighter from "react-syntax-highlighter";
import { diffAsText } from "unidiff";
import "./index.css";

export default function (props: FileBlockProps) {
const { content, context, onRequestUpdateContent } = props;

const [instruction, setInstruction] = useState<string>("");
const [newContent, setNewContent] = useState<string>("");
const [isLoading, setIsLoading] = useState<boolean>(false);

const language = getLanguageFromFilename(context.path.split("/").pop() || "");

const hunks = useMemo(() => {
if (!newContent) return [];
const hunks = parseDiff(
diffAsText(content, newContent, {
context: 100,
}),
{
nearbySequences: "zip",
}
);

return hunks;
}, [content, newContent]);

return (
<div
id="example-block-summarize-block"
className="h-full w-full relative grid grid-cols-2 gap-2 grid-rows-[7em,1fr]"
>
<form
className={`relative px-5 py-2 flex flex-col justify-end ${
isLoading ? "opacity-50 cursor-default" : ""
}`}
onSubmit={async (e) => {
e.preventDefault();
setIsLoading(true);
const res = await axios.post("/api/openai-edit", {
instruction: instruction,
input: content,
});
setNewContent(res.data);
setIsLoading(false);
}}
>
<label className="font-normal">
How would you like to edit this code?
</label>
<div className="flex items-center mt-1">
<input
className="w-full p-2 form-control"
type="text"
value={instruction}
disabled={isLoading}
onChange={(e) => {
setInstruction(e.target.value);
}}
/>
<button disabled={isLoading} className="btn ml-1 self-stretch">
{newContent ? "Re-generate modified code" : "Get modified code"}
<span className="ml-2">
<RocketIcon />
</span>
</button>
</div>
</form>

<div className="flex items-end px-5 py-2">
{newContent && (
<div className="w-full flex justify-between">
<div className="text-gray-500">Proposed code</div>
<button
className="btn btn-primary"
onClick={() => {
onRequestUpdateContent(newContent);
}}
>
Save changes
</button>
</div>
)}
</div>

{newContent ? (
<div className="col-span-2">
<div className="w-full">
{hunks?.[0]?.hunks?.map((hunk: Hunk) => (
<HunkComponent
key={hunk.content}
hunk={hunk}
language={language}
/>
))}
</div>
</div>
) : (
<pre className="px-5 py-3 text-left">
<SyntaxHighlighter
language={syntaxHighlighterLanguageMap[language] || "javascript"}
useInlineStyles={false}
showLineNumbers={false}
lineNumberStyle={{ opacity: 0.45 }}
className="!bg-transparent"
wrapLines
wrapLongLines
>
{content}
</SyntaxHighlighter>
</pre>
)}
</div>
);
}

const syntaxHighlighterLanguageMap = {
JavaScript: "javascript",
TypeScript: "typescript",
} as Record<string, string>;

const HunkComponent = ({ hunk, language }: { hunk: any; language: string }) => {
return (
<pre className="px-5 py-3 text-left">
{hunk.changes.map((change: Hunk["change"], i: number) => (
<Change key={i} change={change} language={language} />
))}
</pre>
);
};

const Change = ({ change, language }: { change: Hunk; language: string }) => {
return (
<div className="grid grid-cols-2">
<SyntaxHighlighter
language={syntaxHighlighterLanguageMap[language] || "javascript"}
useInlineStyles={false}
showLineNumbers={change.type !== "insert"}
startingLineNumber={change.oldLineNumber || change.lineNumber}
lineNumberStyle={{
width: "3em",
textAlign: "right",
marginRight: "0.3em",
color: change.type === "normal" ? "#6e7781" : "#24292f",
background: change.type === "delete" ? "#FFD7D5" : "",
}}
className={`!bg-transparent ${
{
delete: "!bg-[#FFEBE9]",
insert: "!bg-[#F5F6F8]",
}[change.type as string] || ""
}`}
wrapLines
wrapLongLines
>
{(change.type === "delete" ? "- " : " ") +
(change.type === "insert" ? " " : change.content || " ")}
</SyntaxHighlighter>
<SyntaxHighlighter
language={syntaxHighlighterLanguageMap[language] || "javascript"}
useInlineStyles={false}
showLineNumbers={change.type !== "delete"}
startingLineNumber={change.newLineNumber || change.lineNumber}
lineNumberStyle={{
width: "3em",
textAlign: "right",
marginRight: "0.3em",
color: change.type === "normal" ? "#6e7781" : "#24292f",
background: change.type === "insert" ? "#CCFFD8" : "",
}}
className={`!bg-transparent ${
{
delete: "!bg-[#F5F6F8]",
insert: "!bg-[#E6FFEC]",
}[change.type as string] || ""
}`}
wrapLines
wrapLongLines
>
{(change.type === "insert" ? "+ " : " ") +
(change.type === "delete" ? " " : change.content || " ")}
</SyntaxHighlighter>
</div>
);
};
Loading

0 comments on commit 30404b6

Please sign in to comment.