Last active
October 8, 2024 07:02
-
-
Save andy0130tw/96172fb589709ce34f80c9618631441e to your computer and use it in GitHub Desktop.
CodeMirror with a search field that is another CodeMirror instance!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { basicSetup, minimalSetup } from 'codemirror' | |
import { Prec } from '@codemirror/state' | |
import { EditorView, keymap, placeholder } from '@codemirror/view' | |
import { search, findNext, findPrevious } from '@codemirror/search' | |
const SearchPanel = (() => { | |
const searchConfigFacet = search({})[0].facet | |
const dummyView = new EditorView({ | |
doc: '', | |
extensions: [search()], | |
}) | |
const config = dummyView.state.facet(searchConfigFacet) | |
const SearchPanel = config.createPanel(dummyView).constructor | |
dummyView.destroy() | |
return SearchPanel | |
})() | |
function enhancedCreatePanel(ext) { | |
return view => { | |
const panel = new SearchPanel(view) | |
console.log(panel) | |
const oldField = panel.searchField | |
// make a new view | |
const outer = document.createElement('div') | |
const editor = new EditorView({ | |
doc: oldField.value, | |
extensions: [ | |
ext, | |
placeholder(oldField.placeholder), | |
EditorView.theme({ | |
'&.cm-editor': { height: 'auto' }, | |
'&.cm-focused': { outlineStyle: 'none !important' }, | |
'.cm-scroller': { overflow: 'hidden' }, | |
'.cm-content': { padding: '0' }, | |
'.cm-line': { paddingLeft: '1px' }, | |
}), | |
// add the original keyup handler | |
EditorView.domEventHandlers({ | |
change: (_e, innerView) => { | |
_latched = true | |
innerView.contentDOM.value = innerView.state.doc.toString() | |
_latched = false | |
panel.commit() | |
}, | |
keyup: (_e, innerView) => { | |
_latched = true | |
innerView.contentDOM.value = innerView.state.doc.toString() | |
_latched = false | |
panel.commit() | |
}, | |
}), | |
// simply disable enter key to break a line | |
Prec.highest(keymap.of([ | |
{key: 'Enter', run: () => true}, | |
])), | |
// TODO: restrict to single line | |
], | |
parent: outer, | |
}) | |
// TODO: add all attributes from old field | |
outer.className = 'cm-textfield' | |
outer.style = `height: fit-content; | |
width: 160px; | |
margin-right: 4px; | |
display: inline-block;` | |
// monkey-patching the field to make it behave like a text field | |
editor.contentDOM.setAttribute('main-field', true) | |
let _value = '' | |
let _latched = false | |
// this is how one create a private property from outside | |
Object.defineProperty(editor.contentDOM, 'value', { | |
get() { return _value }, | |
set(value) { | |
_value = value | |
if (!_latched) | |
editor.dispatch({ changes: { from: 0, to: editor.state.doc.length, insert: value } }) | |
}, | |
}) | |
editor.contentDOM.select = () => { | |
const pos = editor.state.doc.length | |
editor.focus() | |
editor.dispatch({ selection: { anchor: 0, head: pos } }) | |
} | |
oldField.after(outer) | |
oldField.remove() | |
panel.searchField = editor.contentDOM | |
return panel | |
} | |
} | |
new EditorView({ | |
doc: "console.log('hello')\n", | |
extensions: [ | |
basicSetup, | |
search({ | |
createPanel: enhancedCreatePanel([minimalSetup]), | |
}), | |
], | |
parent: document.body, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment