Fix bin/publish: copy docs.dist from project root

Fix bin/publish: use correct .env path for rspade_system
Fix bin/publish script: prevent grep exit code 1 from terminating script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-10-21 02:08:33 +00:00
commit f6fac6c4bc
79758 changed files with 10547827 additions and 0 deletions

546
node_modules/codemirror/src/input/ContentEditableInput.js generated vendored Executable file
View File

@@ -0,0 +1,546 @@
import { operation, runInOp } from "../display/operations.js"
import { prepareSelection } from "../display/selection.js"
import { regChange } from "../display/view_tracking.js"
import { applyTextInput, copyableRanges, disableBrowserMagic, handlePaste, hiddenTextarea, lastCopied, setLastCopied } from "./input.js"
import { cmp, maxPos, minPos, Pos } from "../line/pos.js"
import { getBetween, getLine, lineNo } from "../line/utils_line.js"
import { findViewForLine, findViewIndex, mapFromLineView, nodeAndOffsetInLineMap } from "../measurement/position_measurement.js"
import { replaceRange } from "../model/changes.js"
import { simpleSelection } from "../model/selection.js"
import { setSelection } from "../model/selection_updates.js"
import { getBidiPartAt, getOrder } from "../util/bidi.js"
import { android, chrome, gecko, ie_version } from "../util/browser.js"
import { activeElt, contains, range, removeChildrenAndAdd, selectInput, rootNode } from "../util/dom.js"
import { on, signalDOMEvent } from "../util/event.js"
import { Delayed, lst, sel_dontScroll } from "../util/misc.js"
// CONTENTEDITABLE INPUT STYLE
export default class ContentEditableInput {
constructor(cm) {
this.cm = cm
this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null
this.polling = new Delayed()
this.composing = null
this.gracePeriod = false
this.readDOMTimeout = null
}
init(display) {
let input = this, cm = input.cm
let div = input.div = display.lineDiv
div.contentEditable = true
disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize)
function belongsToInput(e) {
for (let t = e.target; t; t = t.parentNode) {
if (t == div) return true
if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) break
}
return false
}
on(div, "paste", e => {
if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) return
// IE doesn't fire input events, so we schedule a read for the pasted content in this way
if (ie_version <= 11) setTimeout(operation(cm, () => this.updateFromDOM()), 20)
})
on(div, "compositionstart", e => {
this.composing = {data: e.data, done: false}
})
on(div, "compositionupdate", e => {
if (!this.composing) this.composing = {data: e.data, done: false}
})
on(div, "compositionend", e => {
if (this.composing) {
if (e.data != this.composing.data) this.readFromDOMSoon()
this.composing.done = true
}
})
on(div, "touchstart", () => input.forceCompositionEnd())
on(div, "input", () => {
if (!this.composing) this.readFromDOMSoon()
})
function onCopyCut(e) {
if (!belongsToInput(e) || signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) {
setLastCopied({lineWise: false, text: cm.getSelections()})
if (e.type == "cut") cm.replaceSelection("", null, "cut")
} else if (!cm.options.lineWiseCopyCut) {
return
} else {
let ranges = copyableRanges(cm)
setLastCopied({lineWise: true, text: ranges.text})
if (e.type == "cut") {
cm.operation(() => {
cm.setSelections(ranges.ranges, 0, sel_dontScroll)
cm.replaceSelection("", null, "cut")
})
}
}
if (e.clipboardData) {
e.clipboardData.clearData()
let content = lastCopied.text.join("\n")
// iOS exposes the clipboard API, but seems to discard content inserted into it
e.clipboardData.setData("Text", content)
if (e.clipboardData.getData("Text") == content) {
e.preventDefault()
return
}
}
// Old-fashioned briefly-focus-a-textarea hack
let kludge = hiddenTextarea(), te = kludge.firstChild
disableBrowserMagic(te)
cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild)
te.value = lastCopied.text.join("\n")
let hadFocus = activeElt(rootNode(div))
selectInput(te)
setTimeout(() => {
cm.display.lineSpace.removeChild(kludge)
hadFocus.focus()
if (hadFocus == div) input.showPrimarySelection()
}, 50)
}
on(div, "copy", onCopyCut)
on(div, "cut", onCopyCut)
}
screenReaderLabelChanged(label) {
// Label for screenreaders, accessibility
if(label) {
this.div.setAttribute('aria-label', label)
} else {
this.div.removeAttribute('aria-label')
}
}
prepareSelection() {
let result = prepareSelection(this.cm, false)
result.focus = activeElt(rootNode(this.div)) == this.div
return result
}
showSelection(info, takeFocus) {
if (!info || !this.cm.display.view.length) return
if (info.focus || takeFocus) this.showPrimarySelection()
this.showMultipleSelections(info)
}
getSelection() {
return this.cm.display.wrapper.ownerDocument.getSelection()
}
showPrimarySelection() {
let sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary()
let from = prim.from(), to = prim.to()
if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
sel.removeAllRanges()
return
}
let curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
let curFocus = domToPos(cm, sel.focusNode, sel.focusOffset)
if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
cmp(minPos(curAnchor, curFocus), from) == 0 &&
cmp(maxPos(curAnchor, curFocus), to) == 0)
return
let view = cm.display.view
let start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
{node: view[0].measure.map[2], offset: 0}
let end = to.line < cm.display.viewTo && posToDOM(cm, to)
if (!end) {
let measure = view[view.length - 1].measure
let map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map
end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}
}
if (!start || !end) {
sel.removeAllRanges()
return
}
let old = sel.rangeCount && sel.getRangeAt(0), rng
try { rng = range(start.node, start.offset, end.offset, end.node) }
catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
if (rng) {
if (!gecko && cm.state.focused) {
sel.collapse(start.node, start.offset)
if (!rng.collapsed) {
sel.removeAllRanges()
sel.addRange(rng)
}
} else {
sel.removeAllRanges()
sel.addRange(rng)
}
if (old && sel.anchorNode == null) sel.addRange(old)
else if (gecko) this.startGracePeriod()
}
this.rememberSelection()
}
startGracePeriod() {
clearTimeout(this.gracePeriod)
this.gracePeriod = setTimeout(() => {
this.gracePeriod = false
if (this.selectionChanged())
this.cm.operation(() => this.cm.curOp.selectionChanged = true)
}, 20)
}
showMultipleSelections(info) {
removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors)
removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection)
}
rememberSelection() {
let sel = this.getSelection()
this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset
this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset
}
selectionInEditor() {
let sel = this.getSelection()
if (!sel.rangeCount) return false
let node = sel.getRangeAt(0).commonAncestorContainer
return contains(this.div, node)
}
focus() {
if (this.cm.options.readOnly != "nocursor") {
if (!this.selectionInEditor() || activeElt(rootNode(this.div)) != this.div)
this.showSelection(this.prepareSelection(), true)
this.div.focus()
}
}
blur() { this.div.blur() }
getField() { return this.div }
supportsTouch() { return true }
receivedFocus() {
let input = this
if (this.selectionInEditor())
setTimeout(() => this.pollSelection(), 20)
else
runInOp(this.cm, () => input.cm.curOp.selectionChanged = true)
function poll() {
if (input.cm.state.focused) {
input.pollSelection()
input.polling.set(input.cm.options.pollInterval, poll)
}
}
this.polling.set(this.cm.options.pollInterval, poll)
}
selectionChanged() {
let sel = this.getSelection()
return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
}
pollSelection() {
if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) return
let sel = this.getSelection(), cm = this.cm
// On Android Chrome (version 56, at least), backspacing into an
// uneditable block element will put the cursor in that element,
// and then, because it's not editable, hide the virtual keyboard.
// Because Android doesn't allow us to actually detect backspace
// presses in a sane way, this code checks for when that happens
// and simulates a backspace press in this case.
if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) {
this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs})
this.blur()
this.focus()
return
}
if (this.composing) return
this.rememberSelection()
let anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
let head = domToPos(cm, sel.focusNode, sel.focusOffset)
if (anchor && head) runInOp(cm, () => {
setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll)
if (anchor.bad || head.bad) cm.curOp.selectionChanged = true
})
}
pollContent() {
if (this.readDOMTimeout != null) {
clearTimeout(this.readDOMTimeout)
this.readDOMTimeout = null
}
let cm = this.cm, display = cm.display, sel = cm.doc.sel.primary()
let from = sel.from(), to = sel.to()
if (from.ch == 0 && from.line > cm.firstLine())
from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length)
if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
to = Pos(to.line + 1, 0)
if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false
let fromIndex, fromLine, fromNode
if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
fromLine = lineNo(display.view[0].line)
fromNode = display.view[0].node
} else {
fromLine = lineNo(display.view[fromIndex].line)
fromNode = display.view[fromIndex - 1].node.nextSibling
}
let toIndex = findViewIndex(cm, to.line)
let toLine, toNode
if (toIndex == display.view.length - 1) {
toLine = display.viewTo - 1
toNode = display.lineDiv.lastChild
} else {
toLine = lineNo(display.view[toIndex + 1].line) - 1
toNode = display.view[toIndex + 1].node.previousSibling
}
if (!fromNode) return false
let newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine))
let oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length))
while (newText.length > 1 && oldText.length > 1) {
if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- }
else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ }
else break
}
let cutFront = 0, cutEnd = 0
let newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length)
while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
++cutFront
let newBot = lst(newText), oldBot = lst(oldText)
let maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
oldBot.length - (oldText.length == 1 ? cutFront : 0))
while (cutEnd < maxCutEnd &&
newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
++cutEnd
// Try to move start of change to start of selection if ambiguous
if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
while (cutFront && cutFront > from.ch &&
newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
cutFront--
cutEnd++
}
}
newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "")
newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "")
let chFrom = Pos(fromLine, cutFront)
let chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0)
if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
replaceRange(cm.doc, newText, chFrom, chTo, "+input")
return true
}
}
ensurePolled() {
this.forceCompositionEnd()
}
reset() {
this.forceCompositionEnd()
}
forceCompositionEnd() {
if (!this.composing) return
clearTimeout(this.readDOMTimeout)
this.composing = null
this.updateFromDOM()
this.div.blur()
this.div.focus()
}
readFromDOMSoon() {
if (this.readDOMTimeout != null) return
this.readDOMTimeout = setTimeout(() => {
this.readDOMTimeout = null
if (this.composing) {
if (this.composing.done) this.composing = null
else return
}
this.updateFromDOM()
}, 80)
}
updateFromDOM() {
if (this.cm.isReadOnly() || !this.pollContent())
runInOp(this.cm, () => regChange(this.cm))
}
setUneditable(node) {
node.contentEditable = "false"
}
onKeyPress(e) {
if (e.charCode == 0 || this.composing) return
e.preventDefault()
if (!this.cm.isReadOnly())
operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0)
}
readOnlyChanged(val) {
this.div.contentEditable = String(val != "nocursor")
}
onContextMenu() {}
resetPosition() {}
}
ContentEditableInput.prototype.needsContentAttribute = true
function posToDOM(cm, pos) {
let view = findViewForLine(cm, pos.line)
if (!view || view.hidden) return null
let line = getLine(cm.doc, pos.line)
let info = mapFromLineView(view, line, pos.line)
let order = getOrder(line, cm.doc.direction), side = "left"
if (order) {
let partPos = getBidiPartAt(order, pos.ch)
side = partPos % 2 ? "right" : "left"
}
let result = nodeAndOffsetInLineMap(info.map, pos.ch, side)
result.offset = result.collapse == "right" ? result.end : result.start
return result
}
function isInGutter(node) {
for (let scan = node; scan; scan = scan.parentNode)
if (/CodeMirror-gutter-wrapper/.test(scan.className)) return true
return false
}
function badPos(pos, bad) { if (bad) pos.bad = true; return pos }
function domTextBetween(cm, from, to, fromLine, toLine) {
let text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false
function recognizeMarker(id) { return marker => marker.id == id }
function close() {
if (closing) {
text += lineSep
if (extraLinebreak) text += lineSep
closing = extraLinebreak = false
}
}
function addText(str) {
if (str) {
close()
text += str
}
}
function walk(node) {
if (node.nodeType == 1) {
let cmText = node.getAttribute("cm-text")
if (cmText) {
addText(cmText)
return
}
let markerID = node.getAttribute("cm-marker"), range
if (markerID) {
let found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID))
if (found.length && (range = found[0].find(0)))
addText(getBetween(cm.doc, range.from, range.to).join(lineSep))
return
}
if (node.getAttribute("contenteditable") == "false") return
let isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName)
if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) return
if (isBlock) close()
for (let i = 0; i < node.childNodes.length; i++)
walk(node.childNodes[i])
if (/^(pre|p)$/i.test(node.nodeName)) extraLinebreak = true
if (isBlock) closing = true
} else if (node.nodeType == 3) {
addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " "))
}
}
for (;;) {
walk(from)
if (from == to) break
from = from.nextSibling
extraLinebreak = false
}
return text
}
function domToPos(cm, node, offset) {
let lineNode
if (node == cm.display.lineDiv) {
lineNode = cm.display.lineDiv.childNodes[offset]
if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true)
node = null; offset = 0
} else {
for (lineNode = node;; lineNode = lineNode.parentNode) {
if (!lineNode || lineNode == cm.display.lineDiv) return null
if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break
}
}
for (let i = 0; i < cm.display.view.length; i++) {
let lineView = cm.display.view[i]
if (lineView.node == lineNode)
return locateNodeInLineView(lineView, node, offset)
}
}
function locateNodeInLineView(lineView, node, offset) {
let wrapper = lineView.text.firstChild, bad = false
if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true)
if (node == wrapper) {
bad = true
node = wrapper.childNodes[offset]
offset = 0
if (!node) {
let line = lineView.rest ? lst(lineView.rest) : lineView.line
return badPos(Pos(lineNo(line), line.text.length), bad)
}
}
let textNode = node.nodeType == 3 ? node : null, topNode = node
if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
textNode = node.firstChild
if (offset) offset = textNode.nodeValue.length
}
while (topNode.parentNode != wrapper) topNode = topNode.parentNode
let measure = lineView.measure, maps = measure.maps
function find(textNode, topNode, offset) {
for (let i = -1; i < (maps ? maps.length : 0); i++) {
let map = i < 0 ? measure.map : maps[i]
for (let j = 0; j < map.length; j += 3) {
let curNode = map[j + 2]
if (curNode == textNode || curNode == topNode) {
let line = lineNo(i < 0 ? lineView.line : lineView.rest[i])
let ch = map[j] + offset
if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]
return Pos(line, ch)
}
}
}
}
let found = find(textNode, topNode, offset)
if (found) return badPos(found, bad)
// FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
for (let after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
found = find(after, after.firstChild, 0)
if (found)
return badPos(Pos(found.line, found.ch - dist), bad)
else
dist += after.textContent.length
}
for (let before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
found = find(before, before.firstChild, -1)
if (found)
return badPos(Pos(found.line, found.ch + dist), bad)
else
dist += before.textContent.length
}
}

380
node_modules/codemirror/src/input/TextareaInput.js generated vendored Executable file
View File

@@ -0,0 +1,380 @@
import { operation, runInOp } from "../display/operations.js"
import { prepareSelection } from "../display/selection.js"
import { applyTextInput, copyableRanges, handlePaste, hiddenTextarea, disableBrowserMagic, setLastCopied } from "./input.js"
import { cursorCoords, posFromMouse } from "../measurement/position_measurement.js"
import { eventInWidget } from "../measurement/widgets.js"
import { simpleSelection } from "../model/selection.js"
import { selectAll, setSelection } from "../model/selection_updates.js"
import { captureRightClick, ie, ie_version, ios, mac, mobile, presto, webkit } from "../util/browser.js"
import { activeElt, removeChildrenAndAdd, selectInput, rootNode } from "../util/dom.js"
import { e_preventDefault, e_stop, off, on, signalDOMEvent } from "../util/event.js"
import { hasSelection } from "../util/feature_detection.js"
import { Delayed, sel_dontScroll } from "../util/misc.js"
// TEXTAREA INPUT STYLE
export default class TextareaInput {
constructor(cm) {
this.cm = cm
// See input.poll and input.reset
this.prevInput = ""
// Flag that indicates whether we expect input to appear real soon
// now (after some event like 'keypress' or 'input') and are
// polling intensively.
this.pollingFast = false
// Self-resetting timeout for the poller
this.polling = new Delayed()
// Used to work around IE issue with selection being forgotten when focus moves away from textarea
this.hasSelection = false
this.composing = null
this.resetting = false
}
init(display) {
let input = this, cm = this.cm
this.createField(display)
const te = this.textarea
display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild)
// Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
if (ios) te.style.width = "0px"
on(te, "input", () => {
if (ie && ie_version >= 9 && this.hasSelection) this.hasSelection = null
input.poll()
})
on(te, "paste", e => {
if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return
cm.state.pasteIncoming = +new Date
input.fastPoll()
})
function prepareCopyCut(e) {
if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) {
setLastCopied({lineWise: false, text: cm.getSelections()})
} else if (!cm.options.lineWiseCopyCut) {
return
} else {
let ranges = copyableRanges(cm)
setLastCopied({lineWise: true, text: ranges.text})
if (e.type == "cut") {
cm.setSelections(ranges.ranges, null, sel_dontScroll)
} else {
input.prevInput = ""
te.value = ranges.text.join("\n")
selectInput(te)
}
}
if (e.type == "cut") cm.state.cutIncoming = +new Date
}
on(te, "cut", prepareCopyCut)
on(te, "copy", prepareCopyCut)
on(display.scroller, "paste", e => {
if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return
if (!te.dispatchEvent) {
cm.state.pasteIncoming = +new Date
input.focus()
return
}
// Pass the `paste` event to the textarea so it's handled by its event listener.
const event = new Event("paste")
event.clipboardData = e.clipboardData
te.dispatchEvent(event)
})
// Prevent normal selection in the editor (we handle our own)
on(display.lineSpace, "selectstart", e => {
if (!eventInWidget(display, e)) e_preventDefault(e)
})
on(te, "compositionstart", () => {
let start = cm.getCursor("from")
if (input.composing) input.composing.range.clear()
input.composing = {
start: start,
range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
}
})
on(te, "compositionend", () => {
if (input.composing) {
input.poll()
input.composing.range.clear()
input.composing = null
}
})
}
createField(_display) {
// Wraps and hides input textarea
this.wrapper = hiddenTextarea()
// The semihidden textarea that is focused when the editor is
// focused, and receives input.
this.textarea = this.wrapper.firstChild
let opts = this.cm.options
disableBrowserMagic(this.textarea, opts.spellcheck, opts.autocorrect, opts.autocapitalize)
}
screenReaderLabelChanged(label) {
// Label for screenreaders, accessibility
if(label) {
this.textarea.setAttribute('aria-label', label)
} else {
this.textarea.removeAttribute('aria-label')
}
}
prepareSelection() {
// Redraw the selection and/or cursor
let cm = this.cm, display = cm.display, doc = cm.doc
let result = prepareSelection(cm)
// Move the hidden textarea near the cursor to prevent scrolling artifacts
if (cm.options.moveInputWithCursor) {
let headPos = cursorCoords(cm, doc.sel.primary().head, "div")
let wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect()
result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
headPos.top + lineOff.top - wrapOff.top))
result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
headPos.left + lineOff.left - wrapOff.left))
}
return result
}
showSelection(drawn) {
let cm = this.cm, display = cm.display
removeChildrenAndAdd(display.cursorDiv, drawn.cursors)
removeChildrenAndAdd(display.selectionDiv, drawn.selection)
if (drawn.teTop != null) {
this.wrapper.style.top = drawn.teTop + "px"
this.wrapper.style.left = drawn.teLeft + "px"
}
}
// Reset the input to correspond to the selection (or to be empty,
// when not typing and nothing is selected)
reset(typing) {
if (this.contextMenuPending || this.composing && typing) return
let cm = this.cm
this.resetting = true
if (cm.somethingSelected()) {
this.prevInput = ""
let content = cm.getSelection()
this.textarea.value = content
if (cm.state.focused) selectInput(this.textarea)
if (ie && ie_version >= 9) this.hasSelection = content
} else if (!typing) {
this.prevInput = this.textarea.value = ""
if (ie && ie_version >= 9) this.hasSelection = null
}
this.resetting = false
}
getField() { return this.textarea }
supportsTouch() { return false }
focus() {
if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt(rootNode(this.textarea)) != this.textarea)) {
try { this.textarea.focus() }
catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
}
}
blur() { this.textarea.blur() }
resetPosition() {
this.wrapper.style.top = this.wrapper.style.left = 0
}
receivedFocus() { this.slowPoll() }
// Poll for input changes, using the normal rate of polling. This
// runs as long as the editor is focused.
slowPoll() {
if (this.pollingFast) return
this.polling.set(this.cm.options.pollInterval, () => {
this.poll()
if (this.cm.state.focused) this.slowPoll()
})
}
// When an event has just come in that is likely to add or change
// something in the input textarea, we poll faster, to ensure that
// the change appears on the screen quickly.
fastPoll() {
let missed = false, input = this
input.pollingFast = true
function p() {
let changed = input.poll()
if (!changed && !missed) {missed = true; input.polling.set(60, p)}
else {input.pollingFast = false; input.slowPoll()}
}
input.polling.set(20, p)
}
// Read input from the textarea, and update the document to match.
// When something is selected, it is present in the textarea, and
// selected (unless it is huge, in which case a placeholder is
// used). When nothing is selected, the cursor sits after previously
// seen text (can be empty), which is stored in prevInput (we must
// not reset the textarea when typing, because that breaks IME).
poll() {
let cm = this.cm, input = this.textarea, prevInput = this.prevInput
// Since this is called a *lot*, try to bail out as cheaply as
// possible when it is clear that nothing happened. hasSelection
// will be the case when there is a lot of text in the textarea,
// in which case reading its value would be expensive.
if (this.contextMenuPending || this.resetting || !cm.state.focused ||
(hasSelection(input) && !prevInput && !this.composing) ||
cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
return false
let text = input.value
// If nothing changed, bail.
if (text == prevInput && !cm.somethingSelected()) return false
// Work around nonsensical selection resetting in IE9/10, and
// inexplicable appearance of private area unicode characters on
// some key combos in Mac (#2689).
if (ie && ie_version >= 9 && this.hasSelection === text ||
mac && /[\uf700-\uf7ff]/.test(text)) {
cm.display.input.reset()
return false
}
if (cm.doc.sel == cm.display.selForContextMenu) {
let first = text.charCodeAt(0)
if (first == 0x200b && !prevInput) prevInput = "\u200b"
if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
}
// Find the part of the input that is actually new
let same = 0, l = Math.min(prevInput.length, text.length)
while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same
runInOp(cm, () => {
applyTextInput(cm, text.slice(same), prevInput.length - same,
null, this.composing ? "*compose" : null)
// Don't leave long text in the textarea, since it makes further polling slow
if (text.length > 1000 || text.indexOf("\n") > -1) input.value = this.prevInput = ""
else this.prevInput = text
if (this.composing) {
this.composing.range.clear()
this.composing.range = cm.markText(this.composing.start, cm.getCursor("to"),
{className: "CodeMirror-composing"})
}
})
return true
}
ensurePolled() {
if (this.pollingFast && this.poll()) this.pollingFast = false
}
onKeyPress() {
if (ie && ie_version >= 9) this.hasSelection = null
this.fastPoll()
}
onContextMenu(e) {
let input = this, cm = input.cm, display = cm.display, te = input.textarea
if (input.contextMenuPending) input.contextMenuPending()
let pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop
if (!pos || presto) return // Opera is difficult.
// Reset the current text selection only if the click is done outside of the selection
// and 'resetSelectionOnContextMenu' option is true.
let reset = cm.options.resetSelectionOnContextMenu
if (reset && cm.doc.sel.contains(pos) == -1)
operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll)
let oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText
let wrapperBox = input.wrapper.offsetParent.getBoundingClientRect()
input.wrapper.style.cssText = "position: static"
te.style.cssText = `position: absolute; width: 30px; height: 30px;
top: ${e.clientY - wrapperBox.top - 5}px; left: ${e.clientX - wrapperBox.left - 5}px;
z-index: 1000; background: ${ie ? "rgba(255, 255, 255, .05)" : "transparent"};
outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);`
let oldScrollY
if (webkit) oldScrollY = te.ownerDocument.defaultView.scrollY // Work around Chrome issue (#2712)
display.input.focus()
if (webkit) te.ownerDocument.defaultView.scrollTo(null, oldScrollY)
display.input.reset()
// Adds "Select all" to context menu in FF
if (!cm.somethingSelected()) te.value = input.prevInput = " "
input.contextMenuPending = rehide
display.selForContextMenu = cm.doc.sel
clearTimeout(display.detectingSelectAll)
// Select-all will be greyed out if there's nothing to select, so
// this adds a zero-width space so that we can later check whether
// it got selected.
function prepareSelectAllHack() {
if (te.selectionStart != null) {
let selected = cm.somethingSelected()
let extval = "\u200b" + (selected ? te.value : "")
te.value = "\u21da" // Used to catch context-menu undo
te.value = extval
input.prevInput = selected ? "" : "\u200b"
te.selectionStart = 1; te.selectionEnd = extval.length
// Re-set this, in case some other handler touched the
// selection in the meantime.
display.selForContextMenu = cm.doc.sel
}
}
function rehide() {
if (input.contextMenuPending != rehide) return
input.contextMenuPending = false
input.wrapper.style.cssText = oldWrapperCSS
te.style.cssText = oldCSS
if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos)
// Try to detect the user choosing select-all
if (te.selectionStart != null) {
if (!ie || (ie && ie_version < 9)) prepareSelectAllHack()
let i = 0, poll = () => {
if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
te.selectionEnd > 0 && input.prevInput == "\u200b") {
operation(cm, selectAll)(cm)
} else if (i++ < 10) {
display.detectingSelectAll = setTimeout(poll, 500)
} else {
display.selForContextMenu = null
display.input.reset()
}
}
display.detectingSelectAll = setTimeout(poll, 200)
}
}
if (ie && ie_version >= 9) prepareSelectAllHack()
if (captureRightClick) {
e_stop(e)
let mouseup = () => {
off(window, "mouseup", mouseup)
setTimeout(rehide, 20)
}
on(window, "mouseup", mouseup)
} else {
setTimeout(rehide, 50)
}
}
readOnlyChanged(val) {
if (!val) this.reset()
this.textarea.disabled = val == "nocursor"
this.textarea.readOnly = !!val
}
setUneditable() {}
}
TextareaInput.prototype.needsContentAttribute = false

71
node_modules/codemirror/src/input/indent.js generated vendored Executable file
View File

@@ -0,0 +1,71 @@
import { getContextBefore } from "../line/highlight.js"
import { Pos } from "../line/pos.js"
import { getLine } from "../line/utils_line.js"
import { replaceRange } from "../model/changes.js"
import { Range } from "../model/selection.js"
import { replaceOneSelection } from "../model/selection_updates.js"
import { countColumn, Pass, spaceStr } from "../util/misc.js"
// Indent the given line. The how parameter can be "smart",
// "add"/null, "subtract", or "prev". When aggressive is false
// (typically set to true for forced single-line indents), empty
// lines are not indented, and places where the mode returns Pass
// are left alone.
export function indentLine(cm, n, how, aggressive) {
let doc = cm.doc, state
if (how == null) how = "add"
if (how == "smart") {
// Fall back to "prev" when the mode doesn't have an indentation
// method.
if (!doc.mode.indent) how = "prev"
else state = getContextBefore(cm, n).state
}
let tabSize = cm.options.tabSize
let line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize)
if (line.stateAfter) line.stateAfter = null
let curSpaceString = line.text.match(/^\s*/)[0], indentation
if (!aggressive && !/\S/.test(line.text)) {
indentation = 0
how = "not"
} else if (how == "smart") {
indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text)
if (indentation == Pass || indentation > 150) {
if (!aggressive) return
how = "prev"
}
}
if (how == "prev") {
if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize)
else indentation = 0
} else if (how == "add") {
indentation = curSpace + cm.options.indentUnit
} else if (how == "subtract") {
indentation = curSpace - cm.options.indentUnit
} else if (typeof how == "number") {
indentation = curSpace + how
}
indentation = Math.max(0, indentation)
let indentString = "", pos = 0
if (cm.options.indentWithTabs)
for (let i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"}
if (pos < indentation) indentString += spaceStr(indentation - pos)
if (indentString != curSpaceString) {
replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input")
line.stateAfter = null
return true
} else {
// Ensure that, if the cursor was in the whitespace at the start
// of the line, it is moved to the end of that space.
for (let i = 0; i < doc.sel.ranges.length; i++) {
let range = doc.sel.ranges[i]
if (range.head.line == n && range.head.ch < curSpaceString.length) {
let pos = Pos(n, curSpaceString.length)
replaceOneSelection(doc, i, new Range(pos, pos))
break
}
}
}
}

134
node_modules/codemirror/src/input/input.js generated vendored Executable file
View File

@@ -0,0 +1,134 @@
import { runInOp } from "../display/operations.js"
import { ensureCursorVisible } from "../display/scrolling.js"
import { Pos } from "../line/pos.js"
import { getLine } from "../line/utils_line.js"
import { makeChange } from "../model/changes.js"
import { ios, webkit } from "../util/browser.js"
import { elt } from "../util/dom.js"
import { lst, map } from "../util/misc.js"
import { signalLater } from "../util/operation_group.js"
import { splitLinesAuto } from "../util/feature_detection.js"
import { indentLine } from "./indent.js"
// This will be set to a {lineWise: bool, text: [string]} object, so
// that, when pasting, we know what kind of selections the copied
// text was made out of.
export let lastCopied = null
export function setLastCopied(newLastCopied) {
lastCopied = newLastCopied
}
export function applyTextInput(cm, inserted, deleted, sel, origin) {
let doc = cm.doc
cm.display.shift = false
if (!sel) sel = doc.sel
let recent = +new Date - 200
let paste = origin == "paste" || cm.state.pasteIncoming > recent
let textLines = splitLinesAuto(inserted), multiPaste = null
// When pasting N lines into N selections, insert one line per selection
if (paste && sel.ranges.length > 1) {
if (lastCopied && lastCopied.text.join("\n") == inserted) {
if (sel.ranges.length % lastCopied.text.length == 0) {
multiPaste = []
for (let i = 0; i < lastCopied.text.length; i++)
multiPaste.push(doc.splitLines(lastCopied.text[i]))
}
} else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
multiPaste = map(textLines, l => [l])
}
}
let updateInput = cm.curOp.updateInput
// Normal behavior is to insert the new text into every selection
for (let i = sel.ranges.length - 1; i >= 0; i--) {
let range = sel.ranges[i]
let from = range.from(), to = range.to()
if (range.empty()) {
if (deleted && deleted > 0) // Handle deletion
from = Pos(from.line, from.ch - deleted)
else if (cm.state.overwrite && !paste) // Handle overwrite
to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length))
else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == textLines.join("\n"))
from = to = Pos(from.line, 0)
}
let changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
origin: origin || (paste ? "paste" : cm.state.cutIncoming > recent ? "cut" : "+input")}
makeChange(cm.doc, changeEvent)
signalLater(cm, "inputRead", cm, changeEvent)
}
if (inserted && !paste)
triggerElectric(cm, inserted)
ensureCursorVisible(cm)
if (cm.curOp.updateInput < 2) cm.curOp.updateInput = updateInput
cm.curOp.typing = true
cm.state.pasteIncoming = cm.state.cutIncoming = -1
}
export function handlePaste(e, cm) {
let pasted = e.clipboardData && e.clipboardData.getData("Text")
if (pasted) {
e.preventDefault()
if (!cm.isReadOnly() && !cm.options.disableInput && cm.hasFocus())
runInOp(cm, () => applyTextInput(cm, pasted, 0, null, "paste"))
return true
}
}
export function triggerElectric(cm, inserted) {
// When an 'electric' character is inserted, immediately trigger a reindent
if (!cm.options.electricChars || !cm.options.smartIndent) return
let sel = cm.doc.sel
for (let i = sel.ranges.length - 1; i >= 0; i--) {
let range = sel.ranges[i]
if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue
let mode = cm.getModeAt(range.head)
let indented = false
if (mode.electricChars) {
for (let j = 0; j < mode.electricChars.length; j++)
if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
indented = indentLine(cm, range.head.line, "smart")
break
}
} else if (mode.electricInput) {
if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
indented = indentLine(cm, range.head.line, "smart")
}
if (indented) signalLater(cm, "electricInput", cm, range.head.line)
}
}
export function copyableRanges(cm) {
let text = [], ranges = []
for (let i = 0; i < cm.doc.sel.ranges.length; i++) {
let line = cm.doc.sel.ranges[i].head.line
let lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}
ranges.push(lineRange)
text.push(cm.getRange(lineRange.anchor, lineRange.head))
}
return {text: text, ranges: ranges}
}
export function disableBrowserMagic(field, spellcheck, autocorrect, autocapitalize) {
field.setAttribute("autocorrect", autocorrect ? "on" : "off")
field.setAttribute("autocapitalize", autocapitalize ? "on" : "off")
field.setAttribute("spellcheck", !!spellcheck)
}
export function hiddenTextarea() {
let te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; min-height: 1em; outline: none")
let div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;")
// The textarea is kept positioned near the cursor to prevent the
// fact that it'll be scrolled into view on input from scrolling
// our fake cursor out of view. On webkit, when wrap=off, paste is
// very slow. So make the area wide instead.
if (webkit) te.style.width = "1000px"
else te.setAttribute("wrap", "off")
// If border: 0; -- iOS fails to open keyboard (issue #1287)
if (ios) te.style.border = "1px solid black"
return div
}

147
node_modules/codemirror/src/input/keymap.js generated vendored Executable file
View File

@@ -0,0 +1,147 @@
import { flipCtrlCmd, mac, presto } from "../util/browser.js"
import { map } from "../util/misc.js"
import { keyNames } from "./keynames.js"
export let keyMap = {}
keyMap.basic = {
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
"Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
"Tab": "defaultTab", "Shift-Tab": "indentAuto",
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
"Esc": "singleSelection"
}
// Note that the save and find-related commands aren't defined by
// default. User code or addons can define them. Unknown commands
// are simply ignored.
keyMap.pcDefault = {
"Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
"Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
"Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
"Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
"Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
"Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
"Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
"fallthrough": "basic"
}
// Very basic readline/emacs-style bindings, which are standard on Mac.
keyMap.emacsy = {
"Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
"Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp",
"Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine",
"Ctrl-T": "transposeChars", "Ctrl-O": "openLine"
}
keyMap.macDefault = {
"Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
"Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
"Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
"Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
"Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
"Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
"Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
"fallthrough": ["basic", "emacsy"]
}
keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault
// KEYMAP DISPATCH
function normalizeKeyName(name) {
let parts = name.split(/-(?!$)/)
name = parts[parts.length - 1]
let alt, ctrl, shift, cmd
for (let i = 0; i < parts.length - 1; i++) {
let mod = parts[i]
if (/^(cmd|meta|m)$/i.test(mod)) cmd = true
else if (/^a(lt)?$/i.test(mod)) alt = true
else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true
else if (/^s(hift)?$/i.test(mod)) shift = true
else throw new Error("Unrecognized modifier name: " + mod)
}
if (alt) name = "Alt-" + name
if (ctrl) name = "Ctrl-" + name
if (cmd) name = "Cmd-" + name
if (shift) name = "Shift-" + name
return name
}
// This is a kludge to keep keymaps mostly working as raw objects
// (backwards compatibility) while at the same time support features
// like normalization and multi-stroke key bindings. It compiles a
// new normalized keymap, and then updates the old object to reflect
// this.
export function normalizeKeyMap(keymap) {
let copy = {}
for (let keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
let value = keymap[keyname]
if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue
if (value == "...") { delete keymap[keyname]; continue }
let keys = map(keyname.split(" "), normalizeKeyName)
for (let i = 0; i < keys.length; i++) {
let val, name
if (i == keys.length - 1) {
name = keys.join(" ")
val = value
} else {
name = keys.slice(0, i + 1).join(" ")
val = "..."
}
let prev = copy[name]
if (!prev) copy[name] = val
else if (prev != val) throw new Error("Inconsistent bindings for " + name)
}
delete keymap[keyname]
}
for (let prop in copy) keymap[prop] = copy[prop]
return keymap
}
export function lookupKey(key, map, handle, context) {
map = getKeyMap(map)
let found = map.call ? map.call(key, context) : map[key]
if (found === false) return "nothing"
if (found === "...") return "multi"
if (found != null && handle(found)) return "handled"
if (map.fallthrough) {
if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
return lookupKey(key, map.fallthrough, handle, context)
for (let i = 0; i < map.fallthrough.length; i++) {
let result = lookupKey(key, map.fallthrough[i], handle, context)
if (result) return result
}
}
}
// Modifier key presses don't count as 'real' key presses for the
// purpose of keymap fallthrough.
export function isModifierKey(value) {
let name = typeof value == "string" ? value : keyNames[value.keyCode]
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
}
export function addModifierNames(name, event, noShift) {
let base = name
if (event.altKey && base != "Alt") name = "Alt-" + name
if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name
if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Mod") name = "Cmd-" + name
if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name
return name
}
// Look up the name of a key as indicated by an event object.
export function keyName(event, noShift) {
if (presto && event.keyCode == 34 && event["char"]) return false
let name = keyNames[event.keyCode]
if (name == null || event.altGraphKey) return false
// Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
// so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
if (event.keyCode == 3 && event.code) name = event.code
return addModifierNames(name, event, noShift)
}
export function getKeyMap(val) {
return typeof val == "string" ? keyMap[val] : val
}

17
node_modules/codemirror/src/input/keynames.js generated vendored Executable file
View File

@@ -0,0 +1,17 @@
export let keyNames = {
3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock",
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
221: "]", 222: "'", 224: "Mod", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
}
// Number keys
for (let i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i)
// Alphabetic keys
for (let i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i)
// Function keys
for (let i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i

111
node_modules/codemirror/src/input/movement.js generated vendored Executable file
View File

@@ -0,0 +1,111 @@
import { Pos } from "../line/pos.js"
import { prepareMeasureForLine, measureCharPrepared, wrappedLineExtentChar } from "../measurement/position_measurement.js"
import { getBidiPartAt, getOrder } from "../util/bidi.js"
import { findFirst, lst, skipExtendingChars } from "../util/misc.js"
function moveCharLogically(line, ch, dir) {
let target = skipExtendingChars(line.text, ch + dir, dir)
return target < 0 || target > line.text.length ? null : target
}
export function moveLogically(line, start, dir) {
let ch = moveCharLogically(line, start.ch, dir)
return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
}
export function endOfLine(visually, cm, lineObj, lineNo, dir) {
if (visually) {
if (cm.doc.direction == "rtl") dir = -dir
let order = getOrder(lineObj, cm.doc.direction)
if (order) {
let part = dir < 0 ? lst(order) : order[0]
let moveInStorageOrder = (dir < 0) == (part.level == 1)
let sticky = moveInStorageOrder ? "after" : "before"
let ch
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
// it could be that the last bidi part is not on the last visual line,
// since visual lines contain content order-consecutive chunks.
// Thus, in rtl, we are looking for the first (content-order) character
// in the rtl chunk that is on the last line (that is, the same line
// as the last (content-order) character).
if (part.level > 0 || cm.doc.direction == "rtl") {
let prep = prepareMeasureForLine(cm, lineObj)
ch = dir < 0 ? lineObj.text.length - 1 : 0
let targetTop = measureCharPrepared(cm, prep, ch).top
ch = findFirst(ch => measureCharPrepared(cm, prep, ch).top == targetTop, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
if (sticky == "before") ch = moveCharLogically(lineObj, ch, 1)
} else ch = dir < 0 ? part.to : part.from
return new Pos(lineNo, ch, sticky)
}
}
return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
}
export function moveVisually(cm, line, start, dir) {
let bidi = getOrder(line, cm.doc.direction)
if (!bidi) return moveLogically(line, start, dir)
if (start.ch >= line.text.length) {
start.ch = line.text.length
start.sticky = "before"
} else if (start.ch <= 0) {
start.ch = 0
start.sticky = "after"
}
let partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
// nothing interesting happens.
return moveLogically(line, start, dir)
}
let mv = (pos, dir) => moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir)
let prep
let getWrappedLineExtent = ch => {
if (!cm.options.lineWrapping) return {begin: 0, end: line.text.length}
prep = prep || prepareMeasureForLine(cm, line)
return wrappedLineExtentChar(cm, line, prep, ch)
}
let wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
if (cm.doc.direction == "rtl" || part.level == 1) {
let moveInStorageOrder = (part.level == 1) == (dir < 0)
let ch = mv(start, moveInStorageOrder ? 1 : -1)
if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
let sticky = moveInStorageOrder ? "before" : "after"
return new Pos(start.line, ch, sticky)
}
}
// Case 3: Could not move within this bidi part in this visual line, so leave
// the current bidi part
let searchInVisualLine = (partPos, dir, wrappedLineExtent) => {
let getRes = (ch, moveInStorageOrder) => moveInStorageOrder
? new Pos(start.line, mv(ch, 1), "before")
: new Pos(start.line, ch, "after")
for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
let part = bidi[partPos]
let moveInStorageOrder = (dir > 0) == (part.level != 1)
let ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
if (part.from <= ch && ch < part.to) return getRes(ch, moveInStorageOrder)
ch = moveInStorageOrder ? part.from : mv(part.to, -1)
if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) return getRes(ch, moveInStorageOrder)
}
}
// Case 3a: Look for other bidi parts on the same visual line
let res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
if (res) return res
// Case 3b: Look for other bidi parts on the next visual line
let nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
if (res) return res
}
// Case 4: Nowhere to move
return null
}