159 lines
3.3 KiB
TypeScript
159 lines
3.3 KiB
TypeScript
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()
|