Spaces:
Sleeping
Sleeping
| import { Pos } from "../line/pos" | |
| import { visualLine } from "../line/spans" | |
| import { getLine } from "../line/utils_line" | |
| import { charCoords, cursorCoords, displayWidth, paddingH } from "../measurement/position_measurement" | |
| import { getOrder, iterateBidiSections } from "../util/bidi" | |
| import { elt } from "../util/dom" | |
| export function updateSelection(cm) { | |
| cm.display.input.showSelection(cm.display.input.prepareSelection()) | |
| } | |
| export function prepareSelection(cm, primary) { | |
| let doc = cm.doc, result = {} | |
| let curFragment = result.cursors = document.createDocumentFragment() | |
| let selFragment = result.selection = document.createDocumentFragment() | |
| for (let i = 0; i < doc.sel.ranges.length; i++) { | |
| if (primary === false && i == doc.sel.primIndex) continue | |
| let range = doc.sel.ranges[i] | |
| if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue | |
| let collapsed = range.empty() | |
| if (collapsed || cm.options.showCursorWhenSelecting) | |
| drawSelectionCursor(cm, range.head, curFragment) | |
| if (!collapsed) | |
| drawSelectionRange(cm, range, selFragment) | |
| } | |
| return result | |
| } | |
| // Draws a cursor for the given range | |
| export function drawSelectionCursor(cm, head, output) { | |
| let pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine) | |
| let cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")) | |
| cursor.style.left = pos.left + "px" | |
| cursor.style.top = pos.top + "px" | |
| cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px" | |
| if (pos.other) { | |
| // Secondary cursor, shown when on a 'jump' in bi-directional text | |
| let otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")) | |
| otherCursor.style.display = "" | |
| otherCursor.style.left = pos.other.left + "px" | |
| otherCursor.style.top = pos.other.top + "px" | |
| otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px" | |
| } | |
| } | |
| // Draws the given range as a highlighted selection | |
| function drawSelectionRange(cm, range, output) { | |
| let display = cm.display, doc = cm.doc | |
| let fragment = document.createDocumentFragment() | |
| let padding = paddingH(cm.display), leftSide = padding.left | |
| let rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right | |
| function add(left, top, width, bottom) { | |
| if (top < 0) top = 0 | |
| top = Math.round(top) | |
| bottom = Math.round(bottom) | |
| fragment.appendChild(elt("div", null, "CodeMirror-selected", `position: absolute; left: ${left}px; | |
| top: ${top}px; width: ${width == null ? rightSide - left : width}px; | |
| height: ${bottom - top}px`)) | |
| } | |
| function drawForLine(line, fromArg, toArg) { | |
| let lineObj = getLine(doc, line) | |
| let lineLen = lineObj.text.length | |
| let start, end | |
| function coords(ch, bias) { | |
| return charCoords(cm, Pos(line, ch), "div", lineObj, bias) | |
| } | |
| iterateBidiSections(getOrder(lineObj, doc.direction), fromArg || 0, toArg == null ? lineLen : toArg, (from, to, dir) => { | |
| let leftPos = coords(from, "left"), rightPos, left, right | |
| if (from == to) { | |
| rightPos = leftPos | |
| left = right = leftPos.left | |
| } else { | |
| rightPos = coords(to - 1, "right") | |
| if (dir == "rtl") { let tmp = leftPos; leftPos = rightPos; rightPos = tmp } | |
| left = leftPos.left | |
| right = rightPos.right | |
| } | |
| if (fromArg == null && from == 0) left = leftSide | |
| if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part | |
| add(left, leftPos.top, null, leftPos.bottom) | |
| left = leftSide | |
| if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top) | |
| } | |
| if (toArg == null && to == lineLen) right = rightSide | |
| if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) | |
| start = leftPos | |
| if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) | |
| end = rightPos | |
| if (left < leftSide + 1) left = leftSide | |
| add(left, rightPos.top, right - left, rightPos.bottom) | |
| }) | |
| return {start: start, end: end} | |
| } | |
| let sFrom = range.from(), sTo = range.to() | |
| if (sFrom.line == sTo.line) { | |
| drawForLine(sFrom.line, sFrom.ch, sTo.ch) | |
| } else { | |
| let fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line) | |
| let singleVLine = visualLine(fromLine) == visualLine(toLine) | |
| let leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end | |
| let rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start | |
| if (singleVLine) { | |
| if (leftEnd.top < rightStart.top - 2) { | |
| add(leftEnd.right, leftEnd.top, null, leftEnd.bottom) | |
| add(leftSide, rightStart.top, rightStart.left, rightStart.bottom) | |
| } else { | |
| add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom) | |
| } | |
| } | |
| if (leftEnd.bottom < rightStart.top) | |
| add(leftSide, leftEnd.bottom, null, rightStart.top) | |
| } | |
| output.appendChild(fragment) | |
| } | |
| // Cursor-blinking | |
| export function restartBlink(cm) { | |
| if (!cm.state.focused) return | |
| let display = cm.display | |
| clearInterval(display.blinker) | |
| let on = true | |
| display.cursorDiv.style.visibility = "" | |
| if (cm.options.cursorBlinkRate > 0) | |
| display.blinker = setInterval(() => display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden", | |
| cm.options.cursorBlinkRate) | |
| else if (cm.options.cursorBlinkRate < 0) | |
| display.cursorDiv.style.visibility = "hidden" | |
| } | |