New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

codemirror

Package Overview
Dependencies
Maintainers
1
Versions
151
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

codemirror - npm Package Compare versions

Comparing version 5.29.0 to 5.30.0

11

addon/edit/closebrackets.js

@@ -26,2 +26,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

if (val) {
ensureBound(getOption(val, "pairs"))
cm.state.closeBrackets = val;

@@ -38,6 +39,10 @@ cm.addKeyMap(keyMap);

var bind = defaults.pairs + "`";
var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
for (var i = 0; i < bind.length; i++)
keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
function ensureBound(chars) {
for (var i = 0; i < chars.length; i++) {
var ch = chars.charAt(i), key = "'" + ch + "'"
if (!keyMap[key]) keyMap[key] = handler(ch)
}
}
ensureBound(defaults.pairs + "`")

@@ -44,0 +49,0 @@ function handler(ch) {

@@ -305,3 +305,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

CodeMirror.signal(data, "select", completions[0], hints.firstChild);
CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
return true;

@@ -308,0 +308,0 @@ }

@@ -18,3 +18,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

CodeMirror.registerHelper("lint", "css", function(text) {
CodeMirror.registerHelper("lint", "css", function(text, options) {
var found = [];

@@ -27,3 +27,3 @@ if (!window.CSSLint) {

}
var results = CSSLint.verify(text), messages = results.messages, message = null;
var results = CSSLint.verify(text, options), messages = results.messages, message = null;
for ( var i = 0; i < messages.length; i++) {

@@ -30,0 +30,0 @@ message = messages[i];

@@ -141,3 +141,7 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

var state = cm.state.lint, options = state.options;
var passOptions = options.options || options; // Support deprecated passing of `options` property in options
/*
* Passing rules in `options` property prevents JSHint (and other linters) from complaining
* about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc.
*/
var passOptions = options.options || options;
var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");

@@ -144,0 +148,0 @@ if (!getAnnotations) return;

@@ -139,3 +139,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

if (token && token.apply) token = token(matches)
if (matches.length > 2) {
if (matches.length > 2 && rule.token && typeof rule.token != "string") {
state.pending = [];

@@ -142,0 +142,0 @@ for (var j = 2; j < matches.length; j++)

@@ -120,2 +120,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

var q = cm.getSelection() || state.lastQuery;
if (q instanceof RegExp && q.source == "x^") q = null
if (persistent && cm.openDialog) {

@@ -122,0 +123,0 @@ var hiding = null

@@ -89,3 +89,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||
if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE ||
cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)

@@ -92,0 +92,0 @@ return reset(cm);

@@ -574,3 +574,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

offsetLines: from.line,
text: doc.getRange(from, Pos(endLine, 0))};
text: doc.getRange(from, Pos(endLine, end.line == endLine ? null : 0))};
}

@@ -577,0 +577,0 @@

@@ -84,3 +84,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

if (modeConfig.gitHubSpice !== false) {
if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) {
if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?=.{0,6}\d)(?:[a-f0-9]{7,40}\b)/)) {
// User/Project@SHA

@@ -87,0 +87,0 @@ // User@SHA

@@ -31,3 +31,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "void": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),

@@ -402,3 +402,3 @@ "function": kw("function"), "catch": kw("catch"),

var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);

@@ -448,2 +448,7 @@ }

if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
if (type == "regexp") {
cx.state.lastType = cx.marked = "operator"
cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
return cont(expr)
}
}

@@ -497,2 +502,5 @@ function quasi(type, value) {

if (value == "get" || value == "set") return cont(getterSetter);
var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
cx.state.fatArrowAt = cx.stream.pos + m[0].length
return cont(afterprop);

@@ -655,3 +663,4 @@ } else if (type == "number" || type == "string") {

}
function funarg(type) {
function funarg(type, value) {
if (value == "@") cont(expression, funarg)
if (type == "spread" || type == "modifier") return cont(funarg);

@@ -682,3 +691,3 @@ return pass(pattern, maybetype, maybeAssign);

}
if (type == "variable") {
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";

@@ -745,3 +754,3 @@ return cont(isTS ? classfield : functiondef, classBody);

return state.tokenize == tokenBase &&
/^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
/^(?:operator|sof|keyword [bc]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))

@@ -748,0 +757,0 @@ }

@@ -88,3 +88,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

, listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow listRE
, taskListRE = /^\[(x| )\](?=\s)/i // Must follow listRE
, atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/

@@ -407,3 +407,3 @@ , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/

if (state.taskList) {
var taskOpen = stream.match(taskListRE, true)[1] !== "x";
var taskOpen = stream.match(taskListRE, true)[1] === " ";
if (taskOpen) state.taskOpen = true;

@@ -844,4 +844,4 @@ else state.taskClosed = true;

indent: function(state, textAfter, line) {
if (state.block == htmlBlock) return htmlMode.indent(state.htmlState, textAfter, line)
if (state.localState) return state.localMode.indent(state.localState, textAfter, line)
if (state.block == htmlBlock && htmlMode.indent) return htmlMode.indent(state.htmlState, textAfter, line)
if (state.localState && state.localMode.indent) return state.localMode.indent(state.localState, textAfter, line)
return CodeMirror.Pass

@@ -848,0 +848,0 @@ },

@@ -50,2 +50,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

{name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
{name: "Esper", mime: "text/x-esper", mode: "sql"},
{name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},

@@ -52,0 +53,0 @@ {name: "FCL", mime: "text/x-fcl", mode: "fcl"},

@@ -289,3 +289,4 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

electricInput: /^\s*(?:end|rescue|elsif|else|\})$/,
lineComment: "#"
lineComment: "#",
fold: "indent"
};

@@ -292,0 +293,0 @@ });

@@ -90,3 +90,3 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

templates: null,
variables: null,
variables: prepend(null, 'ij'),
scopes: null,

@@ -132,2 +132,9 @@ indent: 0,

}
if (!state.scopes) {
var paramRe = /@param\??\s+(\S+)/g;
var current = stream.current();
for (var match; (match = paramRe.exec(current)); ) {
state.variables = prepend(state.variables, match[1]);
}
}
return "comment";

@@ -192,2 +199,3 @@

popscope(state);
state.variables = prepend(null, 'ij');
state.indent = 0;

@@ -254,4 +262,10 @@ } else {

state.soyState.push("comment");
if (!state.scopes) {
state.variables = prepend(null, 'ij');
}
return "comment";
} else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) {
if (!state.scopes) {
state.variables = prepend(null, 'ij');
}
return "comment";

@@ -281,14 +295,14 @@ } else if (stream.match(/^\{literal}/)) {

state.soyState.push("templ-def");
}
if (state.tag == "call" || state.tag == "delcall") {
} else if (state.tag == "call" || state.tag == "delcall") {
state.soyState.push("templ-ref");
}
if (state.tag == "let") {
} else if (state.tag == "let") {
state.soyState.push("var-def");
}
if (state.tag == "for" || state.tag == "foreach") {
} else if (state.tag == "for" || state.tag == "foreach") {
state.scopes = prepend(state.scopes, state.variables);
state.soyState.push("var-def");
}
if (state.tag.match(/^@(?:param\??|inject)/)) {
} else if (state.tag == "namespace") {
if (!state.scopes) {
state.variables = prepend(null, 'ij');
}
} else if (state.tag.match(/^@(?:param\??|inject)/)) {
state.soyState.push("param-def");

@@ -295,0 +309,0 @@ }

@@ -444,2 +444,15 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

});
// Esper
CodeMirror.defineMIME("text/x-esper", {
name: "sql",
client: set("source"),
// http://www.espertech.com/esper/release-5.5.0/esper-reference/html/appendix_keywords.html
keywords: set("alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit after all and as at asc avedev avg between by case cast coalesce count create current_timestamp day days delete define desc distinct else end escape events every exists false first from full group having hour hours in inner insert instanceof into irstream is istream join last lastweekday left limit like max match_recognize matches median measures metadatasql min minute minutes msec millisecond milliseconds not null offset on or order outer output partition pattern prev prior regexp retain-union retain-intersection right rstream sec second seconds select set some snapshot sql stddev sum then true unidirectional until update variable weekday when where window"),
builtin: {},
atoms: set("false true null"),
operatorChars: /^[*+\-%<>!=&|^\/#@?~]/,
dateSQL: set("time"),
support: set("decimallessFloat zerolessFloat binaryNumber hexNumber")
});
}());

@@ -446,0 +459,0 @@

@@ -35,3 +35,6 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others

["lang", /coffee(script)?/, "coffeescript"],
["type", /^(?:text|application)\/(?:x-)?coffee(?:script)?$/, "coffeescript"]
["type", /^(?:text|application)\/(?:x-)?coffee(?:script)?$/, "coffeescript"],
["lang", /^babel$/, "javascript"],
["type", /^text\/babel$/, "javascript"],
["type", /^text\/ecmascript-\d+$/, "javascript"]
],

@@ -41,4 +44,8 @@ style: [

["lang", /^sass$/i, "sass"],
["lang", /^less$/i, "text/x-less"],
["lang", /^scss$/i, "text/x-scss"],
["type", /^(text\/)?(x-)?styl(us)?$/i, "stylus"],
["type", /^text\/sass/i, "sass"]
["type", /^text\/sass/i, "sass"],
["type", /^(text\/)?(x-)?scss$/i, "text/x-scss"],
["type", /^(text\/)?(x-)?less$/i, "text/x-less"]
],

@@ -45,0 +52,0 @@ template: [

{
"name": "codemirror",
"version": "5.29.0",
"version": "5.30.0",
"main": "lib/codemirror.js",

@@ -5,0 +5,0 @@ "style": "lib/codemirror.css",

@@ -10,3 +10,4 @@ # CodeMirror

100 language modes and various addons that implement more advanced
editing functionality.
editing functionality. Every language comes with fully-featured code
and syntax highlighting to help with reading and editing complex code.

@@ -13,0 +14,0 @@ A rich programming API and a CSS theming system are available for

@@ -105,3 +105,3 @@ import { clipPos } from "../line/pos"

if (op.updatedDisplay || op.selectionChanged)
op.preparedSelection = display.input.prepareSelection(op.focus)
op.preparedSelection = display.input.prepareSelection()
}

@@ -119,3 +119,3 @@

let takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())
let takeFocus = op.focus && op.focus == activeElt()
if (op.preparedSelection)

@@ -122,0 +122,0 @@ cm.display.input.showSelection(op.preparedSelection, takeFocus)

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 { charCoords, cursorCoords, displayWidth, paddingH, wrappedLineExtentChar } from "../measurement/position_measurement"
import { getOrder, iterateBidiSections } from "../util/bidi"

@@ -12,3 +12,3 @@ import { elt } from "../util/dom"

export function prepareSelection(cm, primary) {
export function prepareSelection(cm, primary = true) {
let doc = cm.doc, result = {}

@@ -19,3 +19,3 @@ let curFragment = result.cursors = document.createDocumentFragment()

for (let i = 0; i < doc.sel.ranges.length; i++) {
if (primary === false && i == doc.sel.primIndex) continue
if (!primary && i == doc.sel.primIndex) continue
let range = doc.sel.ranges[i]

@@ -51,2 +51,4 @@ if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue

function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
// Draws the given range as a highlighted selection

@@ -76,26 +78,44 @@ function drawSelectionRange(cm, range, output) {

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
let order = getOrder(lineObj, doc.direction)
iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, (from, to, dir, i) => {
let fromPos = coords(from, dir == "ltr" ? "left" : "right")
let toPos = coords(to - 1, dir == "ltr" ? "right" : "left")
if (dir == "ltr") {
let fromLeft = fromArg == null && from == 0 ? leftSide : fromPos.left
let toRight = toArg == null && to == lineLen ? rightSide : toPos.right
if (toPos.top - fromPos.top <= 3) { // Single line
add(fromLeft, toPos.top, toRight - fromLeft, toPos.bottom)
} else { // Multiple lines
add(fromLeft, fromPos.top, null, fromPos.bottom)
if (fromPos.bottom < toPos.top) add(leftSide, fromPos.bottom, null, toPos.top)
add(leftSide, toPos.top, toPos.right, toPos.bottom)
}
} else if (from < to) { // RTL
let fromRight = fromArg == null && from == 0 ? rightSide : fromPos.right
let toLeft = toArg == null && to == lineLen ? leftSide : toPos.left
if (toPos.top - fromPos.top <= 3) { // Single line
add(toLeft, toPos.top, fromRight - toLeft, toPos.bottom)
} else { // Multiple lines
let topLeft = leftSide
if (i) {
let topEnd = wrappedLineExtentChar(cm, lineObj, null, from).end
// The coordinates returned for an RTL wrapped space tend to
// be complete bogus, so try to skip that here.
topLeft = coords(topEnd - (/\s/.test(lineObj.text.charAt(topEnd - 1)) ? 2 : 1), "left").left
}
add(topLeft, fromPos.top, fromRight - topLeft, fromPos.bottom)
if (fromPos.bottom < toPos.top) add(leftSide, fromPos.bottom, null, toPos.top)
let botWidth = null
if (i < order.length - 1 || true) {
let botStart = wrappedLineExtentChar(cm, lineObj, null, to).begin
botWidth = coords(botStart, "right").right - toLeft
}
add(toLeft, toPos.top, botWidth, toPos.bottom)
}
}
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)
if (!start || cmpCoords(fromPos, start) < 0) start = fromPos
if (cmpCoords(toPos, start) < 0) start = toPos
if (!end || cmpCoords(fromPos, end) < 0) end = fromPos
if (cmpCoords(toPos, end) < 0) end = toPos
})

@@ -102,0 +122,0 @@ return {start: start, end: end}

@@ -146,3 +146,3 @@ import { Display } from "../display/Display"

on(d.scroller, "touchstart", e => {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
d.input.ensurePolled()

@@ -149,0 +149,0 @@ clearTimeout(touchFinished)

@@ -69,2 +69,2 @@ // EDITOR CONSTRUCTOR

CodeMirror.version = "5.29.0"
CodeMirror.version = "5.30.0"

@@ -11,2 +11,3 @@ import { delayBlurEvent, ensureFocus } from "../display/focus"

import { captureRightClick, chromeOS, ie, ie_version, mac, webkit } from "../util/browser"
import { getOrder, getBidiPartAt } from "../util/bidi"
import { activeElt } from "../util/dom"

@@ -273,3 +274,3 @@ import { e_button, e_defaultPrevented, e_preventDefault, e_target, hasHandler, off, on, signal, signalDOMEvent } from "../util/event"

let ranges = startSel.ranges.slice(0)
ranges[ourIndex] = new Range(clipPos(doc, anchor), head)
ranges[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head))
setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse)

@@ -326,3 +327,35 @@ }

// Used when mouse-selecting to adjust the anchor to the proper side
// of a bidi jump depending on the visual position of the head.
function bidiSimplify(cm, range) {
let {anchor, head} = range, anchorLine = getLine(cm.doc, anchor.line)
if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) return range
let order = getOrder(anchorLine)
if (!order) return range
let index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]
if (part.from != anchor.ch && part.to != anchor.ch) return range
let boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1)
if (boundary == 0 || boundary == order.length) return range
// Compute the relative visual position of the head compared to the
// anchor (<0 is to the left, >0 to the right)
let leftSide
if (head.line != anchor.line) {
leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0
} else {
let headIndex = getBidiPartAt(order, head.ch, head.sticky)
let dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1)
if (headIndex == boundary - 1 || headIndex == boundary)
leftSide = dir < 0
else
leftSide = dir > 0
}
let usePart = order[boundary + (leftSide ? -1 : 0)]
let from = leftSide == (usePart.level == 1)
let ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"
return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head)
}
// Determines whether an event happened in the gutter, and fires the

@@ -332,4 +365,9 @@ // handlers for the corresponding event.

let mX, mY
try { mX = e.clientX; mY = e.clientY }
catch(e) { return false }
if (e.touches) {
mX = e.touches[0].clientX
mY = e.touches[0].clientY
} else {
try { mX = e.clientX; mY = e.clientY }
catch(e) { return false }
}
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false

@@ -336,0 +374,0 @@ if (prevent) e_preventDefault(e)

@@ -1,2 +0,1 @@

import { moveVisually } from "../input/movement"
import { buildLineContent, LineView } from "../line/line_data"

@@ -296,2 +295,9 @@ import { clipPos, Pos } from "../line/pos"

function widgetTopHeight(lineObj) {
let height = 0
if (lineObj.widgets) for (let i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above)
height += widgetHeight(lineObj.widgets[i])
return height
}
// Converts a {top, bottom, left, right} box from line-local

@@ -302,5 +308,5 @@ // coordinates into another coordinate system. Context may be one of

export function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
if (!includeWidgets && lineObj.widgets) for (let i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
let size = widgetHeight(lineObj.widgets[i])
rect.top += size; rect.bottom += size
if (!includeWidgets) {
let height = widgetTopHeight(lineObj)
rect.top += height; rect.bottom += height
}

@@ -381,3 +387,3 @@ if (context == "line") return rect

function getBidi(ch, partPos, invert) {
let part = order[partPos], right = (part.level % 2) != 0
let part = order[partPos], right = part.level == 1
return get(invert ? ch - 1 : ch, right != invert)

@@ -440,6 +446,6 @@ }

function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
let measure = ch => intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line")
y -= widgetTopHeight(lineObj)
let end = lineObj.text.length
let begin = findFirst(ch => measure(ch - 1).bottom <= y, end, 0)
end = findFirst(ch => measure(ch).top > y, begin, end)
let begin = findFirst(ch => measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y, end, 0)
end = findFirst(ch => measureCharPrepared(cm, preparedMeasure, ch).top > y, begin, end)
return {begin, end}

@@ -449,2 +455,3 @@ }

export function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj)
let targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top

@@ -454,62 +461,129 @@ return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)

// Returns true if the given side of a box is after the given
// coordinates, in top-to-bottom, left-to-right order.
function boxIsAfter(box, x, y, left) {
return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
}
function coordsCharInner(cm, lineObj, lineNo, x, y) {
// Move y into line-local coordinate space
y -= heightAtLine(lineObj)
let begin = 0, end = lineObj.text.length
let preparedMeasure = prepareMeasureForLine(cm, lineObj)
let pos
// When directly calling `measureCharPrepared`, we have to adjust
// for the widgets at this line.
let widgetHeight = widgetTopHeight(lineObj)
let begin = 0, end = lineObj.text.length, ltr = true
let order = getOrder(lineObj, cm.doc.direction)
// If the line isn't plain left-to-right text, first figure out
// which bidi section the coordinates fall into.
if (order) {
if (cm.options.lineWrapping) {
;({begin, end} = wrappedLineExtent(cm, lineObj, preparedMeasure, y))
let part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
(cm, lineObj, lineNo, preparedMeasure, order, x, y)
ltr = part.level != 1
// The awkward -1 offsets are needed because findFirst (called
// on these below) will treat its first bound as inclusive,
// second as exclusive, but we want to actually address the
// characters in the part's range
begin = ltr ? part.from : part.to - 1
end = ltr ? part.to : part.from - 1
}
// A binary search to find the first character whose bounding box
// starts after the coordinates. If we run across any whose box wrap
// the coordinates, store that.
let chAround = null, boxAround = null
let ch = findFirst(ch => {
let box = measureCharPrepared(cm, preparedMeasure, ch)
box.top += widgetHeight; box.bottom += widgetHeight
if (!boxIsAfter(box, x, y, false)) return false
if (box.top <= y && box.left <= x) {
chAround = ch
boxAround = box
}
pos = new Pos(lineNo, Math.floor(begin + (end - begin) / 2))
let beginLeft = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left
let dir = beginLeft < x ? 1 : -1
let prevDiff, diff = beginLeft - x, prevPos
let steps = Math.ceil((end - begin) / 4)
outer: do {
prevDiff = diff
prevPos = pos
let i = 0
for (; i < steps; ++i) {
let prevPos = pos
pos = moveVisually(cm, lineObj, pos, dir)
if (pos == null || pos.ch < begin || end <= (pos.sticky == "before" ? pos.ch - 1 : pos.ch)) {
pos = prevPos
break outer
}
}
diff = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left - x
if (steps > 1) {
let diff_change_per_step = Math.abs(diff - prevDiff) / steps
steps = Math.min(steps, Math.ceil(Math.abs(diff) / diff_change_per_step))
dir = diff < 0 ? 1 : -1
}
} while (diff != 0 && (steps > 1 || ((dir < 0) != (diff < 0) && (Math.abs(diff) <= Math.abs(prevDiff)))))
if (Math.abs(diff) > Math.abs(prevDiff)) {
if ((diff < 0) == (prevDiff < 0)) throw new Error("Broke out of infinite loop in coordsCharInner")
pos = prevPos
}
return true
}, begin, end)
let baseX, sticky, outside = false
// If a box around the coordinates was found, use that
if (boxAround) {
// Distinguish coordinates nearer to the left or right side of the box
let atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr
ch = chAround + (atStart ? 0 : 1)
sticky = atStart ? "after" : "before"
baseX = atLeft ? boxAround.left : boxAround.right
} else {
let ch = findFirst(ch => {
let box = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line")
if (box.top > y) {
// For the cursor stickiness
end = Math.min(ch, end)
return true
}
else if (box.bottom <= y) return false
else if (box.left > x) return true
else if (box.right < x) return false
else return (x - box.left < box.right - x)
}, begin, end)
ch = skipExtendingChars(lineObj.text, ch, 1)
pos = new Pos(lineNo, ch, ch == end ? "before" : "after")
// (Adjust for extended bound, if necessary.)
if (!ltr && (ch == end || ch == begin)) ch++
// To determine which side to associate with, get the box to the
// left of the character and compare it's vertical position to the
// coordinates
sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
(measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?
"after" : "before"
// Now get accurate coordinates for this place, in order to get a
// base X position
let coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure)
baseX = coords.left
outside = y < coords.top || y >= coords.bottom
}
let coords = cursorCoords(cm, pos, "line", lineObj, preparedMeasure)
if (y < coords.top || coords.bottom < y) pos.outside = true
pos.xRel = x < coords.left ? -1 : (x > coords.right ? 1 : 0)
return pos
ch = skipExtendingChars(lineObj.text, ch, 1)
return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
}
function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
// Bidi parts are sorted left-to-right, and in a non-line-wrapping
// situation, we can take this ordering to correspond to the visual
// ordering. This finds the first part whose end is after the given
// coordinates.
let index = findFirst(i => {
let part = order[i], ltr = part.level != 1
return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"),
"line", lineObj, preparedMeasure), x, y, true)
}, 0, order.length - 1)
let part = order[index]
// If this isn't the first part, the part's start is also after
// the coordinates, and the coordinates aren't on the same line as
// that start, move one part back.
if (index > 0) {
let ltr = part.level != 1
let start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"),
"line", lineObj, preparedMeasure)
if (boxIsAfter(start, x, y, true) && start.top > y)
part = order[index - 1]
}
return part
}
function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
// In a wrapped line, rtl text on wrapping boundaries can do things
// that don't correspond to the ordering in our `order` array at
// all, so a binary search doesn't work, and we want to return a
// part that only spans one line so that the binary search in
// coordsCharInner is safe. As such, we first find the extent of the
// wrapped line, and then do a flat search in which we discard any
// spans that aren't on the line.
let {begin, end} = wrappedLineExtent(cm, lineObj, preparedMeasure, y)
let part = null, closestDist = null
for (let i = 0; i < order.length; i++) {
let p = order[i]
if (p.from >= end || p.to <= begin) continue
let ltr = p.level != 1
let endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right
// Weigh against spans ending before this, so that they are only
// picked if nothing ends after
let dist = endX < x ? x - endX + 1e9 : endX - x
if (!part || closestDist > dist) {
part = p
closestDist = dist
}
}
if (!part) part = order[order.length - 1]
// Clip the part to the wrapped line.
if (part.from < begin) part = {from: begin, to: part.to, level: part.level}
if (part.to > end) part = {from: part.from, to: end, level: part.level}
return part
}
let measureText

@@ -516,0 +590,0 @@ // Compute the default text height.

@@ -263,5 +263,5 @@ import { retreatFrontier } from "../line/highlight"

if (!to) to = from
if (cmp(to, from) < 0) { let tmp = to; to = from; from = tmp }
if (cmp(to, from) < 0) [from, to] = [to, from]
if (typeof code == "string") code = doc.splitLines(code)
makeChange(doc, {from: from, to: to, text: code, origin: origin})
makeChange(doc, {from, to, text: code, origin})
}

@@ -268,0 +268,0 @@

@@ -6,3 +6,3 @@ import { lst } from "./misc"

export function iterateBidiSections(order, from, to, f) {
if (!order) return f(from, to, "ltr")
if (!order) return f(from, to, "ltr", 0)
let found = false

@@ -12,3 +12,3 @@ for (let i = 0; i < order.length; ++i) {

if (part.from < to && part.to > from || from == to && part.to == from) {
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr")
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i)
found = true

@@ -15,0 +15,0 @@ }

@@ -137,10 +137,15 @@ export function bind(f) {

// Returns the value from the range [`from`; `to`] that satisfies
// `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`.
// `pred` and is closest to `from`. Assumes that at least `to`
// satisfies `pred`. Supports `from` being greater than `to`.
export function findFirst(pred, from, to) {
// At any point we are certain `to` satisfies `pred`, don't know
// whether `from` does.
let dir = from > to ? -1 : 1
for (;;) {
if (Math.abs(from - to) <= 1) return pred(from) ? from : to
let mid = Math.floor((from + to) / 2)
if (from == to) return from
let midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF)
if (mid == from) return pred(mid) ? from : to
if (pred(mid)) to = mid
else from = mid
else from = mid + dir
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc