import { printBytecodeOutput, printParserOutput, runCode } from '#editor/runCode' import { EditorState } from '@codemirror/state' import { keymap } from '@codemirror/view' let multilineMode = false const customKeymap = keymap.of([ { key: 'Enter', run: (view) => { if (multilineMode) return false const input = view.state.doc.toString() history.push(input) runCode(input) view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: '' }, selection: { anchor: 0 }, }) return true }, }, { key: 'Shift-Enter', run: (view) => { if (multilineMode) { const input = view.state.doc.toString() runCode(input) return true } multilineMode = true view.dispatch({ changes: { from: view.state.doc.length, insert: '\n' }, selection: { anchor: view.state.doc.length + 1 }, }) return true }, }, { key: 'Tab', preventDefault: true, run: (view) => { return true }, }, { key: 'ArrowUp', run: (view) => { const command = history.previous() if (command === undefined) return false view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: command }, selection: { anchor: command.length }, }) return true }, }, { key: 'ArrowDown', run: (view) => { const command = history.next() if (command === undefined) return false view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: command }, selection: { anchor: command.length }, }) return true }, }, { key: 'Mod-k 1', preventDefault: true, run: (view) => { const input = view.state.doc.toString() printParserOutput(input) return true }, }, { key: 'Mod-k 2', preventDefault: true, run: (view) => { const input = view.state.doc.toString() printBytecodeOutput(input) return true }, }, ]) let firstTime = true const singleLineFilter = EditorState.transactionFilter.of((transaction) => { if (multilineMode) return transaction // Allow everything in multiline mode if (firstTime) { firstTime = false if (transaction.newDoc.toString().includes('\n')) { multilineMode = true return transaction } } transaction.changes.iterChanges((fromA, toA, fromB, toB, inserted) => { if (inserted.toString().includes('\n')) { multilineMode = true return } }) return transaction }) export const shrimpKeymap = [customKeymap, singleLineFilter] class History { private commands: string[] = [] private index: number | undefined push(command: string) { this.commands.push(command) this.index = undefined } previous(): string | undefined { if (this.commands.length === 0) return if (this.index === undefined) { this.index = this.commands.length - 1 } else if (this.index > 0) { this.index -= 1 } return this.commands[this.index] } next(): string | undefined { if (this.commands.length === 0 || this.index === undefined) return if (this.index < this.commands.length - 1) { this.index += 1 return this.commands[this.index] } else { this.index = undefined return '' } } } const history = new History()