diff --git a/package.json b/package.json index 33fa8dd..908d59e 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "circom2": "^0.2.2", "ffjavascript": "0.2.48", "monaco-editor": "^0.30.1", + "monaco-vim": "^0.3.4", "patch-package": "^6.4.7", "path-browserify": "^1.0.1", "r1csfile": "0.0.35", diff --git a/src/editor.less b/src/editor.less index f57d0c2..bf7a22f 100644 --- a/src/editor.less +++ b/src/editor.less @@ -1,12 +1,10 @@ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; -} - -body { background: #202030; color: white; } + a { color: white; text-decoration: none; @@ -20,6 +18,7 @@ a { } .primary { + position: relative; width: 70vw; height: 100vh; display: flex; @@ -32,6 +31,53 @@ a { flex: 1; } +.toolbar { + display: flex; + flex-basis: 30px; + align-items: center; + justify-content: right; + + .button { + cursor: pointer; + padding: 5px; + color: #9e9e9e; + } + + .button:hover, + .button.active { + color: #525252; + } +} + +.statusbar, +.statusbar input { + font-family: "Courier New", Courier, monospace; + font-size: 15px; + color: gray; +} + +.statusbar { + z-index: 1; + position: absolute; + bottom: 31px; + width: 100%; + height: 30px; + border-top: 1px solid #ddd; + align-items: center; + padding: 5px; + background: white; + + div { + width: 100%; + + input { + outline: none; + border: none; + background: transparent; + } + } +} + code { font-family: inherit; font-size: small; @@ -45,14 +91,6 @@ body { display: flex; } -.sidebar { - flex: 1; - height: 100vh; - width: 0; - display: flex; - flex-direction: column; -} - .heading { background: #303052; color: white; @@ -70,12 +108,16 @@ body { height: 30px; } } + .hidden-file { position: absolute; top: -1000px; left: -1000px; } + .sidebar { + display: flex; + flex-direction: column; flex: 1; white-space: pre-wrap; word-wrap: break-word; @@ -95,13 +137,14 @@ body { font-size: small; text-transform: uppercase; } - .files, .insecure { + .files, + .insecure { font-size: small; padding-left: 20px; padding-bottom: 10px; } .insecure { - color: #ff9800 + color: #ff9800; } .file { &:hover { @@ -245,6 +288,7 @@ button { .editor { border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; } .embed-snippet { diff --git a/src/editor.tsx b/src/editor.tsx index 6443c3f..419fd33 100644 --- a/src/editor.tsx +++ b/src/editor.tsx @@ -1,5 +1,7 @@ -import React from "react" - +import Ansi from "ansi-to-react" +// this is a workaround for what seems to be some kind of bug around +// importing raw urls from webworkers in production builds +import wasmURL from "circom2/circom.wasm?url" import "monaco-editor/esm/vs/editor/browser/controller/coreCommands.js" // import 'monaco-editor/esm/vs/editor/browser/widget/codeEditorWidget.js'; // import 'monaco-editor/esm/vs/editor/browser/widget/diffEditorWidget.js'; @@ -32,6 +34,7 @@ import "monaco-editor/esm/vs/editor/contrib/indentation/indentation.js" // import 'monaco-editor/esm/vs/editor/contrib/linkedEditing/linkedEditing.js'; // import 'monaco-editor/esm/vs/editor/contrib/links/links.js'; import "monaco-editor/esm/vs/editor/contrib/multicursor/multicursor.js" +import * as monaco from "monaco-editor/esm/vs/editor/editor.api" // import 'monaco-editor/esm/vs/editor/contrib/parameterHints/parameterHints.js'; // import 'monaco-editor/esm/vs/editor/contrib/rename/rename.js'; // import 'monaco-editor/esm/vs/editor/contrib/smartSelect/smartSelect.js'; @@ -45,6 +48,10 @@ import "monaco-editor/esm/vs/editor/contrib/multicursor/multicursor.js" // import 'monaco-editor/esm/vs/editor/contrib/wordPartOperations/wordPartOperations.js'; // import 'monaco-editor/esm/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.js'; import "monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.js" +import { initVimMode } from "monaco-vim" +import React from "react" +import circomLib from "./data/circomlib.zip?url" +import codeExample from "./data/example.circom?raw" // import 'monaco-editor/esm/vs/editor/standalone/browser/inspectTokens/inspectTokens.js'; // import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.js'; // import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.js'; @@ -52,20 +59,10 @@ import "monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShow // import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.js'; // import 'monaco-editor/esm/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.js'; // import 'monaco-editor/esm/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.js'; - import "./syntax" -import codeExample from "./data/example.circom?raw" +import { replyHover } from "./syntax" import CircomWorker from "./worker/worker?worker" -import Ansi from "ansi-to-react" - -import * as monaco from "monaco-editor/esm/vs/editor/editor.api" - -// this is a workaround for what seems to be some kind of bug around -// importing raw urls from webworkers in production builds -import wasmURL from "circom2/circom.wasm?url" -import circomLib from "./data/circomlib.zip?url" -import { replyHover } from "./syntax" console.log(circomLib, wasmURL) type Message = { @@ -82,8 +79,10 @@ export default function App() { const [messages, setMessages] = React.useState([]) const [editor, setEditor] = React.useState(null) + const [vimMode, setVimMode] = React.useState() const modelsRef = React.useRef([]) const monacoEl = React.useRef(null) + const statusBarEl = React.useRef(null) const workerRef = React.useRef<(Worker & { running?: boolean }) | null>( null ) @@ -260,7 +259,7 @@ export default function App() { } } React.useEffect(() => { - if (monacoEl && !editor) { + if (monacoEl && statusBarEl && !editor) { const editor = monaco.editor.create(monacoEl.current!, { language: "circom", theme: "vs", @@ -345,11 +344,18 @@ export default function App() { }) run() } + setEditor(editor) + + if (localStorage.getItem("vim-editor")) { + const vimMode = initVimMode(editor, statusBarEl.current) + + setVimMode(vimMode) + } } return () => editor?.dispose() - }, [monacoEl.current]) + }, [monacoEl.current, statusBarEl.current]) const switchEditor = (file: monaco.editor.ITextModel) => { const saveState = editor?.saveViewState() @@ -500,12 +506,47 @@ export default function App() {
+ +
+
+
+ +
+
{ + if (!vimMode) { + const vimMode = initVimMode( + editor, + statusBarEl.current + ) + + localStorage.setItem("vim-editor", "true") + + setVimMode(vimMode) + } else { + vimMode.dispose() + + localStorage.removeItem("vim-editor") + + setVimMode(null) + } + }} + className={!vimMode ? "button" : "button active"} + > + VIM +
+
- Shift-Enter to{" "} + CMD-Enter to{" "} { diff --git a/src/zkrepl.d.ts b/src/zkrepl.d.ts index 38e9339..cb30a20 100644 --- a/src/zkrepl.d.ts +++ b/src/zkrepl.d.ts @@ -105,6 +105,10 @@ declare module "r1csfile" { ): Promise } +declare module "monaco-vim" { + export function initVimMode(editor: any, statusBarClass: any): void +} + declare module "ffjavascript" { export const Scalar: any } diff --git a/yarn.lock b/yarn.lock index b15a79c..132dcb2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1062,6 +1062,11 @@ monaco-editor@^0.30.1: resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.30.1.tgz#47f8d18a0aa2264fc5654581741ab8d7bec01689" integrity sha512-B/y4+b2O5G2gjuxIFtCE2EkM17R2NM7/3F8x0qcPsqy4V83bitJTIO4TIeZpYlzu/xy6INiY/+84BEm6+7Cmzg== +monaco-vim@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/monaco-vim/-/monaco-vim-0.3.4.tgz#141d3e1129a563e63a7286a1472ccfe72b758abe" + integrity sha512-IVogmrQ6fRwW2PD9XRHFysOZBFj8qcRhgabu7GlGiNR14ApKMHz3pYOL1hDq1ctVPj1DS6hZd98vZrFxWr5d6A== + ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"