1import { _ as __vitePreload } from './index-12d4b00b.js'; 2import { f as fade, B as Block } from './Button-c2bc75a7.js'; 3import { C as Check } from './Check-f7edb5d9.js'; 4import { C as Copy$1 } from './Copy-a69620a8.js'; 5import { S as Static } from './Index-9d23d982.js'; 6import { D as DownloadLink, a as Download$1 } from './DownloadLink-df2b9666.js'; 7import { B as BlockLabel } from './BlockLabel-2a595353.js'; 8import { E as Empty } from './Empty-1a32f00a.js'; 9import Example from './Example-26f7bda8.js'; 10 11/* home/runner/work/gradio/gradio/js/icons/src/Code.svelte generated by Svelte v4.2.2 */ 12const { 13 SvelteComponent: SvelteComponent$5, 14 append: append$3, 15 attr: attr$4, 16 detach: detach$5, 17 init: init$5, 18 insert: insert$6, 19 noop: noop$1, 20 safe_not_equal: safe_not_equal$5, 21 svg_element 22} = window.__gradio__svelte__internal; 23function create_fragment$5(ctx) { 24 let svg; 25 let path; 26 27 return { 28 c() { 29 svg = svg_element("svg"); 30 path = svg_element("path"); 31 attr$4(path, "fill", "currentColor"); 32 attr$4(path, "d", "m31 16l-7 7l-1.41-1.41L28.17 16l-5.58-5.59L24 9l7 7zM1 16l7-7l1.41 1.41L3.83 16l5.58 5.59L8 23l-7-7zm11.42 9.484L17.64 6l1.932.517L14.352 26z"); 33 attr$4(svg, "width", "100%"); 34 attr$4(svg, "height", "100%"); 35 attr$4(svg, "viewBox", "0 0 32 32"); 36 }, 37 m(target, anchor) { 38 insert$6(target, svg, anchor); 39 append$3(svg, path); 40 }, 41 p: noop$1, 42 i: noop$1, 43 o: noop$1, 44 d(detaching) { 45 if (detaching) { 46 detach$5(svg); 47 } 48 } 49 }; 50} 51 52let Code$2 = class Code extends SvelteComponent$5 { 53 constructor(options) { 54 super(); 55 init$5(this, options, null, create_fragment$5, safe_not_equal$5, {}); 56 } 57}; 58 59/** 60The data structure for documents. @nonabstract 61*/ 62class Text { 63 /** 64 @internal 65 */ 66 constructor() { } 67 /** 68 Get the line description around the given position. 69 */ 70 lineAt(pos) { 71 if (pos < 0 || pos > this.length) 72 throw new RangeError(`Invalid position ${pos} in document of length ${this.length}`); 73 return this.lineInner(pos, false, 1, 0); 74 } 75 /** 76 Get the description for the given (1-based) line number. 77 */ 78 line(n) { 79 if (n < 1 || n > this.lines) 80 throw new RangeError(`Invalid line number ${n} in ${this.lines}-line document`); 81 return this.lineInner(n, true, 1, 0); 82 } 83 /** 84 Replace a range of the text with the given content. 85 */ 86 replace(from, to, text) { 87 let parts = []; 88 this.decompose(0, from, parts, 2 /* Open.To */); 89 if (text.length) 90 text.decompose(0, text.length, parts, 1 /* Open.From */ | 2 /* Open.To */); 91 this.decompose(to, this.length, parts, 1 /* Open.From */); 92 return TextNode.from(parts, this.length - (to - from) + text.length); 93 } 94 /** 95 Append another document to this one. 96 */ 97 append(other) { 98 return this.replace(this.length, this.length, other); 99 } 100 /** 101 Retrieve the text between the given points. 102 */ 103 slice(from, to = this.length) { 104 let parts = []; 105 this.decompose(from, to, parts, 0); 106 return TextNode.from(parts, to - from); 107 } 108 /** 109 Test whether this text is equal to another instance. 110 */ 111 eq(other) { 112 if (other == this) 113 return true; 114 if (other.length != this.length || other.lines != this.lines) 115 return false; 116 let start = this.scanIdentical(other, 1), end = this.length - this.scanIdentical(other, -1); 117 let a = new RawTextCursor(this), b = new RawTextCursor(other); 118 for (let skip = start, pos = start;;) { 119 a.next(skip); 120 b.next(skip); 121 skip = 0; 122 if (a.lineBreak != b.lineBreak || a.done != b.done || a.value != b.value) 123 return false; 124 pos += a.value.length; 125 if (a.done || pos >= end) 126 return true; 127 } 128 } 129 /** 130 Iterate over the text. When `dir` is `-1`, iteration happens 131 from end to start. This will return lines and the breaks between 132 them as separate strings. 133 */ 134 iter(dir = 1) { return new RawTextCursor(this, dir); } 135 /** 136 Iterate over a range of the text. When `from` > `to`, the 137 iterator will run in reverse. 138 */ 139 iterRange(from, to = this.length) { return new PartialTextCursor(this, from, to); } 140 /** 141 Return a cursor that iterates over the given range of lines, 142 _without_ returning the line breaks between, and yielding empty 143 strings for empty lines. 144 145 When `from` and `to` are given, they should be 1-based line numbers. 146 */ 147 iterLines(from, to) { 148 let inner; 149 if (from == null) { 150 inner = this.iter(); 151 } 152 else { 153 if (to == null) 154 to = this.lines + 1; 155 let start = this.line(from).from; 156 inner = this.iterRange(start, Math.max(start, to == this.lines + 1 ? this.length : to <= 1 ? 0 : this.line(to - 1).to)); 157 } 158 return new LineCursor(inner); 159 } 160 /** 161 @internal 162 */ 163 toString() { return this.sliceString(0); } 164 /** 165 Convert the document to an array of lines (which can be 166 deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#state.Text^of)). 167 */ 168 toJSON() { 169 let lines = []; 170 this.flatten(lines); 171 return lines; 172 } 173 /** 174 Create a `Text` instance for the given array of lines. 175 */ 176 static of(text) { 177 if (text.length == 0) 178 throw new RangeError("A document must have at least one line"); 179 if (text.length == 1 && !text[0]) 180 return Text.empty; 181 return text.length <= 32 /* Tree.Branch */ ? new TextLeaf(text) : TextNode.from(TextLeaf.split(text, [])); 182 } 183} 184// Leaves store an array of line strings. There are always line breaks 185// between these strings. Leaves are limited in size and have to be 186// contained in TextNode instances for bigger documents. 187class TextLeaf extends Text { 188 constructor(text, length = textLength(text)) { 189 super(); 190 this.text = text; 191 this.length = length; 192 } 193 get lines() { return this.text.length; } 194 get children() { return null; } 195 lineInner(target, isLine, line, offset) { 196 for (let i = 0;; i++) { 197 let string = this.text[i], end = offset + string.length; 198 if ((isLine ? line : end) >= target) 199 return new Line(offset, end, line, string); 200 offset = end + 1; 201 line++; 202 } 203 } 204 decompose(from, to, target, open) { 205 let text = from <= 0 && to >= this.length ? this 206 : new TextLeaf(sliceText(this.text, from, to), Math.min(to, this.length) - Math.max(0, from)); 207 if (open & 1 /* Open.From */) { 208 let prev = target.pop(); 209 let joined = appendText(text.text, prev.text.slice(), 0, text.length); 210 if (joined.length <= 32 /* Tree.Branch */) { 211 target.push(new TextLeaf(joined, prev.length + text.length)); 212 } 213 else { 214 let mid = joined.length >> 1; 215 target.push(new TextLeaf(joined.slice(0, mid)), new TextLeaf(joined.slice(mid))); 216 } 217 } 218 else { 219 target.push(text); 220 } 221 } 222 replace(from, to, text) { 223 if (!(text instanceof TextLeaf)) 224 return super.replace(from, to, text); 225 let lines = appendText(this.text, appendText(text.text, sliceText(this.text, 0, from)), to); 226 let newLen = this.length + text.length - (to - from); 227 if (lines.length <= 32 /* Tree.Branch */) 228 return new TextLeaf(lines, newLen); 229 return TextNode.from(TextLeaf.split(lines, []), newLen); 230 } 231 sliceString(from, to = this.length, lineSep = "\n") { 232 let result = ""; 233 for (let pos = 0, i = 0; pos <= to && i < this.text.length; i++) { 234 let line = this.text[i], end = pos + line.length; 235 if (pos > from && i) 236 result += lineSep; 237 if (from < end && to > pos) 238 result += line.slice(Math.max(0, from - pos), to - pos); 239 pos = end + 1; 240 } 241 return result; 242 } 243 flatten(target) { 244 for (let line of this.text) 245 target.push(line); 246 } 247 scanIdentical() { return 0; } 248 static split(text, target) { 249 let part = [], len = -1; 250 for (let line of text) { 251 part.push(line); 252 len += line.length + 1; 253 if (part.length == 32 /* Tree.Branch */) { 254 target.push(new TextLeaf(part, len)); 255 part = []; 256 len = -1; 257 } 258 } 259 if (len > -1) 260 target.push(new TextLeaf(part, len)); 261 return target; 262 } 263}
vendor: 2,733 bytes, lines 264-321
264// Nodes provide the tree structure of the `Text` type. They store a 265// number of other nodes or leaves, taking care to balance themselves 266// on changes. There are implied line breaks _between_ the children of 267// a node (but not before the first or after the last child). 268class TextNode extends Text { 269 constructor(children, length) { 270 super(); 271 this.children = children; 272 this.length = length; 273 this.lines = 0; 274 for (let child of children) 275 this.lines += child.lines; 276 } 277 lineInner(target, isLine, line, offset) { 278 for (let i = 0;; i++) { 279 let child = this.children[i], end = offset + child.length, endLine = line + child.lines - 1; 280 if ((isLine ? endLine : end) >= target) 281 return child.lineInner(target, isLine, line, offset); 282 offset = end + 1; 283 line = endLine + 1; 284 } 285 } 286 decompose(from, to, target, open) { 287 for (let i = 0, pos = 0; pos <= to && i < this.children.length; i++) { 288 let child = this.children[i], end = pos + child.length; 289 if (from <= end && to >= pos) { 290 let childOpen = open & ((pos <= from ? 1 /* Open.From */ : 0) | (end >= to ? 2 /* Open.To */ : 0)); 291 if (pos >= from && end <= to && !childOpen) 292 target.push(child); 293 else 294 child.decompose(from - pos, to - pos, target, childOpen); 295 } 296 pos = end + 1; 297 } 298 } 299 replace(from, to, text) { 300 if (text.lines < this.lines) 301 for (let i = 0, pos = 0; i < this.children.length; i++) { 302 let child = this.children[i], end = pos + child.length; 303 // Fast path: if the change only affects one child and the 304 // child's size remains in the acceptable range, only update 305 // that child 306 if (from >= pos && to <= end) { 307 let updated = child.replace(from - pos, to - pos, text); 308 let totalLines = this.lines - child.lines + updated.lines; 309 if (updated.lines < (totalLines >> (5 /* Tree.BranchShift */ - 1)) && 310 updated.lines > (totalLines >> (5 /* Tree.BranchShift */ + 1))) { 311 let copy = this.children.slice(); 312 copy[i] = updated; 313 return new TextNode(copy, this.length - (to - from) + text.length); 314 } 315 return super.replace(pos, end, updated); 316 } 317 pos = end + 1; 318 } 319 return super.replace(from, to, text); 320 } 321 sliceString(from, to = this.length, lineSep = "\n") {
vendor: 8,292 bytes, lines 321-543
321 322 let result = ""; 323 for (let i = 0, pos = 0; i < this.children.length && pos <= to; i++) { 324 let child = this.children[i], end = pos + child.length; 325 if (pos > from && i) 326 result += lineSep; 327 if (from < end && to > pos) 328 result += child.sliceString(from - pos, to - pos, lineSep); 329 pos = end + 1; 330 } 331 return result; 332 } 333 flatten(target) { 334 for (let child of this.children) 335 child.flatten(target); 336 } 337 scanIdentical(other, dir) { 338 if (!(other instanceof TextNode)) 339 return 0; 340 let length = 0; 341 let [iA, iB, eA, eB] = dir > 0 ? [0, 0, this.children.length, other.children.length] 342 : [this.children.length - 1, other.children.length - 1, -1, -1]; 343 for (;; iA += dir, iB += dir) { 344 if (iA == eA || iB == eB) 345 return length; 346 let chA = this.children[iA], chB = other.children[iB]; 347 if (chA != chB) 348 return length + chA.scanIdentical(chB, dir); 349 length += chA.length + 1; 350 } 351 } 352 static from(children, length = children.reduce((l, ch) => l + ch.length + 1, -1)) { 353 let lines = 0; 354 for (let ch of children) 355 lines += ch.lines; 356 if (lines < 32 /* Tree.Branch */) { 357 let flat = []; 358 for (let ch of children) 359 ch.flatten(flat); 360 return new TextLeaf(flat, length); 361 } 362 let chunk = Math.max(32 /* Tree.Branch */, lines >> 5 /* Tree.BranchShift */), maxChunk = chunk << 1, minChunk = chunk >> 1; 363 let chunked = [], currentLines = 0, currentLen = -1, currentChunk = []; 364 function add(child) { 365 let last; 366 if (child.lines > maxChunk && child instanceof TextNode) { 367 for (let node of child.children) 368 add(node); 369 } 370 else if (child.lines > minChunk && (currentLines > minChunk || !currentLines)) { 371 flush(); 372 chunked.push(child); 373 } 374 else if (child instanceof TextLeaf && currentLines && 375 (last = currentChunk[currentChunk.length - 1]) instanceof TextLeaf && 376 child.lines + last.lines <= 32 /* Tree.Branch */) { 377 currentLines += child.lines; 378 currentLen += child.length + 1; 379 currentChunk[currentChunk.length - 1] = new TextLeaf(last.text.concat(child.text), last.length + 1 + child.length); 380 } 381 else { 382 if (currentLines + child.lines > chunk) 383 flush(); 384 currentLines += child.lines; 385 currentLen += child.length + 1; 386 currentChunk.push(child); 387 } 388 } 389 function flush() { 390 if (currentLines == 0) 391 return; 392 chunked.push(currentChunk.length == 1 ? currentChunk[0] : TextNode.from(currentChunk, currentLen)); 393 currentLen = -1; 394 currentLines = currentChunk.length = 0; 395 } 396 for (let child of children) 397 add(child); 398 flush(); 399 return chunked.length == 1 ? chunked[0] : new TextNode(chunked, length); 400 } 401} 402Text.empty = /*@__PURE__*/new TextLeaf([""], 0); 403function textLength(text) { 404 let length = -1; 405 for (let line of text) 406 length += line.length + 1; 407 return length; 408} 409function appendText(text, target, from = 0, to = 1e9) { 410 for (let pos = 0, i = 0, first = true; i < text.length && pos <= to; i++) { 411 let line = text[i], end = pos + line.length; 412 if (end >= from) { 413 if (end > to) 414 line = line.slice(0, to - pos); 415 if (pos < from) 416 line = line.slice(from - pos); 417 if (first) { 418 target[target.length - 1] += line; 419 first = false; 420 } 421 else 422 target.push(line); 423 } 424 pos = end + 1; 425 } 426 return target; 427} 428function sliceText(text, from, to) { 429 return appendText(text, [""], from, to); 430} 431class RawTextCursor { 432 constructor(text, dir = 1) { 433 this.dir = dir; 434 this.done = false; 435 this.lineBreak = false; 436 this.value = ""; 437 this.nodes = [text]; 438 this.offsets = [dir > 0 ? 1 : (text instanceof TextLeaf ? text.text.length : text.children.length) << 1]; 439 } 440 nextInner(skip, dir) { 441 this.done = this.lineBreak = false; 442 for (;;) { 443 let last = this.nodes.length - 1; 444 let top = this.nodes[last], offsetValue = this.offsets[last], offset = offsetValue >> 1; 445 let size = top instanceof TextLeaf ? top.text.length : top.children.length; 446 if (offset == (dir > 0 ? size : 0)) { 447 if (last == 0) { 448 this.done = true; 449 this.value = ""; 450 return this; 451 } 452 if (dir > 0) 453 this.offsets[last - 1]++; 454 this.nodes.pop(); 455 this.offsets.pop(); 456 } 457 else if ((offsetValue & 1) == (dir > 0 ? 0 : 1)) { 458 this.offsets[last] += dir; 459 if (skip == 0) { 460 this.lineBreak = true; 461 this.value = "\n"; 462 return this; 463 } 464 skip--; 465 } 466 else if (top instanceof TextLeaf) { 467 // Move to the next string 468 let next = top.text[offset + (dir < 0 ? -1 : 0)]; 469 this.offsets[last] += dir; 470 if (next.length > Math.max(0, skip)) { 471 this.value = skip == 0 ? next : dir > 0 ? next.slice(skip) : next.slice(0, next.length - skip); 472 return this; 473 } 474 skip -= next.length; 475 } 476 else { 477 let next = top.children[offset + (dir < 0 ? -1 : 0)]; 478 if (skip > next.length) { 479 skip -= next.length; 480 this.offsets[last] += dir; 481 } 482 else { 483 if (dir < 0) 484 this.offsets[last]--; 485 this.nodes.push(next); 486 this.offsets.push(dir > 0 ? 1 : (next instanceof TextLeaf ? next.text.length : next.children.length) << 1); 487 } 488 } 489 } 490 } 491 next(skip = 0) { 492 if (skip < 0) { 493 this.nextInner(-skip, (-this.dir)); 494 skip = this.value.length; 495 } 496 return this.nextInner(skip, this.dir); 497 } 498} 499class PartialTextCursor { 500 constructor(text, start, end) { 501 this.value = ""; 502 this.done = false; 503 this.cursor = new RawTextCursor(text, start > end ? -1 : 1); 504 this.pos = start > end ? text.length : 0; 505 this.from = Math.min(start, end); 506 this.to = Math.max(start, end); 507 } 508 nextInner(skip, dir) { 509 if (dir < 0 ? this.pos <= this.from : this.pos >= this.to) { 510 this.value = ""; 511 this.done = true; 512 return this; 513 } 514 skip += Math.max(0, dir < 0 ? this.pos - this.to : this.from - this.pos); 515 let limit = dir < 0 ? this.pos - this.from : this.to - this.pos; 516 if (skip > limit) 517 skip = limit; 518 limit -= skip; 519 let { value } = this.cursor.next(skip); 520 this.pos += (value.length + skip) * dir; 521 this.value = value.length <= limit ? value : dir < 0 ? value.slice(value.length - limit) : value.slice(0, limit); 522 this.done = !this.value; 523 return this; 524 } 525 next(skip = 0) { 526 if (skip < 0) 527 skip = Math.max(skip, this.from - this.pos); 528 else if (skip > 0) 529 skip = Math.min(skip, this.to - this.pos); 530 return this.nextInner(skip, this.cursor.dir); 531 } 532 get lineBreak() { return this.cursor.lineBreak && this.value != ""; } 533} 534class LineCursor { 535 constructor(inner) { 536 this.inner = inner; 537 this.afterBreak = true; 538 this.value = ""; 539 this.done = false; 540 } 541 next(skip = 0) { 542 let { done, lineBreak, value } = this.inner.next(skip); 543 if (done
543) { 544 this.done = true; 545 this.value = ""; 546 } 547 else if (lineBreak) { 548 if (this.afterBreak) { 549 this.value = ""; 550 } 551 else { 552 this.afterBreak = true; 553 this.next(); 554 } 555 } 556 else { 557 this.value = value; 558 this.afterBreak = false; 559 } 560 return this; 561 } 562 get lineBreak() { return false; } 563} 564if (typeof Symbol != "undefined") { 565 Text.prototype[Symbol.iterator] = function () { return this.iter(); }; 566 RawTextCursor.prototype[Symbol.iterator] = PartialTextCursor.prototype[Symbol.iterator] = 567 LineCursor.prototype[Symbol.iterator] = function () { return this; }; 568} 569/** 570This type describes a line in the document. It is created 571on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#state.Text.lineAt). 572*/ 573class Line { 574 /** 575 @internal 576 */ 577 constructor( 578 /** 579 The position of the start of the line. 580 */ 581 from, 582 /** 583 The position at the end of the line (_before_ the line break, 584 or at the end of document for the last line). 585 */ 586 to, 587 /** 588 This line's line number (1-based). 589 */ 590 number, 591 /** 592 The line's content. 593 */ 594 text) { 595 this.from = from; 596 this.to = to; 597 this.number = number; 598 this.text = text; 599 } 600 /** 601 The length of the line (not including any line break after it). 602 */ 603 get length() { return this.to - this.from; } 604} 605 606// Compressed representation of the Grapheme_Cluster_Break=Extend 607// information from 608// http://www.unicode.org/Public/13.0.0/ucd/auxiliary/GraphemeBreakProperty.txt. 609// Each pair of elements represents a range, as an offet from the 610// previous range and a length. Numbers are in base-36, with the empty 611// string being a shorthand for 1. 612let extend = /*@__PURE__*/"lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(s => s ? parseInt(s, 36) : 1); 613// Convert offsets into absolute values 614for (let i = 1; i < extend.length; i++) 615 extend[i] += extend[i - 1]; 616function isExtendingChar(code) { 617 for (let i = 1; i < extend.length; i += 2) 618 if (extend[i] > code) 619 return extend[i - 1] <= code; 620 return false; 621} 622function isRegionalIndicator(code) { 623 return code >= 0x1F1E6 && code <= 0x1F1FF; 624} 625const ZWJ = 0x200d; 626/** 627Returns a next grapheme cluster break _after_ (not equal to) 628`pos`, if `forward` is true, or before otherwise. Returns `pos` 629itself if no further cluster break is available in the string. 630Moves across surrogate pairs, extending characters (when 631`includeExtending` is true), characters joined with zero-width 632joiners, and flag emoji. 633*/ 634function findClusterBreak(str, pos, forward = true, includeExtending = true) { 635 return (forward ? nextClusterBreak : prevClusterBreak)(str, pos, includeExtending); 636} 637function nextClusterBreak(str, pos, includeExtending) { 638 if (pos == str.length) 639 return pos; 640 // If pos is in the middle of a surrogate pair, move to its start 641 if (pos && surrogateLow(str.charCodeAt(pos)) && surrogateHigh(str.charCodeAt(pos - 1))) 642 pos--; 643 let prev = codePointAt(str, pos); 644 pos += codePointSize(prev); 645 while (pos < str.length) { 646 let next = codePointAt(str, pos); 647 if (prev == ZWJ || next == ZWJ || includeExtending && isExtendingChar(next)) { 648 pos += codePointSize(next); 649 prev = next; 650 } 651 else if (isRegionalIndicator(next)) { 652 let countBefore = 0, i = pos - 2; 653 while (i >= 0 && isRegionalIndicator(codePointAt(str, i))) { 654 countBefore++; 655 i -= 2; 656 } 657 if (countBefore % 2 == 0) 658 break; 659 else 660 pos += 2; 661 } 662 else { 663 break; 664 } 665 } 666 return pos; 667} 668function prevClusterBreak(str, pos, includeExtending) { 669 while (pos > 0) { 670 let found = nextClusterBreak(str, pos - 2, includeExtending); 671 if (found < pos) 672 return found; 673 pos--; 674 } 675 return 0; 676} 677function surrogateLow(ch) { return ch >= 0xDC00 && ch < 0xE000; } 678function surrogateHigh(ch) { return ch >= 0xD800 && ch < 0xDC00; } 679/** 680Find the code point at the given position in a string (like the 681[`codePointAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) 682string method). 683*/ 684function codePointAt(str, pos) {
vendor: 4,912 bytes, lines 685-829
685 let code0 = str.charCodeAt(pos); 686 if (!surrogateHigh(code0) || pos + 1 == str.length) 687 return code0; 688 let code1 = str.charCodeAt(pos + 1); 689 if (!surrogateLow(code1)) 690 return code0; 691 return ((code0 - 0xd800) << 10) + (code1 - 0xdc00) + 0x10000; 692} 693/** 694Given a Unicode codepoint, return the JavaScript string that 695respresents it (like 696[`String.fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint)). 697*/ 698function fromCodePoint(code) { 699 if (code <= 0xffff) 700 return String.fromCharCode(code); 701 code -= 0x10000; 702 return String.fromCharCode((code >> 10) + 0xd800, (code & 1023) + 0xdc00); 703} 704/** 705The amount of positions a character takes up a JavaScript string. 706*/ 707function codePointSize(code) { return code < 0x10000 ? 1 : 2; } 708 709const DefaultSplit = /\r\n?|\n/; 710/** 711Distinguishes different ways in which positions can be mapped. 712*/ 713var MapMode = /*@__PURE__*/(function (MapMode) { 714 /** 715 Map a position to a valid new position, even when its context 716 was deleted. 717 */ 718 MapMode[MapMode["Simple"] = 0] = "Simple"; 719 /** 720 Return null if deletion happens across the position. 721 */ 722 MapMode[MapMode["TrackDel"] = 1] = "TrackDel"; 723 /** 724 Return null if the character _before_ the position is deleted. 725 */ 726 MapMode[MapMode["TrackBefore"] = 2] = "TrackBefore"; 727 /** 728 Return null if the character _after_ the position is deleted. 729 */ 730 MapMode[MapMode["TrackAfter"] = 3] = "TrackAfter"; 731return MapMode})(MapMode || (MapMode = {})); 732/** 733A change description is a variant of [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet) 734that doesn't store the inserted text. As such, it can't be 735applied, but is cheaper to store and manipulate. 736*/ 737class ChangeDesc { 738 // Sections are encoded as pairs of integers. The first is the 739 // length in the current document, and the second is -1 for 740 // unaffected sections, and the length of the replacement content 741 // otherwise. So an insertion would be (0, n>0), a deletion (n>0, 742 // 0), and a replacement two positive numbers. 743 /** 744 @internal 745 */ 746 constructor( 747 /** 748 @internal 749 */ 750 sections) { 751 this.sections = sections; 752 } 753 /** 754 The length of the document before the change. 755 */ 756 get length() { 757 let result = 0; 758 for (let i = 0; i < this.sections.length; i += 2) 759 result += this.sections[i]; 760 return result; 761 } 762 /** 763 The length of the document after the change. 764 */ 765 get newLength() { 766 let result = 0; 767 for (let i = 0; i < this.sections.length; i += 2) { 768 let ins = this.sections[i + 1]; 769 result += ins < 0 ? this.sections[i] : ins; 770 } 771 return result; 772 } 773 /** 774 False when there are actual changes in this set. 775 */ 776 get empty() { return this.sections.length == 0 || this.sections.length == 2 && this.sections[1] < 0; } 777 /** 778 Iterate over the unchanged parts left by these changes. `posA` 779 provides the position of the range in the old document, `posB` 780 the new position in the changed document. 781 */ 782 iterGaps(f) { 783 for (let i = 0, posA = 0, posB = 0; i < this.sections.length;) { 784 let len = this.sections[i++], ins = this.sections[i++]; 785 if (ins < 0) { 786 f(posA, posB, len); 787 posB += len; 788 } 789 else { 790 posB += ins; 791 } 792 posA += len; 793 } 794 } 795 /** 796 Iterate over the ranges changed by these changes. (See 797 [`ChangeSet.iterChanges`](https://codemirror.net/6/docs/ref/#state.ChangeSet.iterChanges) for a 798 variant that also provides you with the inserted text.) 799 `fromA`/`toA` provides the extent of the change in the starting 800 document, `fromB`/`toB` the extent of the replacement in the 801 changed document. 802 803 When `individual` is true, adjacent changes (which are kept 804 separate for [position mapping](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) are 805 reported separately. 806 */ 807 iterChangedRanges(f, individual = false) { 808 iterChanges(this, f, individual); 809 } 810 /** 811 Get a description of the inverted form of these changes. 812 */ 813 get invertedDesc() { 814 let sections = []; 815 for (let i = 0; i < this.sections.length;) { 816 let len = this.sections[i++], ins = this.sections[i++]; 817 if (ins < 0) 818 sections.push(len, ins); 819 else 820 sections.push(ins, len); 821 } 822 return new ChangeDesc(sections); 823 } 824 /** 825 Compute the combined effect of applying another set of changes 826 after this one. The length of the document after this set should 827 match the length before `other`. 828 */ 829 composeDesc(other) { return this.empty ? other : other.empty ? this
829: composeSets(this, other); } 830 /** 831 Map this description, which should start with the same document 832 as `other`, over another set of changes, so that it can be 833 applied after it. When `before` is true, map as if the changes 834 in `other` happened before the ones in `this
vendor: 11,648 bytes, lines 834-1137
834`. 835 */ 836 mapDesc(other, before = false) { return other.empty ? this : mapSet(this, other, before); } 837 mapPos(pos, assoc = -1, mode = MapMode.Simple) { 838 let posA = 0, posB = 0; 839 for (let i = 0; i < this.sections.length;) { 840 let len = this.sections[i++], ins = this.sections[i++], endA = posA + len; 841 if (ins < 0) { 842 if (endA > pos) 843 return posB + (pos - posA); 844 posB += len; 845 } 846 else { 847 if (mode != MapMode.Simple && endA >= pos && 848 (mode == MapMode.TrackDel && posA < pos && endA > pos || 849 mode == MapMode.TrackBefore && posA < pos || 850 mode == MapMode.TrackAfter && endA > pos)) 851 return null; 852 if (endA > pos || endA == pos && assoc < 0 && !len) 853 return pos == posA || assoc < 0 ? posB : posB + ins; 854 posB += ins; 855 } 856 posA = endA; 857 } 858 if (pos > posA) 859 throw new RangeError(`Position ${pos} is out of range for changeset of length ${posA}`); 860 return posB; 861 } 862 /** 863 Check whether these changes touch a given range. When one of the 864 changes entirely covers the range, the string `"cover"` is 865 returned. 866 */ 867 touchesRange(from, to = from) { 868 for (let i = 0, pos = 0; i < this.sections.length && pos <= to;) { 869 let len = this.sections[i++], ins = this.sections[i++], end = pos + len; 870 if (ins >= 0 && pos <= to && end >= from) 871 return pos < from && end > to ? "cover" : true; 872 pos = end; 873 } 874 return false; 875 } 876 /** 877 @internal 878 */ 879 toString() { 880 let result = ""; 881 for (let i = 0; i < this.sections.length;) { 882 let len = this.sections[i++], ins = this.sections[i++]; 883 result += (result ? " " : "") + len + (ins >= 0 ? ":" + ins : ""); 884 } 885 return result; 886 } 887 /** 888 Serialize this change desc to a JSON-representable value. 889 */ 890 toJSON() { return this.sections; } 891 /** 892 Create a change desc from its JSON representation (as produced 893 by [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeDesc.toJSON). 894 */ 895 static fromJSON(json) { 896 if (!Array.isArray(json) || json.length % 2 || json.some(a => typeof a != "number")) 897 throw new RangeError("Invalid JSON representation of ChangeDesc"); 898 return new ChangeDesc(json); 899 } 900 /** 901 @internal 902 */ 903 static create(sections) { return new ChangeDesc(sections); } 904} 905/** 906A change set represents a group of modifications to a document. It 907stores the document length, and can only be applied to documents 908with exactly that length. 909*/ 910class ChangeSet extends ChangeDesc { 911 constructor(sections, 912 /** 913 @internal 914 */ 915 inserted) { 916 super(sections); 917 this.inserted = inserted; 918 } 919 /** 920 Apply the changes to a document, returning the modified 921 document. 922 */ 923 apply(doc) { 924 if (this.length != doc.length) 925 throw new RangeError("Applying change set to a document with the wrong length"); 926 iterChanges(this, (fromA, toA, fromB, _toB, text) => doc = doc.replace(fromB, fromB + (toA - fromA), text), false); 927 return doc; 928 } 929 mapDesc(other, before = false) { return mapSet(this, other, before, true); } 930 /** 931 Given the document as it existed _before_ the changes, return a 932 change set that represents the inverse of this set, which could 933 be used to go from the document created by the changes back to 934 the document as it existed before the changes. 935 */ 936 invert(doc) { 937 let sections = this.sections.slice(), inserted = []; 938 for (let i = 0, pos = 0; i < sections.length; i += 2) { 939 let len = sections[i], ins = sections[i + 1]; 940 if (ins >= 0) { 941 sections[i] = ins; 942 sections[i + 1] = len; 943 let index = i >> 1; 944 while (inserted.length < index) 945 inserted.push(Text.empty); 946 inserted.push(len ? doc.slice(pos, pos + len) : Text.empty); 947 } 948 pos += len; 949 } 950 return new ChangeSet(sections, inserted); 951 } 952 /** 953 Combine two subsequent change sets into a single set. `other` 954 must start in the document produced by `this`. If `this` goes 955 `docA` â `docB` and `other` represents `docB` â `docC`, the 956 returned value will represent the change `docA` â `docC`. 957 */ 958 compose(other) { return this.empty ? other : other.empty ? this : composeSets(this, other, true); } 959 /** 960 Given another change set starting in the same document, maps this 961 change set over the other, producing a new change set that can be 962 applied to the document produced by applying `other`. When 963 `before` is `true`, order changes as if `this` comes before 964 `other`, otherwise (the default) treat `other` as coming first. 965 966 Given two changes `A` and `B`, `A.compose(B.map(A))` and 967 `B.compose(A.map(B, true))` will produce the same document. This 968 provides a basic form of [operational 969 transformation](https://en.wikipedia.org/wiki/Operational_transformation), 970 and can be used for collaborative editing. 971 */ 972 map(other, before = false) { return other.empty ? this : mapSet(this, other, before, true); } 973 /** 974 Iterate over the changed ranges in the document, calling `f` for 975 each, with the range in the original document (`fromA`-`toA`) 976 and the range that replaces it in the new document 977 (`fromB`-`toB`). 978 979 When `individual` is true, adjacent changes are reported 980 separately. 981 */ 982 iterChanges(f, individual = false) { 983 iterChanges(this, f, individual); 984 } 985 /** 986 Get a [change description](https://codemirror.net/6/docs/ref/#state.ChangeDesc) for this change 987 set. 988 */ 989 get desc() { return ChangeDesc.create(this.sections); } 990 /** 991 @internal 992 */ 993 filter(ranges) { 994 let resultSections = [], resultInserted = [], filteredSections = []; 995 let iter = new SectionIter(this); 996 done: for (let i = 0, pos = 0;;) { 997 let next = i == ranges.length ? 1e9 : ranges[i++]; 998 while (pos < next || pos == next && iter.len == 0) { 999 if (iter.done) 1000 break done; 1001 let len = Math.min(iter.len, next - pos); 1002 addSection(filteredSections, len, -1); 1003 let ins = iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0; 1004 addSection(resultSections, len, ins); 1005 if (ins > 0) 1006 addInsert(resultInserted, resultSections, iter.text); 1007 iter.forward(len); 1008 pos += len; 1009 } 1010 let end = ranges[i++]; 1011 while (pos < end) { 1012 if (iter.done) 1013 break done; 1014 let len = Math.min(iter.len, end - pos); 1015 addSection(resultSections, len, -1); 1016 addSection(filteredSections, len, iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0); 1017 iter.forward(len); 1018 pos += len; 1019 } 1020 } 1021 return { changes: new ChangeSet(resultSections, resultInserted), 1022 filtered: ChangeDesc.create(filteredSections) }; 1023 } 1024 /** 1025 Serialize this change set to a JSON-representable value. 1026 */ 1027 toJSON() { 1028 let parts = []; 1029 for (let i = 0; i < this.sections.length; i += 2) { 1030 let len = this.sections[i], ins = this.sections[i + 1]; 1031 if (ins < 0) 1032 parts.push(len); 1033 else if (ins == 0) 1034 parts.push([len]); 1035 else 1036 parts.push([len].concat(this.inserted[i >> 1].toJSON())); 1037 } 1038 return parts; 1039 } 1040 /** 1041 Create a change set for the given changes, for a document of the 1042 given length, using `lineSep` as line separator. 1043 */ 1044 static of(changes, length, lineSep) { 1045 let sections = [], inserted = [], pos = 0; 1046 let total = null; 1047 function flush(force = false) { 1048 if (!force && !sections.length) 1049 return; 1050 if (pos < length) 1051 addSection(sections, length - pos, -1); 1052 let set = new ChangeSet(sections, inserted); 1053 total = total ? total.compose(set.map(total)) : set; 1054 sections = []; 1055 inserted = []; 1056 pos = 0; 1057 } 1058 function process(spec) { 1059 if (Array.isArray(spec)) { 1060 for (let sub of spec) 1061 process(sub); 1062 } 1063 else if (spec instanceof ChangeSet) { 1064 if (spec.length != length) 1065 throw new RangeError(`Mismatched change set length (got ${spec.length}, expected ${length})`); 1066 flush(); 1067 total = total ? total.compose(spec.map(total)) : spec; 1068 } 1069 else { 1070 let { from, to = from, insert } = spec; 1071 if (from > to || from < 0 || to > length) 1072 throw new RangeError(`Invalid change range ${from} to ${to} (in doc of length ${length})`); 1073 let insText = !insert ? Text.empty : typeof insert == "string" ? Text.of(insert.split(lineSep || DefaultSplit)) : insert; 1074 let insLen = insText.length; 1075 if (from == to && insLen == 0) 1076 return; 1077 if (from < pos) 1078 flush(); 1079 if (from > pos) 1080 addSection(sections, from - pos, -1); 1081 addSection(sections, to - from, insLen); 1082 addInsert(inserted, sections, insText); 1083 pos = to; 1084 } 1085 } 1086 process(changes); 1087 flush(!total); 1088 return total; 1089 } 1090 /** 1091 Create an empty changeset of the given length. 1092 */ 1093 static empty(length) { 1094 return new ChangeSet(length ? [length, -1] : [], []); 1095 } 1096 /** 1097 Create a changeset from its JSON representation (as produced by 1098 [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeSet.toJSON). 1099 */ 1100 static fromJSON(json) { 1101 if (!Array.isArray(json)) 1102 throw new RangeError("Invalid JSON representation of ChangeSet"); 1103 let sections = [], inserted = []; 1104 for (let i = 0; i < json.length; i++) { 1105 let part = json[i]; 1106 if (typeof part == "number") { 1107 sections.push(part, -1); 1108 } 1109 else if (!Array.isArray(part) || typeof part[0] != "number" || part.some((e, i) => i && typeof e != "string")) { 1110 throw new RangeError("Invalid JSON representation of ChangeSet"); 1111 } 1112 else if (part.length == 1) { 1113 sections.push(part[0], 0); 1114 } 1115 else { 1116 while (inserted.length < i) 1117 inserted.push(Text.empty); 1118 inserted[i] = Text.of(part.slice(1)); 1119 sections.push(part[0], inserted[i].length); 1120 } 1121 } 1122 return new ChangeSet(sections, inserted); 1123 } 1124 /** 1125 @internal 1126 */ 1127 static createSet(sections, inserted) { 1128 return new ChangeSet(sections, inserted); 1129 } 1130} 1131function addSection(sections, len, ins, forceJoin = false) { 1132 if (len == 0 && ins <= 0) 1133 return; 1134 let last = sections.length - 2; 1135 if (last >= 0 && ins <= 0 && ins == sections[last + 1]) 1136 sections[last] += len; 1137 else if (l
vendor: 7,736 bytes, lines 1137-1359
1137en == 0 && sections[last] == 0) 1138 sections[last + 1] += ins; 1139 else if (forceJoin) { 1140 sections[last] += len; 1141 sections[last + 1] += ins; 1142 } 1143 else 1144 sections.push(len, ins); 1145} 1146function addInsert(values, sections, value) { 1147 if (value.length == 0) 1148 return; 1149 let index = (sections.length - 2) >> 1; 1150 if (index < values.length) { 1151 values[values.length - 1] = values[values.length - 1].append(value); 1152 } 1153 else { 1154 while (values.length < index) 1155 values.push(Text.empty); 1156 values.push(value); 1157 } 1158} 1159function iterChanges(desc, f, individual) { 1160 let inserted = desc.inserted; 1161 for (let posA = 0, posB = 0, i = 0; i < desc.sections.length;) { 1162 let len = desc.sections[i++], ins = desc.sections[i++]; 1163 if (ins < 0) { 1164 posA += len; 1165 posB += len; 1166 } 1167 else { 1168 let endA = posA, endB = posB, text = Text.empty; 1169 for (;;) { 1170 endA += len; 1171 endB += ins; 1172 if (ins && inserted) 1173 text = text.append(inserted[(i - 2) >> 1]); 1174 if (individual || i == desc.sections.length || desc.sections[i + 1] < 0) 1175 break; 1176 len = desc.sections[i++]; 1177 ins = desc.sections[i++]; 1178 } 1179 f(posA, endA, posB, endB, text); 1180 posA = endA; 1181 posB = endB; 1182 } 1183 } 1184} 1185function mapSet(setA, setB, before, mkSet = false) { 1186 // Produce a copy of setA that applies to the document after setB 1187 // has been applied (assuming both start at the same document). 1188 let sections = [], insert = mkSet ? [] : null; 1189 let a = new SectionIter(setA), b = new SectionIter(setB); 1190 // Iterate over both sets in parallel. inserted tracks, for changes 1191 // in A that have to be processed piece-by-piece, whether their 1192 // content has been inserted already, and refers to the section 1193 // index. 1194 for (let inserted = -1;;) { 1195 if (a.ins == -1 && b.ins == -1) { 1196 // Move across ranges skipped by both sets. 1197 let len = Math.min(a.len, b.len); 1198 addSection(sections, len, -1); 1199 a.forward(len); 1200 b.forward(len); 1201 } 1202 else if (b.ins >= 0 && (a.ins < 0 || inserted == a.i || a.off == 0 && (b.len < a.len || b.len == a.len && !before))) { 1203 // If there's a change in B that comes before the next change in 1204 // A (ordered by start pos, then len, then before flag), skip 1205 // that (and process any changes in A it covers). 1206 let len = b.len; 1207 addSection(sections, b.ins, -1); 1208 while (len) { 1209 let piece = Math.min(a.len, len); 1210 if (a.ins >= 0 && inserted < a.i && a.len <= piece) { 1211 addSection(sections, 0, a.ins); 1212 if (insert) 1213 addInsert(insert, sections, a.text); 1214 inserted = a.i; 1215 } 1216 a.forward(piece); 1217 len -= piece; 1218 } 1219 b.next(); 1220 } 1221 else if (a.ins >= 0) { 1222 // Process the part of a change in A up to the start of the next 1223 // non-deletion change in B (if overlapping). 1224 let len = 0, left = a.len; 1225 while (left) { 1226 if (b.ins == -1) { 1227 let piece = Math.min(left, b.len); 1228 len += piece; 1229 left -= piece; 1230 b.forward(piece); 1231 } 1232 else if (b.ins == 0 && b.len < left) { 1233 left -= b.len; 1234 b.next(); 1235 } 1236 else { 1237 break; 1238 } 1239 } 1240 addSection(sections, len, inserted < a.i ? a.ins : 0); 1241 if (insert && inserted < a.i) 1242 addInsert(insert, sections, a.text); 1243 inserted = a.i; 1244 a.forward(a.len - left); 1245 } 1246 else if (a.done && b.done) { 1247 return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections); 1248 } 1249 else { 1250 throw new Error("Mismatched change set lengths"); 1251 } 1252 } 1253} 1254function composeSets(setA, setB, mkSet = false) { 1255 let sections = []; 1256 let insert = mkSet ? [] : null; 1257 let a = new SectionIter(setA), b = new SectionIter(setB); 1258 for (let open = false;;) { 1259 if (a.done && b.done) { 1260 return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections); 1261 } 1262 else if (a.ins == 0) { // Deletion in A 1263 addSection(sections, a.len, 0, open); 1264 a.next(); 1265 } 1266 else if (b.len == 0 && !b.done) { // Insertion in B 1267 addSection(sections, 0, b.ins, open); 1268 if (insert) 1269 addInsert(insert, sections, b.text); 1270 b.next(); 1271 } 1272 else if (a.done || b.done) { 1273 throw new Error("Mismatched change set lengths"); 1274 } 1275 else { 1276 let len = Math.min(a.len2, b.len), sectionLen = sections.length; 1277 if (a.ins == -1) { 1278 let insB = b.ins == -1 ? -1 : b.off ? 0 : b.ins; 1279 addSection(sections, len, insB, open); 1280 if (insert && insB) 1281 addInsert(insert, sections, b.text); 1282 } 1283 else if (b.ins == -1) { 1284 addSection(sections, a.off ? 0 : a.len, len, open); 1285 if (insert) 1286 addInsert(insert, sections, a.textBit(len)); 1287 } 1288 else { 1289 addSection(sections, a.off ? 0 : a.len, b.off ? 0 : b.ins, open); 1290 if (insert && !b.off) 1291 addInsert(insert, sections, b.text); 1292 } 1293 open = (a.ins > len || b.ins >= 0 && b.len > len) && (open || sections.length > sectionLen); 1294 a.forward2(len); 1295 b.forward(len); 1296 } 1297 } 1298} 1299class SectionIter { 1300 constructor(set) { 1301 this.set = set; 1302 this.i = 0; 1303 this.next(); 1304 } 1305 next() { 1306 let { sections } = this.set; 1307 if (this.i < sections.length) { 1308 this.len = sections[this.i++]; 1309 this.ins = sections[this.i++]; 1310 } 1311 else { 1312 this.len = 0; 1313 this.ins = -2; 1314 } 1315 this.off = 0; 1316 } 1317 get done() { return this.ins == -2; } 1318 get len2() { return this.ins < 0 ? this.len : this.ins; } 1319 get text() { 1320 let { inserted } = this.set, index = (this.i - 2) >> 1; 1321 return index >= inserted.length ? Text.empty : inserted[index]; 1322 } 1323 textBit(len) { 1324 let { inserted } = this.set, index = (this.i - 2) >> 1; 1325 return index >= inserted.length && !len ? Text.empty 1326 : inserted[index].slice(this.off, len == null ? undefined : this.off + len); 1327 } 1328 forward(len) { 1329 if (len == this.len) 1330 this.next(); 1331 else { 1332 this.len -= len; 1333 this.off += len; 1334 } 1335 } 1336 forward2(len) { 1337 if (this.ins == -1) 1338 this.forward(len); 1339 else if (len == this.ins) 1340 this.next(); 1341 else { 1342 this.ins -= len; 1343 this.off += len; 1344 } 1345 } 1346} 1347 1348/** 1349A single selection range. When 1350[`allowMultipleSelections`](https://codemirror.net/6/docs/ref/#state.EditorState^allowMultipleSelections) 1351is enabled, a [selection](https://codemirror.net/6/docs/ref/#state.EditorSelection) may hold 1352multiple ranges. By default, selections hold exactly one range. 1353*/ 1354class SelectionRange { 1355 constructor( 1356 /** 1357 The lower boundary of the range. 1358 */ 1359 from,
vendor: 4,324 bytes, lines 1360-1490
1360 /** 1361 The upper boundary of the range. 1362 */ 1363 to, flags) { 1364 this.from = from; 1365 this.to = to; 1366 this.flags = flags; 1367 } 1368 /** 1369 The anchor of the rangeâthe side that doesn't move when you 1370 extend it. 1371 */ 1372 get anchor() { return this.flags & 16 /* RangeFlag.Inverted */ ? this.to : this.from; } 1373 /** 1374 The head of the range, which is moved when the range is 1375 [extended](https://codemirror.net/6/docs/ref/#state.SelectionRange.extend). 1376 */ 1377 get head() { return this.flags & 16 /* RangeFlag.Inverted */ ? this.from : this.to; } 1378 /** 1379 True when `anchor` and `head` are at the same position. 1380 */ 1381 get empty() { return this.from == this.to; } 1382 /** 1383 If this is a cursor that is explicitly associated with the 1384 character on one of its sides, this returns the side. -1 means 1385 the character before its position, 1 the character after, and 0 1386 means no association. 1387 */ 1388 get assoc() { return this.flags & 4 /* RangeFlag.AssocBefore */ ? -1 : this.flags & 8 /* RangeFlag.AssocAfter */ ? 1 : 0; } 1389 /** 1390 The bidirectional text level associated with this cursor, if 1391 any. 1392 */ 1393 get bidiLevel() { 1394 let level = this.flags & 3 /* RangeFlag.BidiLevelMask */; 1395 return level == 3 ? null : level; 1396 } 1397 /** 1398 The goal column (stored vertical offset) associated with a 1399 cursor. This is used to preserve the vertical position when 1400 [moving](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) across 1401 lines of different length. 1402 */ 1403 get goalColumn() { 1404 let value = this.flags >> 5 /* RangeFlag.GoalColumnOffset */; 1405 return value == 33554431 /* RangeFlag.NoGoalColumn */ ? undefined : value; 1406 } 1407 /** 1408 Map this range through a change, producing a valid range in the 1409 updated document. 1410 */ 1411 map(change, assoc = -1) { 1412 let from, to; 1413 if (this.empty) { 1414 from = to = change.mapPos(this.from, assoc); 1415 } 1416 else { 1417 from = change.mapPos(this.from, 1); 1418 to = change.mapPos(this.to, -1); 1419 } 1420 return from == this.from && to == this.to ? this : new SelectionRange(from, to, this.flags); 1421 } 1422 /** 1423 Extend this range to cover at least `from` to `to`. 1424 */ 1425 extend(from, to = from) { 1426 if (from <= this.anchor && to >= this.anchor) 1427 return EditorSelection.range(from, to); 1428 let head = Math.abs(from - this.anchor) > Math.abs(to - this.anchor) ? from : to; 1429 return EditorSelection.range(this.anchor, head); 1430 } 1431 /** 1432 Compare this range to another range. 1433 */ 1434 eq(other) { 1435 return this.anchor == other.anchor && this.head == other.head; 1436 } 1437 /** 1438 Return a JSON-serializable object representing the range. 1439 */ 1440 toJSON() { return { anchor: this.anchor, head: this.head }; } 1441 /** 1442 Convert a JSON representation of a range to a `SelectionRange` 1443 instance. 1444 */ 1445 static fromJSON(json) { 1446 if (!json || typeof json.anchor != "number" || typeof json.head != "number") 1447 throw new RangeError("Invalid JSON representation for SelectionRange"); 1448 return EditorSelection.range(json.anchor, json.head); 1449 } 1450 /** 1451 @internal 1452 */ 1453 static create(from, to, flags) { 1454 return new SelectionRange(from, to, flags); 1455 } 1456} 1457/** 1458An editor selection holds one or more selection ranges. 1459*/ 1460class EditorSelection { 1461 constructor( 1462 /** 1463 The ranges in the selection, sorted by position. Ranges cannot 1464 overlap (but they may touch, if they aren't empty). 1465 */ 1466 ranges, 1467 /** 1468 The index of the _main_ range in the selection (which is 1469 usually the range that was added last). 1470 */ 1471 mainIndex) { 1472 this.ranges = ranges; 1473 this.mainIndex = mainIndex; 1474 } 1475 /** 1476 Map a selection through a change. Used to adjust the selection 1477 position for changes. 1478 */ 1479 map(change, assoc = -1) { 1480 if (change.empty) 1481 return this; 1482 return EditorSelection.create(this.ranges.map(r => r.map(change, assoc)), this.mainIndex); 1483 } 1484 /** 1485 Compare this selection to another selection. 1486 */ 1487 eq(other) { 1488 if (this.ranges.length != other.ranges.length || 1489 this.mainIndex != other.mainIndex) 1490 return false;
1491 for (let i = 0; i < this.ranges.length; i++) 1492 if (!this.ranges[i].eq(other.ranges[i])) 1493 return false; 1494 return true; 1495 } 1496 /** 1497 Get the primary selection range. Usually, you should make sure 1498 your code applies to _all_ ranges, by using methods like 1499 [`changeByRange`](https://codemirror.net/6/docs/ref/#state.EditorState.changeByRange). 1500 */ 1501 get main() { return this.ranges[this.mainIndex]; } 1502 /** 1503 Make sure the selection only has one range. Returns a selection 1504 holding only the main range from this selection. 1505 */ 1506 asSingle() { 1507 return this.ranges.length == 1 ? this : new EditorSelection([this.main], 0); 1508 } 1509 /** 1510 Extend this selection with an extra range. 1511 */ 1512 addRange(range, main = true) { 1513 return EditorSelection.create([range].concat(this.ranges), main ? 0 : this.mainIndex + 1); 1514 } 1515 /** 1516 Replace a given range with another range, and then normalize the 1517 selection to merge and sort ranges if necessary. 1518 */ 1519 replaceRange(range, which = this.mainIndex) { 1520 let ranges = this.ranges.slice(); 1521 ranges[which] = range; 1522 return EditorSelection.create(ranges, this.mainIndex); 1523 } 1524 /** 1525 Convert this selection to an object that can be serialized to 1526 JSON. 1527 */ 1528 toJSON() { 1529 return { ranges: this.ranges.map(r => r.toJSON()), main: this.mainIndex }; 1530 } 1531 /** 1532 Create a selection from a JSON representation. 1533 */ 1534 static fromJSON(json) { 1535 if (!json || !Array.isArray(json.ranges) || typeof json.main != "number" || json.main >= json.ranges.length) 1536 throw new RangeError("Invalid JSON representation for EditorSelection"); 1537 return new EditorSelection(json.ranges.map((r) => SelectionRange.fromJSON(r)), json.main); 1538 } 1539 /** 1540 Create a selection holding a single range. 1541 */ 1542 static single(anchor, head = anchor) { 1543 return new EditorSelection([EditorSelection.range(anchor, head)], 0); 1544 } 1545 /** 1546 Sort and merge the given set of ranges, creating a valid 1547 selection. 1548 */ 1549 static create(ranges, mainIndex = 0) { 1550 if (ranges.length == 0) 1551 throw new RangeError("A selection needs at least one range"); 1552 for (let pos = 0, i = 0; i < ranges.length; i++) { 1553 let range = ranges[i]; 1554 if (range.empty ? range.from <= pos : range.from < pos) 1555 return EditorSelection.normalized(ranges.slice(), mainIndex); 1556 pos = range.to; 1557 } 1558 return new EditorSelection(ranges, mainIndex); 1559 } 1560 /** 1561 Create a cursor selection range at the given position. You can 1562 safely ignore the optional arguments in most situations. 1563 */ 1564 static cursor(pos, assoc = 0, bidiLevel, goalColumn) { 1565 return SelectionRange.create(pos, pos, (assoc == 0 ? 0 : assoc < 0 ? 4 /* RangeFlag.AssocBefore */ : 8 /* RangeFlag.AssocAfter */) | 1566 (bidiLevel == null ? 3 : Math.min(2, bidiLevel)) | 1567 ((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 33554431 /* RangeFlag.NoGoalColumn */) << 5 /* RangeFlag.GoalColumnOffset */)); 1568 } 1569 /** 1570 Create a selection range. 1571 */ 1572 static range(anchor, head, goalColumn) { 1573 let goal = (goalColumn !== null && goalColumn !== void 0 ? goalColumn : 33554431 /* RangeFlag.NoGoalColumn */) << 5 /* RangeFlag.GoalColumnOffset */; 1574 return head < anchor ? SelectionRange.create(head, anchor, 16 /* RangeFlag.Inverted */ | goal | 8 /* RangeFlag.AssocAfter */) 1575 : SelectionRange.create(anchor, head, goal | (head > anchor ? 4 /* RangeFlag.AssocBefore */ : 0)); 1576 } 1577 /** 1578 @internal 1579 */ 1580 static normalized(ranges, mainIndex = 0) { 1581 let main = ranges[mainIndex]; 1582 ranges.sort((a, b) => a.from - b.from); 1583 mainIndex = ranges.indexOf(main); 1584 for (let i = 1; i < ranges.length; i++) { 1585 let range = ranges[i], prev = ranges[i - 1]; 1586 if (range.empty ? range.from <= prev.to : range.from < prev.to) { 1587 let from = prev.from, to = Math.max(range.to, prev.to); 1588 if (i <= mainIndex) 1589 mainIndex--; 1590 ranges.splice(--i, 2, range.anchor > range.head ? EditorSelection.range(to, from) : EditorSelection.range(from, to)); 1591 } 1592 } 1593 return new EditorSelection(ranges, mainIndex); 1594 } 1595} 1596function checkSelection(selection, docLength) { 1597 for (let range of selection.ranges) 1598 if (range.to > docLength) 1599 throw new RangeError("Selection points outside of document"); 1600} 1601 1602let nextID = 0; 1603/** 1604A facet is a labeled value that is associated with an editor
vendor: 19,007 bytes, lines 1605-2118
1605state. It takes inputs from any number of extensions, and combines 1606those into a single output value. 1607 1608Examples of uses of facets are the [tab 1609size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize), [editor 1610attributes](https://codemirror.net/6/docs/ref/#view.EditorView^editorAttributes), and [update 1611listeners](https://codemirror.net/6/docs/ref/#view.EditorView^updateListener). 1612*/ 1613class Facet { 1614 constructor( 1615 /** 1616 @internal 1617 */ 1618 combine, 1619 /** 1620 @internal 1621 */ 1622 compareInput, 1623 /** 1624 @internal 1625 */ 1626 compare, isStatic, enables) { 1627 this.combine = combine; 1628 this.compareInput = compareInput; 1629 this.compare = compare; 1630 this.isStatic = isStatic; 1631 /** 1632 @internal 1633 */ 1634 this.id = nextID++; 1635 this.default = combine([]); 1636 this.extensions = typeof enables == "function" ? enables(this) : enables; 1637 } 1638 /** 1639 Define a new facet. 1640 */ 1641 static define(config = {}) { 1642 return new Facet(config.combine || ((a) => a), config.compareInput || ((a, b) => a === b), config.compare || (!config.combine ? sameArray$1 : (a, b) => a === b), !!config.static, config.enables); 1643 } 1644 /** 1645 Returns an extension that adds the given value to this facet. 1646 */ 1647 of(value) { 1648 return new FacetProvider([], this, 0 /* Provider.Static */, value); 1649 } 1650 /** 1651 Create an extension that computes a value for the facet from a 1652 state. You must take care to declare the parts of the state that 1653 this value depends on, since your function is only called again 1654 for a new state when one of those parts changed. 1655 1656 In cases where your value depends only on a single field, you'll 1657 want to use the [`from`](https://codemirror.net/6/docs/ref/#state.Facet.from) method instead. 1658 */ 1659 compute(deps, get) { 1660 if (this.isStatic) 1661 throw new Error("Can't compute a static facet"); 1662 return new FacetProvider(deps, this, 1 /* Provider.Single */, get); 1663 } 1664 /** 1665 Create an extension that computes zero or more values for this 1666 facet from a state. 1667 */ 1668 computeN(deps, get) { 1669 if (this.isStatic) 1670 throw new Error("Can't compute a static facet"); 1671 return new FacetProvider(deps, this, 2 /* Provider.Multi */, get); 1672 } 1673 from(field, get) { 1674 if (!get) 1675 get = x => x; 1676 return this.compute([field], state => get(state.field(field))); 1677 } 1678} 1679function sameArray$1(a, b) { 1680 return a == b || a.length == b.length && a.every((e, i) => e === b[i]); 1681} 1682class FacetProvider { 1683 constructor(dependencies, facet, type, value) { 1684 this.dependencies = dependencies; 1685 this.facet = facet; 1686 this.type = type; 1687 this.value = value; 1688 this.id = nextID++; 1689 } 1690 dynamicSlot(addresses) { 1691 var _a; 1692 let getter = this.value; 1693 let compare = this.facet.compareInput; 1694 let id = this.id, idx = addresses[id] >> 1, multi = this.type == 2 /* Provider.Multi */; 1695 let depDoc = false, depSel = false, depAddrs = []; 1696 for (let dep of this.dependencies) { 1697 if (dep == "doc") 1698 depDoc = true; 1699 else if (dep == "selection") 1700 depSel = true; 1701 else if ((((_a = addresses[dep.id]) !== null && _a !== void 0 ? _a : 1) & 1) == 0) 1702 depAddrs.push(addresses[dep.id]); 1703 } 1704 return { 1705 create(state) { 1706 state.values[idx] = getter(state); 1707 return 1 /* SlotStatus.Changed */; 1708 }, 1709 update(state, tr) { 1710 if ((depDoc && tr.docChanged) || (depSel && (tr.docChanged || tr.selection)) || ensureAll(state, depAddrs)) { 1711 let newVal = getter(state); 1712 if (multi ? !compareArray(newVal, state.values[idx], compare) : !compare(newVal, state.values[idx])) { 1713 state.values[idx] = newVal; 1714 return 1 /* SlotStatus.Changed */; 1715 } 1716 } 1717 return 0; 1718 }, 1719 reconfigure: (state, oldState) => { 1720 let newVal = getter(state); 1721 let oldAddr = oldState.config.address[id]; 1722 if (oldAddr != null) { 1723 let oldVal = getAddr(oldState, oldAddr); 1724 if (this.dependencies.every(dep => { 1725 return dep instanceof Facet ? oldState.facet(dep) === state.facet(dep) : 1726 dep instanceof StateField ? oldState.field(dep, false) == state.field(dep, false) : true; 1727 }) || (multi ? compareArray(newVal, oldVal, compare) : compare(newVal, oldVal))) { 1728 state.values[idx] = oldVal; 1729 return 0; 1730 } 1731 } 1732 state.values[idx] = newVal; 1733 return 1 /* SlotStatus.Changed */; 1734 } 1735 }; 1736 } 1737} 1738function compareArray(a, b, compare) { 1739 if (a.length != b.length) 1740 return false; 1741 for (let i = 0; i < a.length; i++) 1742 if (!compare(a[i], b[i])) 1743 return false; 1744 return true; 1745} 1746function ensureAll(state, addrs) { 1747 let changed = false; 1748 for (let addr of addrs) 1749 if (ensureAddr(state, addr) & 1 /* SlotStatus.Changed */) 1750 changed = true; 1751 return changed; 1752} 1753function dynamicFacetSlot(addresses, facet, providers) { 1754 let providerAddrs = providers.map(p => addresses[p.id]); 1755 let providerTypes = providers.map(p => p.type); 1756 let dynamic = providerAddrs.filter(p => !(p & 1)); 1757 let idx = addresses[facet.id] >> 1; 1758 function get(state) { 1759 let values = []; 1760 for (let i = 0; i < providerAddrs.length; i++) { 1761 let value = getAddr(state, providerAddrs[i]); 1762 if (providerTypes[i] == 2 /* Provider.Multi */) 1763 for (let val of value) 1764 values.push(val); 1765 else 1766 values.push(value); 1767 } 1768 return facet.combine(values); 1769 } 1770 return { 1771 create(state) { 1772 for (let addr of providerAddrs) 1773 ensureAddr(state, addr); 1774 state.values[idx] = get(state); 1775 return 1 /* SlotStatus.Changed */; 1776 }, 1777 update(state, tr) { 1778 if (!ensureAll(state, dynamic)) 1779 return 0; 1780 let value = get(state); 1781 if (facet.compare(value, state.values[idx])) 1782 return 0; 1783 state.values[idx] = value; 1784 return 1 /* SlotStatus.Changed */; 1785 }, 1786 reconfigure(state, oldState) { 1787 let depChanged = ensureAll(state, providerAddrs); 1788 let oldProviders = oldState.config.facets[facet.id], oldValue = oldState.facet(facet); 1789 if (oldProviders && !depChanged && sameArray$1(providers, oldProviders)) { 1790 state.values[idx] = oldValue; 1791 return 0; 1792 } 1793 let value = get(state); 1794 if (facet.compare(value, oldValue)) { 1795 state.values[idx] = oldValue; 1796 return 0; 1797 } 1798 state.values[idx] = value; 1799 return 1 /* SlotStatus.Changed */; 1800 } 1801 }; 1802} 1803const initField = /*@__PURE__*/Facet.define({ static: true }); 1804/** 1805Fields can store additional information in an editor state, and 1806keep it in sync with the rest of the state. 1807*/ 1808class StateField { 1809 constructor( 1810 /** 1811 @internal 1812 */ 1813 id, createF, updateF, compareF, 1814 /** 1815 @internal 1816 */ 1817 spec) { 1818 this.id = id; 1819 this.createF = createF; 1820 this.updateF = updateF; 1821 this.compareF = compareF; 1822 this.spec = spec; 1823 /** 1824 @internal 1825 */ 1826 this.provides = undefined; 1827 } 1828 /** 1829 Define a state field. 1830 */ 1831 static define(config) { 1832 let field = new StateField(nextID++, config.create, config.update, config.compare || ((a, b) => a === b), config); 1833 if (config.provide) 1834 field.provides = config.provide(field); 1835 return field; 1836 } 1837 create(state) { 1838 let init = state.facet(initField).find(i => i.field == this); 1839 return ((init === null || init === void 0 ? void 0 : init.create) || this.createF)(state); 1840 } 1841 /** 1842 @internal 1843 */ 1844 slot(addresses) { 1845 let idx = addresses[this.id] >> 1; 1846 return { 1847 create: (state) => { 1848 state.values[idx] = this.create(state); 1849 return 1 /* SlotStatus.Changed */; 1850 }, 1851 update: (state, tr) => { 1852 let oldVal = state.values[idx]; 1853 let value = this.updateF(oldVal, tr); 1854 if (this.compareF(oldVal, value)) 1855 return 0; 1856 state.values[idx] = value; 1857 return 1 /* SlotStatus.Changed */; 1858 }, 1859 reconfigure: (state, oldState) => { 1860 if (oldState.config.address[this.id] != null) { 1861 state.values[idx] = oldState.field(this); 1862 return 0; 1863 } 1864 state.values[idx] = this.create(state); 1865 return 1 /* SlotStatus.Changed */; 1866 } 1867 }; 1868 } 1869 /** 1870 Returns an extension that enables this field and overrides the 1871 way it is initialized. Can be useful when you need to provide a 1872 non-default starting value for the field. 1873 */ 1874 init(create) { 1875 return [this, initField.of({ field: this, create })]; 1876 } 1877 /** 1878 State field instances can be used as 1879 [`Extension`](https://codemirror.net/6/docs/ref/#state.Extension) values to enable the field in a 1880 given state. 1881 */ 1882 get extension() { return this; } 1883} 1884const Prec_ = { lowest: 4, low: 3, default: 2, high: 1, highest: 0 }; 1885function prec(value) { 1886 return (ext) => new PrecExtension(ext, value); 1887} 1888/** 1889By default extensions are registered in the order they are found 1890in the flattened form of nested array that was provided. 1891Individual extension values can be assigned a precedence to 1892override this. Extensions that do not have a precedence set get 1893the precedence of the nearest parent with a precedence, or 1894[`default`](https://codemirror.net/6/docs/ref/#state.Prec.default) if there is no such parent. The 1895final ordering of extensions is determined by first sorting by 1896precedence and then by order within each precedence. 1897*/ 1898const Prec = { 1899 /** 1900 The highest precedence level, for extensions that should end up 1901 near the start of the precedence ordering. 1902 */ 1903 highest: /*@__PURE__*/prec(Prec_.highest), 1904 /** 1905 A higher-than-default precedence, for extensions that should 1906 come before those with default precedence. 1907 */ 1908 high: /*@__PURE__*/prec(Prec_.high), 1909 /** 1910 The default precedence, which is also used for extensions 1911 without an explicit precedence. 1912 */ 1913 default: /*@__PURE__*/prec(Prec_.default), 1914 /** 1915 A lower-than-default precedence. 1916 */ 1917 low: /*@__PURE__*/prec(Prec_.low), 1918 /** 1919 The lowest precedence level. Meant for things that should end up 1920 near the end of the extension order. 1921 */ 1922 lowest: /*@__PURE__*/prec(Prec_.lowest) 1923}; 1924class PrecExtension { 1925 constructor(inner, prec) { 1926 this.inner = inner; 1927 this.prec = prec; 1928 } 1929} 1930/** 1931Extension compartments can be used to make a configuration 1932dynamic. By [wrapping](https://codemirror.net/6/docs/ref/#state.Compartment.of) part of your 1933configuration in a compartment, you can later 1934[replace](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure) that part through a 1935transaction. 1936*/ 1937class Compartment { 1938 /** 1939 Create an instance of this compartment to add to your [state 1940 configuration](https://codemirror.net/6/docs/ref/#state.EditorStateConfig.extensions). 1941 */ 1942 of(ext) { return new CompartmentInstance(this, ext); } 1943 /** 1944 Create an [effect](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) that 1945 reconfigures this compartment. 1946 */ 1947 reconfigure(content) { 1948 return Compartment.reconfigure.of({ compartment: this, extension: content }); 1949 } 1950 /** 1951 Get the current content of the compartment in the state, or 1952 `undefined` if it isn't present. 1953 */ 1954 get(state) { 1955 return state.config.compartments.get(this); 1956 } 1957} 1958class CompartmentInstance { 1959 constructor(compartment, inner) { 1960 this.compartment = compartment; 1961 this.inner = inner; 1962 } 1963} 1964class Configuration { 1965 constructor(base, compartments, dynamicSlots, address, staticValues, facets) { 1966 this.base = base; 1967 this.compartments = compartments; 1968 this.dynamicSlots = dynamicSlots; 1969 this.address = address; 1970 this.staticValues = staticValues; 1971 this.facets = facets; 1972 this.statusTemplate = []; 1973 while (this.statusTemplate.length < dynamicSlots.length) 1974 this.statusTemplate.push(0 /* SlotStatus.Unresolved */); 1975 } 1976 staticFacet(facet) { 1977 let addr = this.address[facet.id]; 1978 return addr == null ? facet.default : this.staticValues[addr >> 1]; 1979 } 1980 static resolve(base, compartments, oldState) { 1981 let fields = []; 1982 let facets = Object.create(null); 1983 let newCompartments = new Map(); 1984 for (let ext of flatten(base, compartments, newCompartments)) { 1985 if (ext instanceof StateField) 1986 fields.push(ext); 1987 else 1988 (facets[ext.facet.id] || (facets[ext.facet.id] = [])).push(ext); 1989 } 1990 let address = Object.create(null); 1991 let staticValues = []; 1992 let dynamicSlots = []; 1993 for (let field of fields) { 1994 address[field.id] = dynamicSlots.length << 1; 1995 dynamicSlots.push(a => field.slot(a)); 1996 } 1997 let oldFacets = oldState === null || oldState === void 0 ? void 0 : oldState.config.facets; 1998 for (let id in facets) { 1999 let providers = facets[id], facet = providers[0].facet; 2000 let oldProviders = oldFacets && oldFacets[id] || []; 2001 if (providers.every(p => p.type == 0 /* Provider.Static */)) { 2002 address[facet.id] = (staticValues.length << 1) | 1; 2003 if (sameArray$1(oldProviders, providers)) { 2004 staticValues.push(oldState.facet(facet)); 2005 } 2006 else { 2007 let value = facet.combine(providers.map(p => p.value)); 2008 staticValues.push(oldState && facet.compare(value, oldState.facet(facet)) ? oldState.facet(facet) : value); 2009 } 2010 } 2011 else { 2012 for (let p of providers) { 2013 if (p.type == 0 /* Provider.Static */) { 2014 address[p.id] = (staticValues.length << 1) | 1; 2015 staticValues.push(p.value); 2016 } 2017 else { 2018 address[p.id] = dynamicSlots.length << 1; 2019 dynamicSlots.push(a => p.dynamicSlot(a)); 2020 } 2021 } 2022 address[facet.id] = dynamicSlots.length << 1; 2023 dynamicSlots.push(a => dynamicFacetSlot(a, facet, providers)); 2024 } 2025 } 2026 let dynamic = dynamicSlots.map(f => f(address)); 2027 return new Configuration(base, newCompartments, dynamic, address, staticValues, facets); 2028 } 2029} 2030function flatten(extension, compartments, newCompartments) { 2031 let result = [[], [], [], [], []]; 2032 let seen = new Map(); 2033 function inner(ext, prec) { 2034 let known = seen.get(ext); 2035 if (known != null) { 2036 if (known <= prec) 2037 return; 2038 let found = result[known].indexOf(ext); 2039 if (found > -1) 2040 result[known].splice(found, 1); 2041 if (ext instanceof CompartmentInstance) 2042 newCompartments.delete(ext.compartment); 2043 } 2044 seen.set(ext, prec); 2045 if (Array.isArray(ext)) { 2046 for (let e of ext) 2047 inner(e, prec); 2048 } 2049 else if (ext instanceof CompartmentInstance) { 2050 if (newCompartments.has(ext.compartment)) 2051 throw new RangeError(`Duplicate use of compartment in extensions`); 2052 let content = compartments.get(ext.compartment) || ext.inner; 2053 newCompartments.set(ext.compartment, content); 2054 inner(content, prec); 2055 } 2056 else if (ext instanceof PrecExtension) { 2057 inner(ext.inner, ext.prec); 2058 } 2059 else if (ext instanceof StateField) { 2060 result[prec].push(ext); 2061 if (ext.provides) 2062 inner(ext.provides, prec); 2063 } 2064 else if (ext instanceof FacetProvider) { 2065 result[prec].push(ext); 2066 if (ext.facet.extensions) 2067 inner(ext.facet.extensions, Prec_.default); 2068 } 2069 else { 2070 let content = ext.extension; 2071 if (!content) 2072 throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`); 2073 inner(content, prec); 2074 } 2075 } 2076 inner(extension, Prec_.default); 2077 return result.reduce((a, b) => a.concat(b)); 2078} 2079function ensureAddr(state, addr) { 2080 if (addr & 1) 2081 return 2 /* SlotStatus.Computed */; 2082 let idx = addr >> 1; 2083 let status = state.status[idx]; 2084 if (status == 4 /* SlotStatus.Computing */) 2085 throw new Error("Cyclic dependency between fields and/or facets"); 2086 if (status & 2 /* SlotStatus.Computed */) 2087 return status; 2088 state.status[idx] = 4 /* SlotStatus.Computing */; 2089 let changed = state.computeSlot(state, state.config.dynamicSlots[idx]); 2090 return state.status[idx] = 2 /* SlotStatus.Computed */ | changed; 2091} 2092function getAddr(state, addr) { 2093 return addr & 1 ? state.config.staticValues[addr >> 1] : state.values[addr >> 1]; 2094} 2095 2096const languageData = /*@__PURE__*/Facet.define(); 2097const allowMultipleSelections = /*@__PURE__*/Facet.define({ 2098 combine: values => values.some(v => v), 2099 static: true 2100}); 2101const lineSeparator = /*@__PURE__*/Facet.define({ 2102 combine: values => values.length ? values[0] : undefined, 2103 static: true 2104}); 2105const changeFilter = /*@__PURE__*/Facet.define(); 2106const transactionFilter = /*@__PURE__*/Facet.define(); 2107const transactionExtender = /*@__PURE__*/Facet.define(); 2108const readOnly = /*@__PURE__*/Facet.define({ 2109 combine: values => values.length ? values[0] : false 2110}); 2111 2112/** 2113Annotations are tagged values that are used to add metadata to 2114transactions in an extensible way. They should be used to model 2115things that effect the entire transaction (such as its [time 2116stamp](https://codemirror.net/6/docs/ref/#state.Transaction^time) or information about its 2117[origin](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent)). For effects that happen 2118_alongside_ the other changes made by the transaction, [state
2119effects](https://codemirror.net/6/docs/ref/#state.StateEffect) are more appropriate. 2120*/ 2121class Annotation { 2122 /** 2123 @internal 2124 */ 2125 constructor( 2126 /** 2127 The annotation type. 2128 */ 2129 type, 2130 /** 2131 The value of this annotation. 2132 */ 2133 value) { 2134 this.type = type; 2135 this.value = value; 2136 } 2137 /** 2138 Define a new type of annotation. 2139 */ 2140 static define() { return new AnnotationType(); } 2141} 2142/** 2143Marker that identifies a type of [annotation](https://codemirror.net/6/docs/ref/#state.Annotation). 2144*/ 2145class AnnotationType { 2146 /** 2147 Create an instance of this annotation. 2148 */ 2149 of(value) { return new Annotation(this, value); } 2150} 2151/** 2152Representation of a type of state effect. Defined with 2153[`StateEffect.define`](https://codemirror.net/6/docs/ref/#state.StateEffect^define). 2154*/ 2155class StateEffectType { 2156 /** 2157 @internal 2158 */ 2159 constructor( 2160 // The `any` types in these function types are there to work 2161 // around TypeScript issue #37631, where the type guard on 2162 // `StateEffect.is` mysteriously stops working when these properly 2163 // have type `Value`. 2164 /** 2165 @internal 2166 */ 2167 map) { 2168 this.map = map; 2169 } 2170 /** 2171 Create a [state effect](https://codemirror.net/6/docs/ref/#state.StateEffect) instance of this 2172 type. 2173 */ 2174 of(value) { return new StateEffect(this, value); } 2175} 2176/** 2177State effects can be used to represent additional effects 2178associated with a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction.effects). They 2179are often useful to model changes to custom [state 2180fields](https://codemirror.net/6/docs/ref/#state.StateField), when those changes aren't implicit in 2181document or selection changes. 2182*/ 2183class StateEffect { 2184 /** 2185 @internal 2186 */ 2187 constructor( 2188 /** 2189 @internal 2190 */ 2191 type, 2192 /** 2193 The value of this effect. 2194 */ 2195 value) { 2196 this.type = type; 2197 this.value = value; 2198 } 2199 /** 2200 Map this effect through a position mapping. Will return 2201 `undefined` when that ends up deleting the effect. 2202 */ 2203 map(mapping) { 2204 let mapped = this.type.map(this.value, mapping); 2205 return mapped === undefined ? undefined : mapped == this.value ? this : new StateEffect(this.type, mapped); 2206 } 2207 /** 2208 Tells you whether this effect object is of a given 2209 [type](https://codemirror.net/6/docs/ref/#state.StateEffectType). 2210 */ 2211 is(type) { return this.type == type; } 2212 /** 2213 Define a new effect type. The type parameter indicates the type 2214 of values that his effect holds
vendor: 8,946 bytes, lines 2214-2457
2214. 2215 */ 2216 static define(spec = {}) { 2217 return new StateEffectType(spec.map || (v => v)); 2218 } 2219 /** 2220 Map an array of effects through a change set. 2221 */ 2222 static mapEffects(effects, mapping) { 2223 if (!effects.length) 2224 return effects; 2225 let result = []; 2226 for (let effect of effects) { 2227 let mapped = effect.map(mapping); 2228 if (mapped) 2229 result.push(mapped); 2230 } 2231 return result; 2232 } 2233} 2234/** 2235This effect can be used to reconfigure the root extensions of 2236the editor. Doing this will discard any extensions 2237[appended](https://codemirror.net/6/docs/ref/#state.StateEffect^appendConfig), but does not reset 2238the content of [reconfigured](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure) 2239compartments. 2240*/ 2241StateEffect.reconfigure = /*@__PURE__*/StateEffect.define(); 2242/** 2243Append extensions to the top-level configuration of the editor. 2244*/ 2245StateEffect.appendConfig = /*@__PURE__*/StateEffect.define(); 2246/** 2247Changes to the editor state are grouped into transactions. 2248Typically, a user action creates a single transaction, which may 2249contain any number of document changes, may change the selection, 2250or have other effects. Create a transaction by calling 2251[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update), or immediately 2252dispatch one by calling 2253[`EditorView.dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch). 2254*/ 2255class Transaction { 2256 constructor( 2257 /** 2258 The state from which the transaction starts. 2259 */ 2260 startState, 2261 /** 2262 The document changes made by this transaction. 2263 */ 2264 changes, 2265 /** 2266 The selection set by this transaction, or undefined if it 2267 doesn't explicitly set a selection. 2268 */ 2269 selection, 2270 /** 2271 The effects added to the transaction. 2272 */ 2273 effects, 2274 /** 2275 @internal 2276 */ 2277 annotations, 2278 /** 2279 Whether the selection should be scrolled into view after this 2280 transaction is dispatched. 2281 */ 2282 scrollIntoView) { 2283 this.startState = startState; 2284 this.changes = changes; 2285 this.selection = selection; 2286 this.effects = effects; 2287 this.annotations = annotations; 2288 this.scrollIntoView = scrollIntoView; 2289 /** 2290 @internal 2291 */ 2292 this._doc = null; 2293 /** 2294 @internal 2295 */ 2296 this._state = null; 2297 if (selection) 2298 checkSelection(selection, changes.newLength); 2299 if (!annotations.some((a) => a.type == Transaction.time)) 2300 this.annotations = annotations.concat(Transaction.time.of(Date.now())); 2301 } 2302 /** 2303 @internal 2304 */ 2305 static create(startState, changes, selection, effects, annotations, scrollIntoView) { 2306 return new Transaction(startState, changes, selection, effects, annotations, scrollIntoView); 2307 } 2308 /** 2309 The new document produced by the transaction. Contrary to 2310 [`.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state)`.doc`, accessing this won't 2311 force the entire new state to be computed right away, so it is 2312 recommended that [transaction 2313 filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) use this getter 2314 when they need to look at the new document. 2315 */ 2316 get newDoc() { 2317 return this._doc || (this._doc = this.changes.apply(this.startState.doc)); 2318 } 2319 /** 2320 The new selection produced by the transaction. If 2321 [`this.selection`](https://codemirror.net/6/docs/ref/#state.Transaction.selection) is undefined, 2322 this will [map](https://codemirror.net/6/docs/ref/#state.EditorSelection.map) the start state's 2323 current selection through the changes made by the transaction. 2324 */ 2325 get newSelection() { 2326 return this.selection || this.startState.selection.map(this.changes); 2327 } 2328 /** 2329 The new state created by the transaction. Computed on demand 2330 (but retained for subsequent access), so it is recommended not to 2331 access it in [transaction 2332 filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) when possible. 2333 */ 2334 get state() { 2335 if (!this._state) 2336 this.startState.applyTransaction(this); 2337 return this._state; 2338 } 2339 /** 2340 Get the value of the given annotation type, if any. 2341 */ 2342 annotation(type) { 2343 for (let ann of this.annotations) 2344 if (ann.type == type) 2345 return ann.value; 2346 return undefined; 2347 } 2348 /** 2349 Indicates whether the transaction changed the document. 2350 */ 2351 get docChanged() { return !this.changes.empty; } 2352 /** 2353 Indicates whether this transaction reconfigures the state 2354 (through a [configuration compartment](https://codemirror.net/6/docs/ref/#state.Compartment) or 2355 with a top-level configuration 2356 [effect](https://codemirror.net/6/docs/ref/#state.StateEffect^reconfigure). 2357 */ 2358 get reconfigured() { return this.startState.config != this.state.config; } 2359 /** 2360 Returns true if the transaction has a [user 2361 event](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent) annotation that is equal to 2362 or more specific than `event`. For example, if the transaction 2363 has `"select.pointer"` as user event, `"select"` and 2364 `"select.pointer"` will match it. 2365 */ 2366 isUserEvent(event) { 2367 let e = this.annotation(Transaction.userEvent); 2368 return !!(e && (e == event || e.length > event.length && e.slice(0, event.length) == event && e[event.length] == ".")); 2369 } 2370} 2371/** 2372Annotation used to store transaction timestamps. Automatically 2373added to every transaction, holding `Date.now()`. 2374*/ 2375Transaction.time = /*@__PURE__*/Annotation.define(); 2376/** 2377Annotation used to associate a transaction with a user interface 2378event. Holds a string identifying the event, using a 2379dot-separated format to support attaching more specific 2380information. The events used by the core libraries are: 2381 2382 - `"input"` when content is entered 2383 - `"input.type"` for typed input 2384 - `"input.type.compose"` for composition 2385 - `"input.paste"` for pasted input 2386 - `"input.drop"` when adding content with drag-and-drop 2387 - `"input.complete"` when autocompleting 2388 - `"delete"` when the user deletes content 2389 - `"delete.selection"` when deleting the selection 2390 - `"delete.forward"` when deleting forward from the selection 2391 - `"delete.backward"` when deleting backward from the selection 2392 - `"delete.cut"` when cutting to the clipboard 2393 - `"move"` when content is moved 2394 - `"move.drop"` when content is moved within the editor through drag-and-drop 2395 - `"select"` when explicitly changing the selection 2396 - `"select.pointer"` when selecting with a mouse or other pointing device 2397 - `"undo"` and `"redo"` for history actions 2398 2399Use [`isUserEvent`](https://codemirror.net/6/docs/ref/#state.Transaction.isUserEvent) to check 2400whether the annotation matches a given event. 2401*/ 2402Transaction.userEvent = /*@__PURE__*/Annotation.define(); 2403/** 2404Annotation indicating whether a transaction should be added to 2405the undo history or not. 2406*/ 2407Transaction.addToHistory = /*@__PURE__*/Annotation.define(); 2408/** 2409Annotation indicating (when present and true) that a transaction 2410represents a change made by some other actor, not the user. This 2411is used, for example, to tag other people's changes in 2412collaborative editing. 2413*/ 2414Transaction.remote = /*@__PURE__*/Annotation.define(); 2415function joinRanges(a, b) { 2416 let result = []; 2417 for (let iA = 0, iB = 0;;) { 2418 let from, to; 2419 if (iA < a.length && (iB == b.length || b[iB] >= a[iA])) { 2420 from = a[iA++]; 2421 to = a[iA++]; 2422 } 2423 else if (iB < b.length) { 2424 from = b[iB++]; 2425 to = b[iB++]; 2426 } 2427 else 2428 return result; 2429 if (!result.length || result[result.length - 1] < from) 2430 result.push(from, to); 2431 else if (result[result.length - 1] < to) 2432 result[result.length - 1] = to; 2433 } 2434} 2435function mergeTransaction(a, b, sequential) { 2436 var _a; 2437 let mapForA, mapForB, changes; 2438 if (sequential) { 2439 mapForA = b.changes; 2440 mapForB = ChangeSet.empty(b.changes.length); 2441 changes = a.changes.compose(b.changes); 2442 } 2443 else { 2444 mapForA = b.changes.map(a.changes); 2445 mapForB = a.changes.mapDesc(b.changes, true); 2446 changes = a.changes.compose(mapForA); 2447 } 2448 return { 2449 changes, 2450 selection: b.selection ? b.selection.map(mapForB) : (_a = a.selection) === null || _a === void 0 ? void 0 : _a.map(mapForA), 2451 effects: StateEffect.mapEffects(a.effects, mapForA).concat(StateEffect.mapEffects(b.effects, mapForB)), 2452 annotations: a.annotations.length ? a.annotations.concat(b.annotations) : b.annotations, 2453 scrollIntoView: a.scrollIntoView || b.scrollIntoView 2454 }; 2455} 2456function resolveTransactionInner(state, spec, docSize) { 2457 let sel = spec.selection, annotations = asArray
vendor: 1,516 bytes, lines 2457-2490
2457$1(spec.annotations); 2458 if (spec.userEvent) 2459 annotations = annotations.concat(Transaction.userEvent.of(spec.userEvent)); 2460 return { 2461 changes: spec.changes instanceof ChangeSet ? spec.changes 2462 : ChangeSet.of(spec.changes || [], docSize, state.facet(lineSeparator)), 2463 selection: sel && (sel instanceof EditorSelection ? sel : EditorSelection.single(sel.anchor, sel.head)), 2464 effects: asArray$1(spec.effects), 2465 annotations, 2466 scrollIntoView: !!spec.scrollIntoView 2467 }; 2468} 2469function resolveTransaction(state, specs, filter) { 2470 let s = resolveTransactionInner(state, specs.length ? specs[0] : {}, state.doc.length); 2471 if (specs.length && specs[0].filter === false) 2472 filter = false; 2473 for (let i = 1; i < specs.length; i++) { 2474 if (specs[i].filter === false) 2475 filter = false; 2476 let seq = !!specs[i].sequential; 2477 s = mergeTransaction(s, resolveTransactionInner(state, specs[i], seq ? s.changes.newLength : state.doc.length), seq); 2478 } 2479 let tr = Transaction.create(state, s.changes, s.selection, s.effects, s.annotations, s.scrollIntoView); 2480 return extendTransaction(filter ? filterTransaction(tr) : tr); 2481} 2482// Finish a transaction by applying filters if necessary. 2483function filterTransaction(tr) { 2484 let state = tr.startState; 2485 // Change filters 2486 let result = true; 2487 for (let filter of state.facet(changeFilter)) { 2488 let value = filter(tr); 2489 if (value === false) { 2490 result = false;
vendor: 4,312 bytes, lines 2491-2617
2491 break; 2492 } 2493 if (Array.isArray(value)) 2494 result = result === true ? value : joinRanges(result, value); 2495 } 2496 if (result !== true) { 2497 let changes, back; 2498 if (result === false) { 2499 back = tr.changes.invertedDesc; 2500 changes = ChangeSet.empty(state.doc.length); 2501 } 2502 else { 2503 let filtered = tr.changes.filter(result); 2504 changes = filtered.changes; 2505 back = filtered.filtered.mapDesc(filtered.changes).invertedDesc; 2506 } 2507 tr = Transaction.create(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView); 2508 } 2509 // Transaction filters 2510 let filters = state.facet(transactionFilter); 2511 for (let i = filters.length - 1; i >= 0; i--) { 2512 let filtered = filters[i](tr); 2513 if (filtered instanceof Transaction) 2514 tr = filtered; 2515 else if (Array.isArray(filtered) && filtered.length == 1 && filtered[0] instanceof Transaction) 2516 tr = filtered[0]; 2517 else 2518 tr = resolveTransaction(state, asArray$1(filtered), false); 2519 } 2520 return tr; 2521} 2522function extendTransaction(tr) { 2523 let state = tr.startState, extenders = state.facet(transactionExtender), spec = tr; 2524 for (let i = extenders.length - 1; i >= 0; i--) { 2525 let extension = extenders[i](tr); 2526 if (extension && Object.keys(extension).length) 2527 spec = mergeTransaction(spec, resolveTransactionInner(state, extension, tr.changes.newLength), true); 2528 } 2529 return spec == tr ? tr : Transaction.create(state, tr.changes, tr.selection, spec.effects, spec.annotations, spec.scrollIntoView); 2530} 2531const none$2 = []; 2532function asArray$1(value) { 2533 return value == null ? none$2 : Array.isArray(value) ? value : [value]; 2534} 2535 2536/** 2537The categories produced by a [character 2538categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer). These are used 2539do things like selecting by word. 2540*/ 2541var CharCategory = /*@__PURE__*/(function (CharCategory) { 2542 /** 2543 Word characters. 2544 */ 2545 CharCategory[CharCategory["Word"] = 0] = "Word"; 2546 /** 2547 Whitespace. 2548 */ 2549 CharCategory[CharCategory["Space"] = 1] = "Space"; 2550 /** 2551 Anything else. 2552 */ 2553 CharCategory[CharCategory["Other"] = 2] = "Other"; 2554return CharCategory})(CharCategory || (CharCategory = {})); 2555const nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; 2556let wordChar; 2557try { 2558 wordChar = /*@__PURE__*/new RegExp("[\\p{Alphabetic}\\p{Number}_]", "u"); 2559} 2560catch (_) { } 2561function hasWordChar(str) { 2562 if (wordChar) 2563 return wordChar.test(str); 2564 for (let i = 0; i < str.length; i++) { 2565 let ch = str[i]; 2566 if (/\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))) 2567 return true; 2568 } 2569 return false; 2570} 2571function makeCategorizer(wordChars) { 2572 return (char) => { 2573 if (!/\S/.test(char)) 2574 return CharCategory.Space; 2575 if (hasWordChar(char)) 2576 return CharCategory.Word; 2577 for (let i = 0; i < wordChars.length; i++) 2578 if (char.indexOf(wordChars[i]) > -1) 2579 return CharCategory.Word; 2580 return CharCategory.Other; 2581 }; 2582} 2583 2584/** 2585The editor state class is a persistent (immutable) data structure. 2586To update a state, you [create](https://codemirror.net/6/docs/ref/#state.EditorState.update) a 2587[transaction](https://codemirror.net/6/docs/ref/#state.Transaction), which produces a _new_ state 2588instance, without modifying the original object. 2589 2590As such, _never_ mutate properties of a state directly. That'll 2591just break things. 2592*/ 2593class EditorState { 2594 constructor( 2595 /** 2596 @internal 2597 */ 2598 config, 2599 /** 2600 The current document. 2601 */ 2602 doc, 2603 /** 2604 The current selection. 2605 */ 2606 selection, 2607 /** 2608 @internal 2609 */ 2610 values, computeSlot, tr) { 2611 this.config = config; 2612 this.doc = doc; 2613 this.selection = selection; 2614 this.values = values; 2615 this.status = config.statusTemplate.slice(); 2616 this.computeSlot = computeSlot; 2617 // Fill in the computed state immediately, so that further queries
vendor: 4,847 bytes, lines 2618-2720
2618 // for it made during the update return this state 2619 if (tr) 2620 tr._state = this; 2621 for (let i = 0; i < this.config.dynamicSlots.length; i++) 2622 ensureAddr(this, i << 1); 2623 this.computeSlot = null; 2624 } 2625 field(field, require = true) { 2626 let addr = this.config.address[field.id]; 2627 if (addr == null) { 2628 if (require) 2629 throw new RangeError("Field is not present in this state"); 2630 return undefined; 2631 } 2632 ensureAddr(this, addr); 2633 return getAddr(this, addr); 2634 } 2635 /** 2636 Create a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction) that updates this 2637 state. Any number of [transaction specs](https://codemirror.net/6/docs/ref/#state.TransactionSpec) 2638 can be passed. Unless 2639 [`sequential`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.sequential) is set, the 2640 [changes](https://codemirror.net/6/docs/ref/#state.TransactionSpec.changes) (if any) of each spec 2641 are assumed to start in the _current_ document (not the document 2642 produced by previous specs), and its 2643 [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) and 2644 [effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) are assumed to refer 2645 to the document created by its _own_ changes. The resulting 2646 transaction contains the combined effect of all the different 2647 specs. For [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection), later 2648 specs take precedence over earlier ones. 2649 */ 2650 update(...specs) { 2651 return resolveTransaction(this, specs, true); 2652 } 2653 /** 2654 @internal 2655 */ 2656 applyTransaction(tr) { 2657 let conf = this.config, { base, compartments } = conf; 2658 for (let effect of tr.effects) { 2659 if (effect.is(Compartment.reconfigure)) { 2660 if (conf) { 2661 compartments = new Map; 2662 conf.compartments.forEach((val, key) => compartments.set(key, val)); 2663 conf = null; 2664 } 2665 compartments.set(effect.value.compartment, effect.value.extension); 2666 } 2667 else if (effect.is(StateEffect.reconfigure)) { 2668 conf = null; 2669 base = effect.value; 2670 } 2671 else if (effect.is(StateEffect.appendConfig)) { 2672 conf = null; 2673 base = asArray$1(base).concat(effect.value); 2674 } 2675 } 2676 let startValues; 2677 if (!conf) { 2678 conf = Configuration.resolve(base, compartments, this); 2679 let intermediateState = new EditorState(conf, this.doc, this.selection, conf.dynamicSlots.map(() => null), (state, slot) => slot.reconfigure(state, this), null); 2680 startValues = intermediateState.values; 2681 } 2682 else { 2683 startValues = tr.startState.values.slice(); 2684 } 2685 new EditorState(conf, tr.newDoc, tr.newSelection, startValues, (state, slot) => slot.update(state, tr), tr); 2686 } 2687 /** 2688 Create a [transaction spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec) that 2689 replaces every selection range with the given content. 2690 */ 2691 replaceSelection(text) { 2692 if (typeof text == "string") 2693 text = this.toText(text); 2694 return this.changeByRange(range => ({ changes: { from: range.from, to: range.to, insert: text }, 2695 range: EditorSelection.cursor(range.from + text.length) })); 2696 } 2697 /** 2698 Create a set of changes and a new selection by running the given 2699 function for each range in the active selection. The function 2700 can return an optional set of changes (in the coordinate space 2701 of the start document), plus an updated range (in the coordinate 2702 space of the document produced by the call's own changes). This 2703 method will merge all the changes and ranges into a single 2704 changeset and selection, and return it as a [transaction 2705 spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec), which can be passed to 2706 [`update`](https://codemirror.net/6/docs/ref/#state.EditorState.update). 2707 */ 2708 changeByRange(f) { 2709 let sel = this.selection; 2710 let result1 = f(sel.ranges[0]); 2711 let changes = this.changes(result1.changes), ranges = [result1.range]; 2712 let effects = asArray$1(result1.effects); 2713 for (let i = 1; i < sel.ranges.length; i++) { 2714 let result = f(sel.ranges[i]); 2715 let newChanges = this.changes(result.changes), newMapped = newChanges.map(changes); 2716 for (let j = 0; j < i; j++) 2717 ranges[j] = ranges[j].map(newMapped); 2718 let mapBy = changes.mapDesc(newChanges, true); 2719 ranges.push(result.range.map(mapBy)); 2720 changes = changes.compose(newMapped);
vendor: 3,791 bytes, lines 2721-2814
2721 effects = StateEffect.mapEffects(effects, newMapped).concat(StateEffect.mapEffects(asArray$1(result.effects), mapBy)); 2722 } 2723 return { 2724 changes, 2725 selection: EditorSelection.create(ranges, sel.mainIndex), 2726 effects 2727 }; 2728 } 2729 /** 2730 Create a [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet) from the given change 2731 description, taking the state's document length and line 2732 separator into account. 2733 */ 2734 changes(spec = []) { 2735 if (spec instanceof ChangeSet) 2736 return spec; 2737 return ChangeSet.of(spec, this.doc.length, this.facet(EditorState.lineSeparator)); 2738 } 2739 /** 2740 Using the state's [line 2741 separator](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator), create a 2742 [`Text`](https://codemirror.net/6/docs/ref/#state.Text) instance from the given string. 2743 */ 2744 toText(string) { 2745 return Text.of(string.split(this.facet(EditorState.lineSeparator) || DefaultSplit)); 2746 } 2747 /** 2748 Return the given range of the document as a string. 2749 */ 2750 sliceDoc(from = 0, to = this.doc.length) { 2751 return this.doc.sliceString(from, to, this.lineBreak); 2752 } 2753 /** 2754 Get the value of a state [facet](https://codemirror.net/6/docs/ref/#state.Facet). 2755 */ 2756 facet(facet) { 2757 let addr = this.config.address[facet.id]; 2758 if (addr == null) 2759 return facet.default; 2760 ensureAddr(this, addr); 2761 return getAddr(this, addr); 2762 } 2763 /** 2764 Convert this state to a JSON-serializable object. When custom 2765 fields should be serialized, you can pass them in as an object 2766 mapping property names (in the resulting object, which should 2767 not use `doc` or `selection`) to fields. 2768 */ 2769 toJSON(fields) { 2770 let result = { 2771 doc: this.sliceDoc(), 2772 selection: this.selection.toJSON() 2773 }; 2774 if (fields) 2775 for (let prop in fields) { 2776 let value = fields[prop]; 2777 if (value instanceof StateField && this.config.address[value.id] != null) 2778 result[prop] = value.spec.toJSON(this.field(fields[prop]), this); 2779 } 2780 return result; 2781 } 2782 /** 2783 Deserialize a state from its JSON representation. When custom 2784 fields should be deserialized, pass the same object you passed 2785 to [`toJSON`](https://codemirror.net/6/docs/ref/#state.EditorState.toJSON) when serializing as 2786 third argument. 2787 */ 2788 static fromJSON(json, config = {}, fields) { 2789 if (!json || typeof json.doc != "string") 2790 throw new RangeError("Invalid JSON representation for EditorState"); 2791 let fieldInit = []; 2792 if (fields) 2793 for (let prop in fields) { 2794 if (Object.prototype.hasOwnProperty.call(json, prop)) { 2795 let field = fields[prop], value = json[prop]; 2796 fieldInit.push(field.init(state => field.spec.fromJSON(value, state))); 2797 } 2798 } 2799 return EditorState.create({ 2800 doc: json.doc, 2801 selection: EditorSelection.fromJSON(json.selection), 2802 extensions: config.extensions ? fieldInit.concat([config.extensions]) : fieldInit 2803 }); 2804 } 2805 /** 2806 Create a new state. You'll usually only need this when 2807 initializing an editorâupdated states are created by applying 2808 transactions. 2809 */ 2810 static create(config = {}) { 2811 let configuration = Configuration.resolve(config.extensions || [], new Map); 2812 let doc = config.doc instanceof Text ? config.doc 2813 : Text.of((config.doc || "").split(configuration.staticFacet(EditorState.lineSeparator) || DefaultSplit)); 2814 let selection = !config.selection ? EditorSelection.single(0)
vendor: 8,474 bytes, lines 2815-3014
2815 : config.selection instanceof EditorSelection ? config.selection 2816 : EditorSelection.single(config.selection.anchor, config.selection.head); 2817 checkSelection(selection, doc.length); 2818 if (!configuration.staticFacet(allowMultipleSelections)) 2819 selection = selection.asSingle(); 2820 return new EditorState(configuration, doc, selection, configuration.dynamicSlots.map(() => null), (state, slot) => slot.create(state), null); 2821 } 2822 /** 2823 The size (in columns) of a tab in the document, determined by 2824 the [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) facet. 2825 */ 2826 get tabSize() { return this.facet(EditorState.tabSize); } 2827 /** 2828 Get the proper [line-break](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator) 2829 string for this state. 2830 */ 2831 get lineBreak() { return this.facet(EditorState.lineSeparator) || "\n"; } 2832 /** 2833 Returns true when the editor is 2834 [configured](https://codemirror.net/6/docs/ref/#state.EditorState^readOnly) to be read-only. 2835 */ 2836 get readOnly() { return this.facet(readOnly); } 2837 /** 2838 Look up a translation for the given phrase (via the 2839 [`phrases`](https://codemirror.net/6/docs/ref/#state.EditorState^phrases) facet), or return the 2840 original string if no translation is found. 2841 2842 If additional arguments are passed, they will be inserted in 2843 place of markers like `$1` (for the first value) and `$2`, etc. 2844 A single `$` is equivalent to `$1`, and `$$` will produce a 2845 literal dollar sign. 2846 */ 2847 phrase(phrase, ...insert) { 2848 for (let map of this.facet(EditorState.phrases)) 2849 if (Object.prototype.hasOwnProperty.call(map, phrase)) { 2850 phrase = map[phrase]; 2851 break; 2852 } 2853 if (insert.length) 2854 phrase = phrase.replace(/\$(\$|\d*)/g, (m, i) => { 2855 if (i == "$") 2856 return "$"; 2857 let n = +(i || 1); 2858 return !n || n > insert.length ? m : insert[n - 1]; 2859 }); 2860 return phrase; 2861 } 2862 /** 2863 Find the values for a given language data field, provided by the 2864 the [`languageData`](https://codemirror.net/6/docs/ref/#state.EditorState^languageData) facet. 2865 */ 2866 languageDataAt(name, pos, side = -1) { 2867 let values = []; 2868 for (let provider of this.facet(languageData)) { 2869 for (let result of provider(this, pos, side)) { 2870 if (Object.prototype.hasOwnProperty.call(result, name)) 2871 values.push(result[name]); 2872 } 2873 } 2874 return values; 2875 } 2876 /** 2877 Return a function that can categorize strings (expected to 2878 represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak)) 2879 into one of: 2880 2881 - Word (contains an alphanumeric character or a character 2882 explicitly listed in the local language's `"wordChars"` 2883 language data, which should be a string) 2884 - Space (contains only whitespace) 2885 - Other (anything else) 2886 */ 2887 charCategorizer(at) { 2888 return makeCategorizer(this.languageDataAt("wordChars", at).join("")); 2889 } 2890 /** 2891 Find the word at the given position, meaning the range 2892 containing all [word](https://codemirror.net/6/docs/ref/#state.CharCategory.Word) characters 2893 around it. If no word characters are adjacent to the position, 2894 this returns null. 2895 */ 2896 wordAt(pos) { 2897 let { text, from, length } = this.doc.lineAt(pos); 2898 let cat = this.charCategorizer(pos); 2899 let start = pos - from, end = pos - from; 2900 while (start > 0) { 2901 let prev = findClusterBreak(text, start, false); 2902 if (cat(text.slice(prev, start)) != CharCategory.Word) 2903 break; 2904 start = prev; 2905 } 2906 while (end < length) { 2907 let next = findClusterBreak(text, end); 2908 if (cat(text.slice(end, next)) != CharCategory.Word) 2909 break; 2910 end = next; 2911 } 2912 return start == end ? null : EditorSelection.range(start + from, end + from); 2913 } 2914} 2915/** 2916A facet that, when enabled, causes the editor to allow multiple 2917ranges to be selected. Be careful though, because by default the 2918editor relies on the native DOM selection, which cannot handle 2919multiple selections. An extension like 2920[`drawSelection`](https://codemirror.net/6/docs/ref/#view.drawSelection) can be used to make 2921secondary selections visible to the user. 2922*/ 2923EditorState.allowMultipleSelections = allowMultipleSelections; 2924/** 2925Configures the tab size to use in this state. The first 2926(highest-precedence) value of the facet is used. If no value is 2927given, this defaults to 4. 2928*/ 2929EditorState.tabSize = /*@__PURE__*/Facet.define({ 2930 combine: values => values.length ? values[0] : 4 2931}); 2932/** 2933The line separator to use. By default, any of `"\n"`, `"\r\n"` 2934and `"\r"` is treated as a separator when splitting lines, and 2935lines are joined with `"\n"`. 2936 2937When you configure a value here, only that precise separator 2938will be used, allowing you to round-trip documents through the 2939editor without normalizing line separators. 2940*/ 2941EditorState.lineSeparator = lineSeparator; 2942/** 2943This facet controls the value of the 2944[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) getter, which is 2945consulted by commands and extensions that implement editing 2946functionality to determine whether they should apply. It 2947defaults to false, but when its highest-precedence value is 2948`true`, such functionality disables itself. 2949 2950Not to be confused with 2951[`EditorView.editable`](https://codemirror.net/6/docs/ref/#view.EditorView^editable), which 2952controls whether the editor's DOM is set to be editable (and 2953thus focusable). 2954*/ 2955EditorState.readOnly = readOnly; 2956/** 2957Registers translation phrases. The 2958[`phrase`](https://codemirror.net/6/docs/ref/#state.EditorState.phrase) method will look through 2959all objects registered with this facet to find translations for 2960its argument. 2961*/ 2962EditorState.phrases = /*@__PURE__*/Facet.define({ 2963 compare(a, b) { 2964 let kA = Object.keys(a), kB = Object.keys(b); 2965 return kA.length == kB.length && kA.every(k => a[k] == b[k]); 2966 } 2967}); 2968/** 2969A facet used to register [language 2970data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) providers. 2971*/ 2972EditorState.languageData = languageData; 2973/** 2974Facet used to register change filters, which are called for each 2975transaction (unless explicitly 2976[disabled](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter)), and can suppress 2977part of the transaction's changes. 2978 2979Such a function can return `true` to indicate that it doesn't 2980want to do anything, `false` to completely stop the changes in 2981the transaction, or a set of ranges in which changes should be 2982suppressed. Such ranges are represented as an array of numbers, 2983with each pair of two numbers indicating the start and end of a 2984range. So for example `[10, 20, 100, 110]` suppresses changes 2985between 10 and 20, and between 100 and 110. 2986*/ 2987EditorState.changeFilter = changeFilter; 2988/** 2989Facet used to register a hook that gets a chance to update or 2990replace transaction specs before they are applied. This will 2991only be applied for transactions that don't have 2992[`filter`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter) set to `false`. You 2993can either return a single transaction spec (possibly the input 2994transaction), or an array of specs (which will be combined in 2995the same way as the arguments to 2996[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update)). 2997 2998When possible, it is recommended to avoid accessing 2999[`Transaction.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state) in a filter, 3000since it will force creation of a state that will then be 3001discarded again, if the transaction is actually filtered. 3002 3003(This functionality should be used with care. Indiscriminately 3004modifying transaction is likely to break something or degrade 3005the user experience.) 3006*/ 3007EditorState.transactionFilter = transactionFilter; 3008/** 3009This is a more limited form of 3010[`transactionFilter`](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter), 3011which can only add 3012[annotations](https://codemirror.net/6/docs/ref/#state.TransactionSpec.annotations) and 3013[effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects). _But_, this type 3014of filter runs even if the transaction has disabled regular
3015[filtering](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter), making it suitable 3016for effects that don't need to touch the changes or selection, 3017but do want to process every transaction. 3018 3019Extenders run _after_ filters, when both are present. 3020*/ 3021EditorState.transactionExtender = transactionExtender; 3022Compartment.reconfigure = /*@__PURE__*/StateEffect.define(); 3023 3024/** 3025Utility function for combining behaviors to fill in a config 3026object from an array of provided configs. `defaults` should hold 3027default values for all optional fields in `Config`. 3028 3029The function will, by default, error 3030when a field gets two values that aren't `===`-equal, but you can 3031provide combine functions per field to do something else. 3032*/ 3033function combineConfig(configs, defaults, // Should hold only the optional properties of Config, but I haven't managed to express that 3034combine = {}) { 3035 let result = {}; 3036 for (let config of configs) 3037 for (let key of Object.keys(config)) { 3038 let value = config[key], current = result[key]; 3039 if (current === undefined) 3040 result[key] = value; 3041 else if (current === value || value === undefined) ; // No conflict 3042 else if (Object.hasOwnProperty.call(combine, key)) 3043 result[key] = combine[key](current, value); 3044 else 3045 throw new Error("Config merge conflict for field " + key); 3046 } 3047 for (let key in defaults) 3048 if (result[key] === undefined) 3049 result[key] = defaults[key]; 3050 return result; 3051} 3052 3053/** 3054Each range is associated with a value, which must inherit from 3055this class. 3056*/ 3057class RangeValue { 3058 /** 3059 Compare this value with another value. Used when comparing 3060 rangesets. The default implementation compares by identity. 3061 Unless you are only creating a fixed number of unique instances 3062 of your value type, it is a good idea to implement this 3063 properly. 3064 */ 3065 eq(other) { return this == other; } 3066 /** 3067 Create a [range](https://codemirror.net/6/docs/ref/#state.Range) with this value. 3068 */ 3069 range(from, to = from) { return Range$1.create(from, to, this); } 3070} 3071RangeValue.prototype.startSide = RangeValue.prototype.endSide = 0; 3072RangeValue.prototype.point = false; 3073RangeValue.prototype.mapMode = MapMode.TrackDel; 3074/** 3075A range associates a value with a range of positions. 3076*/ 3077let Range$1 = class Range { 3078 constructor( 3079 /** 3080 The range's start position. 3081 */ 3082 from, 3083 /** 3084 Its end position. 3085 */ 3086 to, 3087 /** 3088 The value associated with this range. 3089 */ 3090 value) { 3091 this.from = from; 3092 this.to = to; 3093 this.value = value; 3094 } 3095 /** 3096 @internal 3097 */ 3098 static create(from, to, value) { 3099 return new Range(from, to, value); 3100 } 3101}; 3102function cmpRange(a, b) { 3103 return a.from - b.from || a.value.startSide - b.value.startSide; 3104} 3105class Chunk { 3106 constructor(from, to, value, 3107 // Chunks are marked with the largest point that occurs 3108 // in them (or -1 for no points), so that scans that are 3109 // only interested in points (such as the 3110 // heightmap-related logic) can skip range-only chunks. 3111 maxPoint) { 3112 this.from = from; 3113 this.to = to; 3114 this.value = value; 3115 this.maxPoint = maxPoint; 3116 } 3117 get length() { return this.to[this.to.length - 1]; } 3118 // Find the index of the given position and side. Use the ranges' 3119 // `from` pos when `end == false`, `to` when `end == true`. 3120 findIndex(pos, side, end, startAt = 0) { 3121 let arr = end ? this.to : this.from; 3122 for (let lo = startAt, hi = arr.length;;) { 3123 if (lo == hi) 3124 return lo; 3125 let mid = (lo + hi) >> 1; 3126 let diff = arr[mid] - pos || (end ? this.value[mid].endSide : this.value[mid].startSide) - side; 3127 if (mid == lo) 3128 return diff >= 0 ? lo : hi; 3129 if (diff >= 0) 3130 hi = mid; 3131 else 3132 lo = mid + 1; 3133 } 3134 } 3135 between(offset, from, to, f) { 3136 for (let i = this.findIndex(from, -1000000000 /* C.Far */, true), e = this.findIndex(to, 1000000000 /* C.Far */, false, i); i < e; i++) 3137 if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false) 3138 return false;
vendor: 4,484 bytes, lines 3139-3266
3139 } 3140 map(offset, changes) { 3141 let value = [], from = [], to = [], newPos = -1, maxPoint = -1; 3142 for (let i = 0; i < this.value.length; i++) { 3143 let val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom, newTo; 3144 if (curFrom == curTo) { 3145 let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode); 3146 if (mapped == null) 3147 continue; 3148 newFrom = newTo = mapped; 3149 if (val.startSide != val.endSide) { 3150 newTo = changes.mapPos(curFrom, val.endSide); 3151 if (newTo < newFrom) 3152 continue; 3153 } 3154 } 3155 else { 3156 newFrom = changes.mapPos(curFrom, val.startSide); 3157 newTo = changes.mapPos(curTo, val.endSide); 3158 if (newFrom > newTo || newFrom == newTo && val.startSide > 0 && val.endSide <= 0) 3159 continue; 3160 } 3161 if ((newTo - newFrom || val.endSide - val.startSide) < 0) 3162 continue; 3163 if (newPos < 0) 3164 newPos = newFrom; 3165 if (val.point) 3166 maxPoint = Math.max(maxPoint, newTo - newFrom); 3167 value.push(val); 3168 from.push(newFrom - newPos); 3169 to.push(newTo - newPos); 3170 } 3171 return { mapped: value.length ? new Chunk(from, to, value, maxPoint) : null, pos: newPos }; 3172 } 3173} 3174/** 3175A range set stores a collection of [ranges](https://codemirror.net/6/docs/ref/#state.Range) in a 3176way that makes them efficient to [map](https://codemirror.net/6/docs/ref/#state.RangeSet.map) and 3177[update](https://codemirror.net/6/docs/ref/#state.RangeSet.update). This is an immutable data 3178structure. 3179*/ 3180class RangeSet { 3181 constructor( 3182 /** 3183 @internal 3184 */ 3185 chunkPos, 3186 /** 3187 @internal 3188 */ 3189 chunk, 3190 /** 3191 @internal 3192 */ 3193 nextLayer, 3194 /** 3195 @internal 3196 */ 3197 maxPoint) { 3198 this.chunkPos = chunkPos; 3199 this.chunk = chunk; 3200 this.nextLayer = nextLayer; 3201 this.maxPoint = maxPoint; 3202 } 3203 /** 3204 @internal 3205 */ 3206 static create(chunkPos, chunk, nextLayer, maxPoint) { 3207 return new RangeSet(chunkPos, chunk, nextLayer, maxPoint); 3208 } 3209 /** 3210 @internal 3211 */ 3212 get length() { 3213 let last = this.chunk.length - 1; 3214 return last < 0 ? 0 : Math.max(this.chunkEnd(last), this.nextLayer.length); 3215 } 3216 /** 3217 The number of ranges in the set. 3218 */ 3219 get size() { 3220 if (this.isEmpty) 3221 return 0; 3222 let size = this.nextLayer.size; 3223 for (let chunk of this.chunk) 3224 size += chunk.value.length; 3225 return size; 3226 } 3227 /** 3228 @internal 3229 */ 3230 chunkEnd(index) { 3231 return this.chunkPos[index] + this.chunk[index].length; 3232 } 3233 /** 3234 Update the range set, optionally adding new ranges or filtering 3235 out existing ones. 3236 3237 (Note: The type parameter is just there as a kludge to work 3238 around TypeScript variance issues that prevented `RangeSet<X>` 3239 from being a subtype of `RangeSet<Y>` when `X` is a subtype of 3240 `Y`.) 3241 */ 3242 update(updateSpec) { 3243 let { add = [], sort = false, filterFrom = 0, filterTo = this.length } = updateSpec; 3244 let filter = updateSpec.filter; 3245 if (add.length == 0 && !filter) 3246 return this; 3247 if (sort) 3248 add = add.slice().sort(cmpRange); 3249 if (this.isEmpty) 3250 return add.length ? RangeSet.of(add) : this; 3251 let cur = new LayerCursor(this, null, -1).goto(0), i = 0, spill = []; 3252 let builder = new RangeSetBuilder(); 3253 while (cur.value || i < add.length) { 3254 if (i < add.length && (cur.from - add[i].from || cur.startSide - add[i].value.startSide) >= 0) { 3255 let range = add[i++]; 3256 if (!builder.addInner(range.from, range.to, range.value)) 3257 spill.push(range); 3258 } 3259 else if (cur.rangeIndex == 1 && cur.chunkIndex < this.chunk.length && 3260 (i == add.length || this.chunkEnd(cur.chunkIndex) < add[i].from) && 3261 (!filter || filterFrom > this.chunkEnd(cur.chunkIndex) || filterTo < this.chunkPos[cur.chunkIndex]) && 3262 builder.addChunk(this.chunkPos[cur.chunkIndex], this.chunk[cur.chunkIndex])) { 3263 cur.nextChunk(); 3264 } 3265 else { 3266 if (!filter || filterFrom >
vendor: 4,381 bytes, lines 3266-3373
3266 cur.to || filterTo < cur.from || filter(cur.from, cur.to, cur.value)) { 3267 if (!builder.addInner(cur.from, cur.to, cur.value)) 3268 spill.push(Range$1.create(cur.from, cur.to, cur.value)); 3269 } 3270 cur.next(); 3271 } 3272 } 3273 return builder.finishInner(this.nextLayer.isEmpty && !spill.length ? RangeSet.empty 3274 : this.nextLayer.update({ add: spill, filter, filterFrom, filterTo })); 3275 } 3276 /** 3277 Map this range set through a set of changes, return the new set. 3278 */ 3279 map(changes) { 3280 if (changes.empty || this.isEmpty) 3281 return this; 3282 let chunks = [], chunkPos = [], maxPoint = -1; 3283 for (let i = 0; i < this.chunk.length; i++) { 3284 let start = this.chunkPos[i], chunk = this.chunk[i]; 3285 let touch = changes.touchesRange(start, start + chunk.length); 3286 if (touch === false) { 3287 maxPoint = Math.max(maxPoint, chunk.maxPoint); 3288 chunks.push(chunk); 3289 chunkPos.push(changes.mapPos(start)); 3290 } 3291 else if (touch === true) { 3292 let { mapped, pos } = chunk.map(start, changes); 3293 if (mapped) { 3294 maxPoint = Math.max(maxPoint, mapped.maxPoint); 3295 chunks.push(mapped); 3296 chunkPos.push(pos); 3297 } 3298 } 3299 } 3300 let next = this.nextLayer.map(changes); 3301 return chunks.length == 0 ? next : new RangeSet(chunkPos, chunks, next || RangeSet.empty, maxPoint); 3302 } 3303 /** 3304 Iterate over the ranges that touch the region `from` to `to`, 3305 calling `f` for each. There is no guarantee that the ranges will 3306 be reported in any specific order. When the callback returns 3307 `false`, iteration stops. 3308 */ 3309 between(from, to, f) { 3310 if (this.isEmpty) 3311 return; 3312 for (let i = 0; i < this.chunk.length; i++) { 3313 let start = this.chunkPos[i], chunk = this.chunk[i]; 3314 if (to >= start && from <= start + chunk.length && 3315 chunk.between(start, from - start, to - start, f) === false) 3316 return; 3317 } 3318 this.nextLayer.between(from, to, f); 3319 } 3320 /** 3321 Iterate over the ranges in this set, in order, including all 3322 ranges that end at or after `from`. 3323 */ 3324 iter(from = 0) { 3325 return HeapCursor.from([this]).goto(from); 3326 } 3327 /** 3328 @internal 3329 */ 3330 get isEmpty() { return this.nextLayer == this; } 3331 /** 3332 Iterate over the ranges in a collection of sets, in order, 3333 starting from `from`. 3334 */ 3335 static iter(sets, from = 0) { 3336 return HeapCursor.from(sets).goto(from); 3337 } 3338 /** 3339 Iterate over two groups of sets, calling methods on `comparator` 3340 to notify it of possible differences. 3341 */ 3342 static compare(oldSets, newSets, 3343 /** 3344 This indicates how the underlying data changed between these 3345 ranges, and is needed to synchronize the iteration. `from` and 3346 `to` are coordinates in the _new_ space, after these changes. 3347 */ 3348 textDiff, comparator, 3349 /** 3350 Can be used to ignore all non-point ranges, and points below 3351 the given size. When -1, all ranges are compared. 3352 */ 3353 minPointSize = -1) { 3354 let a = oldSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize); 3355 let b = newSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize); 3356 let sharedChunks = findSharedChunks(a, b, textDiff); 3357 let sideA = new SpanCursor(a, sharedChunks, minPointSize); 3358 let sideB = new SpanCursor(b, sharedChunks, minPointSize); 3359 textDiff.iterGaps((fromA, fromB, length) => compare(sideA, fromA, sideB, fromB, length, comparator)); 3360 if (textDiff.empty && textDiff.length == 0) 3361 compare(sideA, 0, sideB, 0, 0, comparator); 3362 } 3363 /** 3364 Compare the contents of two groups of range sets, returning true 3365 if they are equivalent in the given range. 3366 */ 3367 static eq(oldSets, newSets, from = 0, to) { 3368 if (to == null) 3369 to = 1000000000 /* C.Far */; 3370 let a = oldSets.filter(set => !set.isEmpty && newSets.indexOf(set) < 0); 3371 let b = newSets.filter(set => !set.isEmpty && oldSets.indexOf(set) < 0); 3372 if (a.length != b.length) 3373 return false;
3374 if (!a.length) 3375 return true; 3376 let sharedChunks = findSharedChunks(a, b); 3377 let sideA = new SpanCursor(a, sharedChunks, 0).goto(from), sideB = new SpanCursor(b, sharedChunks, 0).goto(from); 3378 for (;;) { 3379 if (sideA.to != sideB.to || 3380 !sameValues(sideA.active, sideB.active) || 3381 sideA.point && (!sideB.point || !sideA.point.eq(sideB.point))) 3382 return false; 3383 if (sideA.to > to) 3384 return true; 3385 sideA.next(); 3386 sideB.next(); 3387 } 3388 } 3389 /** 3390 Iterate over a group of range sets at the same time, notifying 3391 the iterator about the ranges covering every given piece of 3392 content. Returns the open count (see 3393 [`SpanIterator.span`](https://codemirror.net/6/docs/ref/#state.SpanIterator.span)) at the end 3394 of the iteration. 3395 */ 3396 static spans(sets, from, to, iterator, 3397 /** 3398 When given and greater than -1, only points of at least this 3399 size are taken into account. 3400 */ 3401 minPointSize = -1) { 3402 let cursor = new SpanCursor(sets, null, minPointSize).goto(from), pos = from; 3403 let open = cursor.openStart; 3404 for (;;) { 3405 let curTo = Math.min(cursor.to, to); 3406 if (cursor.point) { 3407 iterator.point(pos, curTo, cursor.point, cursor.activeForPoint(cursor.to), open, cursor.pointRank); 3408 open = cursor.openEnd(curTo) + (cursor.to > curTo ? 1 : 0); 3409 } 3410 else if (curTo > pos) { 3411 iterator.span(pos, curTo, cursor.active, open); 3412 open = cursor.openEnd(curTo); 3413 } 3414 if (cursor.to > to) 3415 break; 3416 pos = cursor.to; 3417 cursor.next(); 3418 } 3419 return open; 3420 } 3421 /** 3422 Create a range set for the given range or array of ranges. By 3423 default, this expects the ranges to be _sorted_ (by start 3424 position and, if two start at the same position, 3425 `value.startSide`). You can pass `true` as second argument to 3426 cause the method to sort them. 3427 */ 3428 static of(ranges, sort = false) { 3429 let build = new RangeSetBuilder(); 3430 for (let range of ranges instanceof Range$1 ? [ranges] : sort ? lazySort(ranges) : ranges) 3431 build.add(range.from, range.to, range.value); 3432 return build.finish(); 3433 } 3434} 3435/** 3436The empty set of ranges. 3437*/ 3438RangeSet.empty = /*@__PURE__*/new RangeSet([], [], null, -1); 3439function lazySort(ranges) { 3440 if (ranges.length > 1) 3441 for (let prev = ranges[0], i = 1; i < ranges.length; i++) { 3442 let cur = ranges[i]; 3443 if (cmpRange(prev, cur) > 0) 3444 return ranges.slice().sort(cmpRange); 3445 prev = cur; 3446 } 3447 return ranges; 3448} 3449RangeSet.empty.nextLayer = RangeSet.empty; 3450/** 3451A range set builder is a data structure that helps build up a 3452[range set](https://codemirror.net/6/docs/ref/#state.RangeSet) directly, without first allocating 3453an array of [`Range`](https://codemirror.net/6/docs/ref/#state.Range) objects. 3454*/ 3455class RangeSetBuilder { 3456 /** 3457 Create an empty builder. 3458 */ 3459 constructor() { 3460 this.chunks = []; 3461 this.chunkPos = []; 3462 this.chunkStart = -1; 3463 this.last = null; 3464 this.lastFrom = -1000000000 /* C.Far */; 3465 this.lastTo = -1000000000 /* C.Far */; 3466 this.from = []; 3467 this.to = []; 3468 this.value = []; 3469 this.maxPoint = -1; 3470 this.setMaxPoint = -1; 3471 this.nextLayer = null; 3472 } 3473 finishChunk(newArrays) { 3474 this.chunks.push(new Chunk(this.from, this.to, this.value, this.maxPoint)); 3475 this.chunkPos.push(this.chunkStart); 3476 this.chunkStart = -1; 3477 this.setMaxPoint = Math.max(this.setMaxPoint, this.maxPoint); 3478 this.maxPoint = -1; 3479 if (newArrays) { 3480 this.from = []; 3481 this.to = []; 3482 this.value = []; 3483 } 3484 } 3485 /** 3486 Add a range. Ranges should be added in sorted (by `from` and 3487 `value.startSide`) order. 3488 */ 3489 add(from, to, value) { 3490 if (!this.addInner(from, to, value)) 3491 (this.nextLayer || (this.nextLayer = new RangeSetBuilder)).add(from, to, value); 3492 } 3493 /** 3494 @internal 3495 */ 3496 addInner(from, to, value) { 3497 let diff = from - this.lastTo || value.startSide - this.last.endSide; 3498 if (diff <= 0 && (from - this.lastFrom || value.startSide - this.last.startSide) < 0) 3499 throw new Error("Ranges must be added sorted by `from` position and `startSide`"); 3500 if (diff < 0) 3501 return false;
vendor: 13,276 bytes, lines 3502-3865
3502 if (this.from.length == 250 /* C.ChunkSize */) 3503 this.finishChunk(true); 3504 if (this.chunkStart < 0) 3505 this.chunkStart = from; 3506 this.from.push(from - this.chunkStart); 3507 this.to.push(to - this.chunkStart); 3508 this.last = value; 3509 this.lastFrom = from; 3510 this.lastTo = to; 3511 this.value.push(value); 3512 if (value.point) 3513 this.maxPoint = Math.max(this.maxPoint, to - from); 3514 return true; 3515 } 3516 /** 3517 @internal 3518 */ 3519 addChunk(from, chunk) { 3520 if ((from - this.lastTo || chunk.value[0].startSide - this.last.endSide) < 0) 3521 return false; 3522 if (this.from.length) 3523 this.finishChunk(true); 3524 this.setMaxPoint = Math.max(this.setMaxPoint, chunk.maxPoint); 3525 this.chunks.push(chunk); 3526 this.chunkPos.push(from); 3527 let last = chunk.value.length - 1; 3528 this.last = chunk.value[last]; 3529 this.lastFrom = chunk.from[last] + from; 3530 this.lastTo = chunk.to[last] + from; 3531 return true; 3532 } 3533 /** 3534 Finish the range set. Returns the new set. The builder can't be 3535 used anymore after this has been called. 3536 */ 3537 finish() { return this.finishInner(RangeSet.empty); } 3538 /** 3539 @internal 3540 */ 3541 finishInner(next) { 3542 if (this.from.length) 3543 this.finishChunk(false); 3544 if (this.chunks.length == 0) 3545 return next; 3546 let result = RangeSet.create(this.chunkPos, this.chunks, this.nextLayer ? this.nextLayer.finishInner(next) : next, this.setMaxPoint); 3547 this.from = null; // Make sure further `add` calls produce errors 3548 return result; 3549 } 3550} 3551function findSharedChunks(a, b, textDiff) { 3552 let inA = new Map(); 3553 for (let set of a) 3554 for (let i = 0; i < set.chunk.length; i++) 3555 if (set.chunk[i].maxPoint <= 0) 3556 inA.set(set.chunk[i], set.chunkPos[i]); 3557 let shared = new Set(); 3558 for (let set of b) 3559 for (let i = 0; i < set.chunk.length; i++) { 3560 let known = inA.get(set.chunk[i]); 3561 if (known != null && (textDiff ? textDiff.mapPos(known) : known) == set.chunkPos[i] && 3562 !(textDiff === null || textDiff === void 0 ? void 0 : textDiff.touchesRange(known, known + set.chunk[i].length))) 3563 shared.add(set.chunk[i]); 3564 } 3565 return shared; 3566} 3567class LayerCursor { 3568 constructor(layer, skip, minPoint, rank = 0) { 3569 this.layer = layer; 3570 this.skip = skip; 3571 this.minPoint = minPoint; 3572 this.rank = rank; 3573 } 3574 get startSide() { return this.value ? this.value.startSide : 0; } 3575 get endSide() { return this.value ? this.value.endSide : 0; } 3576 goto(pos, side = -1000000000 /* C.Far */) { 3577 this.chunkIndex = this.rangeIndex = 0; 3578 this.gotoInner(pos, side, false); 3579 return this; 3580 } 3581 gotoInner(pos, side, forward) { 3582 while (this.chunkIndex < this.layer.chunk.length) { 3583 let next = this.layer.chunk[this.chunkIndex]; 3584 if (!(this.skip && this.skip.has(next) || 3585 this.layer.chunkEnd(this.chunkIndex) < pos || 3586 next.maxPoint < this.minPoint)) 3587 break; 3588 this.chunkIndex++; 3589 forward = false; 3590 } 3591 if (this.chunkIndex < this.layer.chunk.length) { 3592 let rangeIndex = this.layer.chunk[this.chunkIndex].findIndex(pos - this.layer.chunkPos[this.chunkIndex], side, true); 3593 if (!forward || this.rangeIndex < rangeIndex) 3594 this.setRangeIndex(rangeIndex); 3595 } 3596 this.next(); 3597 } 3598 forward(pos, side) { 3599 if ((this.to - pos || this.endSide - side) < 0) 3600 this.gotoInner(pos, side, true); 3601 } 3602 next() { 3603 for (;;) { 3604 if (this.chunkIndex == this.layer.chunk.length) { 3605 this.from = this.to = 1000000000 /* C.Far */; 3606 this.value = null; 3607 break; 3608 } 3609 else { 3610 let chunkPos = this.layer.chunkPos[this.chunkIndex], chunk = this.layer.chunk[this.chunkIndex]; 3611 let from = chunkPos + chunk.from[this.rangeIndex]; 3612 this.from = from; 3613 this.to = chunkPos + chunk.to[this.rangeIndex]; 3614 this.value = chunk.value[this.rangeIndex]; 3615 this.setRangeIndex(this.rangeIndex + 1); 3616 if (this.minPoint < 0 || this.value.point && this.to - this.from >= this.minPoint) 3617 break; 3618 } 3619 } 3620 } 3621 setRangeIndex(index) { 3622 if (index == this.layer.chunk[this.chunkIndex].value.length) { 3623 this.chunkIndex++; 3624 if (this.skip) { 3625 while (this.chunkIndex < this.layer.chunk.length && this.skip.has(this.layer.chunk[this.chunkIndex])) 3626 this.chunkIndex++; 3627 } 3628 this.rangeIndex = 0; 3629 } 3630 else { 3631 this.rangeIndex = index; 3632 } 3633 } 3634 nextChunk() { 3635 this.chunkIndex++; 3636 this.rangeIndex = 0; 3637 this.next(); 3638 } 3639 compare(other) { 3640 return this.from - other.from || this.startSide - other.startSide || this.rank - other.rank || 3641 this.to - other.to || this.endSide - other.endSide; 3642 } 3643} 3644class HeapCursor { 3645 constructor(heap) { 3646 this.heap = heap; 3647 } 3648 static from(sets, skip = null, minPoint = -1) { 3649 let heap = []; 3650 for (let i = 0; i < sets.length; i++) { 3651 for (let cur = sets[i]; !cur.isEmpty; cur = cur.nextLayer) { 3652 if (cur.maxPoint >= minPoint) 3653 heap.push(new LayerCursor(cur, skip, minPoint, i)); 3654 } 3655 } 3656 return heap.length == 1 ? heap[0] : new HeapCursor(heap); 3657 } 3658 get startSide() { return this.value ? this.value.startSide : 0; } 3659 goto(pos, side = -1000000000 /* C.Far */) { 3660 for (let cur of this.heap) 3661 cur.goto(pos, side); 3662 for (let i = this.heap.length >> 1; i >= 0; i--) 3663 heapBubble(this.heap, i); 3664 this.next(); 3665 return this; 3666 } 3667 forward(pos, side) { 3668 for (let cur of this.heap) 3669 cur.forward(pos, side); 3670 for (let i = this.heap.length >> 1; i >= 0; i--) 3671 heapBubble(this.heap, i); 3672 if ((this.to - pos || this.value.endSide - side) < 0) 3673 this.next(); 3674 } 3675 next() { 3676 if (this.heap.length == 0) { 3677 this.from = this.to = 1000000000 /* C.Far */; 3678 this.value = null; 3679 this.rank = -1; 3680 } 3681 else { 3682 let top = this.heap[0]; 3683 this.from = top.from; 3684 this.to = top.to; 3685 this.value = top.value; 3686 this.rank = top.rank; 3687 if (top.value) 3688 top.next(); 3689 heapBubble(this.heap, 0); 3690 } 3691 } 3692} 3693function heapBubble(heap, index) { 3694 for (let cur = heap[index];;) { 3695 let childIndex = (index << 1) + 1; 3696 if (childIndex >= heap.length) 3697 break; 3698 let child = heap[childIndex]; 3699 if (childIndex + 1 < heap.length && child.compare(heap[childIndex + 1]) >= 0) { 3700 child = heap[childIndex + 1]; 3701 childIndex++; 3702 } 3703 if (cur.compare(child) < 0) 3704 break; 3705 heap[childIndex] = cur; 3706 heap[index] = child; 3707 index = childIndex; 3708 } 3709} 3710class SpanCursor { 3711 constructor(sets, skip, minPoint) { 3712 this.minPoint = minPoint; 3713 this.active = []; 3714 this.activeTo = []; 3715 this.activeRank = []; 3716 this.minActive = -1; 3717 // A currently active point range, if any 3718 this.point = null; 3719 this.pointFrom = 0; 3720 this.pointRank = 0; 3721 this.to = -1000000000 /* C.Far */; 3722 this.endSide = 0; 3723 this.openStart = -1; 3724 this.cursor = HeapCursor.from(sets, skip, minPoint); 3725 } 3726 goto(pos, side = -1000000000 /* C.Far */) { 3727 this.cursor.goto(pos, side); 3728 this.active.length = this.activeTo.length = this.activeRank.length = 0; 3729 this.minActive = -1; 3730 this.to = pos; 3731 this.endSide = side; 3732 this.openStart = -1; 3733 this.next(); 3734 return this; 3735 } 3736 forward(pos, side) { 3737 while (this.minActive > -1 && (this.activeTo[this.minActive] - pos || this.active[this.minActive].endSide - side) < 0) 3738 this.removeActive(this.minActive); 3739 this.cursor.forward(pos, side); 3740 } 3741 removeActive(index) { 3742 remove(this.active, index); 3743 remove(this.activeTo, index); 3744 remove(this.activeRank, index); 3745 this.minActive = findMinIndex(this.active, this.activeTo); 3746 } 3747 addActive(trackOpen) { 3748 let i = 0, { value, to, rank } = this.cursor; 3749 while (i < this.activeRank.length && this.activeRank[i] <= rank) 3750 i++; 3751 insert$5(this.active, i, value); 3752 insert$5(this.activeTo, i, to); 3753 insert$5(this.activeRank, i, rank); 3754 if (trackOpen) 3755 insert$5(trackOpen, i, this.cursor.from); 3756 this.minActive = findMinIndex(this.active, this.activeTo); 3757 } 3758 // After calling this, if `this.point` != null, the next range is a 3759 // point. Otherwise, it's a regular range, covered by `this.active`. 3760 next() { 3761 let from = this.to, wasPoint = this.point; 3762 this.point = null; 3763 let trackOpen = this.openStart < 0 ? [] : null, trackExtra = 0; 3764 for (;;) { 3765 let a = this.minActive; 3766 if (a > -1 && (this.activeTo[a] - this.cursor.from || this.active[a].endSide - this.cursor.startSide) < 0) { 3767 if (this.activeTo[a] > from) { 3768 this.to = this.activeTo[a]; 3769 this.endSide = this.active[a].endSide; 3770 break; 3771 } 3772 this.removeActive(a); 3773 if (trackOpen) 3774 remove(trackOpen, a); 3775 } 3776 else if (!this.cursor.value) { 3777 this.to = this.endSide = 1000000000 /* C.Far */; 3778 break; 3779 } 3780 else if (this.cursor.from > from) { 3781 this.to = this.cursor.from; 3782 this.endSide = this.cursor.startSide; 3783 break; 3784 } 3785 else { 3786 let nextVal = this.cursor.value; 3787 if (!nextVal.point) { // Opening a range 3788 this.addActive(trackOpen); 3789 if (this.cursor.from < from && this.cursor.to > from) 3790 trackExtra++; 3791 this.cursor.next(); 3792 } 3793 else if (wasPoint && this.cursor.to == this.to && this.cursor.from < this.cursor.to) { 3794 // Ignore any non-empty points that end precisely at the end of the prev point 3795 this.cursor.next(); 3796 } 3797 else { // New point 3798 this.point = nextVal; 3799 this.pointFrom = this.cursor.from; 3800 this.pointRank = this.cursor.rank; 3801 this.to = this.cursor.to; 3802 this.endSide = nextVal.endSide; 3803 if (this.cursor.from < from) 3804 trackExtra = 1; 3805 this.cursor.next(); 3806 this.forward(this.to, this.endSide); 3807 break; 3808 } 3809 } 3810 } 3811 if (trackOpen) { 3812 let openStart = 0; 3813 while (openStart < trackOpen.length && trackOpen[openStart] < from) 3814 openStart++; 3815 this.openStart = openStart + trackExtra; 3816 } 3817 } 3818 activeForPoint(to) { 3819 if (!this.active.length) 3820 return this.active; 3821 let active = []; 3822 for (let i = this.active.length - 1; i >= 0; i--) { 3823 if (this.activeRank[i] < this.pointRank) 3824 break; 3825 if (this.activeTo[i] > to || this.activeTo[i] == to && this.active[i].endSide >= this.point.endSide) 3826 active.push(this.active[i]); 3827 } 3828 return active.reverse(); 3829 } 3830 openEnd(to) { 3831 let open = 0; 3832 for (let i = this.activeTo.length - 1; i >= 0 && this.activeTo[i] > to; i--) 3833 open++; 3834 return open; 3835 } 3836} 3837function compare(a, startA, b, startB, length, comparator) { 3838 a.goto(startA); 3839 b.goto(startB); 3840 let endB = startB + length; 3841 let pos = startB, dPos = startB - startA; 3842 for (;;) { 3843 let diff = (a.to + dPos) - b.to || a.endSide - b.endSide; 3844 let end = diff < 0 ? a.to + dPos : b.to, clipEnd = Math.min(end, endB); 3845 if (a.point || b.point) { 3846 if (!(a.point && b.point && (a.point == b.point || a.point.eq(b.point)) && 3847 sameValues(a.activeForPoint(a.to + dPos), b.activeForPoint(b.to)))) 3848 comparator.comparePoint(pos, clipEnd, a.point, b.point); 3849 } 3850 else { 3851 if (clipEnd > pos && !sameValues(a.active, b.active)) 3852 comparator.compareRange(pos, clipEnd, a.active, b.active); 3853 } 3854 if (end > endB) 3855 break; 3856 pos = end; 3857 if (diff <= 0) 3858 a.next(); 3859 if (diff >= 0) 3860 b.next(); 3861 } 3862} 3863function sameValues(a, b) { 3864 if (a.length != b.length) 3865 return false;
3866 for (let i = 0; i < a.length; i++) 3867 if (a[i] != b[i] && !a[i].eq(b[i])) 3868 return false; 3869 return true; 3870} 3871function remove(array, index) { 3872 for (let i = index, e = array.length - 1; i < e; i++) 3873 array[i] = array[i + 1]; 3874 array.pop(); 3875} 3876function insert$5(array, index, value) { 3877 for (let i = array.length - 1; i >= index; i--) 3878 array[i + 1] = array[i]; 3879 array[index] = value; 3880} 3881function findMinIndex(value, array) { 3882 let found = -1, foundPos = 1000000000 /* C.Far */; 3883 for (let i = 0; i < array.length; i++) 3884 if ((array[i] - foundPos || value[i].endSide - value[found].endSide) < 0) { 3885 found = i; 3886 foundPos = array[i]; 3887 } 3888 return found; 3889} 3890 3891/** 3892Count the column position at the given offset into the string, 3893taking extending characters and tab size into account. 3894*/ 3895function countColumn(string, tabSize, to = string.length) { 3896 let n = 0; 3897 for (let i = 0; i < to;) { 3898 if (string.charCodeAt(i) == 9) { 3899 n += tabSize - (n % tabSize); 3900 i++; 3901 } 3902 else { 3903 n++; 3904 i = findClusterBreak(string, i); 3905 } 3906 } 3907 return n; 3908} 3909/** 3910Find the offset that corresponds to the given column position in a 3911string, taking extending characters and tab size into account. By 3912default, the string length is returned when it is too short to 3913reach the column. Pass `strict` true to make it return -1 in that 3914situation. 3915*/ 3916function findColumn(string, col, tabSize, strict) { 3917 for (let i = 0, n = 0;;) { 3918 if (n >= col) 3919 return i; 3920 if (i == string.length) 3921 break; 3922 n += string.charCodeAt(i) == 9 ? tabSize - (n % tabSize) : 1; 3923 i = findClusterBreak(string, i); 3924 } 3925 return strict === true ? -1 : string.length; 3926} 3927 3928const C = "\u037c"; 3929const COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C); 3930const SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : Symbol("styleSet"); 3931const top = typeof globalThis != "undefined" ? globalThis : typeof window != "undefined" ? window : {}; 3932 3933// :: - Style modules encapsulate a set of CSS rules defined from 3934// JavaScript. Their definitions are only available in a given DOM 3935// root after it has been _mounted_ there with `StyleModule.mount`. 3936// 3937// Style modules should be created once and stored somewhere, as 3938// opposed to re-creating them every time you need them. The amount of 3939// CSS rules generated for a given DOM root is bounded by the amount 3940// of style modules that were used. So to avoid leaking rules, don't 3941// create these dynamically, but treat them as one-time allocations. 3942class StyleModule { 3943 // :: (Object<Style>, ?{finish: ?(string) â string}) 3944 // Create a style module from the given spec. 3945 // 3946 // When `finish` is given, it is called on regular (non-`@`) 3947 // selectors (after `&` expansion) to compute the final selector. 3948 constructor(spec, options) { 3949 this.rules = []; 3950 let {finish} = options || {}; 3951 3952 function splitSelector(selector) { 3953 return /^@/.test(selector) ? [selector] : selector.split(/,\s*/) 3954 } 3955 3956 function render(selectors, spec, target, isKeyframes) { 3957 let local = [], isAt = /^@(\w+)\b/.exec(selectors[0]), keyframes = isAt && isAt[1] == "keyframes"; 3958 if (isAt && spec == null) return target.push(selectors[0] + ";") 3959 for (let prop in spec) { 3960 let value = spec[prop]; 3961 if (/&/.test(prop)) { 3962 render(prop.split(/,\s*/).map(part => selectors.map(sel => part.replace(/&/, sel))).reduce((a, b) => a.concat(b)), 3963 value, target); 3964 } else if (value && typeof value == "object") { 3965 if (!isAt) throw new RangeError("The value of a property (" + prop + ") should be a primitive value.") 3966 render(splitSelector(prop), value, local, keyframes); 3967 } else if (value != null) {
3968 local.push(prop.replace(/_.*/, "").replace(/[A-Z]/g, l => "-" + l.toLowerCase()) + ": " + value + ";"); 3969 } 3970 } 3971 if (local.length || keyframes) { 3972 target.push((finish && !isAt && !isKeyframes ? selectors.map(finish) : selectors).join(", ") + 3973 " {" + local.join(" ") + "}"); 3974 } 3975 } 3976 3977 for (let prop in spec) render(splitSelector(prop), spec[prop], this.rules); 3978 } 3979 3980 // :: () â string 3981 // Returns a string containing the module's CSS rules. 3982 getRules() { return this.rules.join("\n") } 3983 3984 // :: () â string 3985 // Generate a new unique CSS class name. 3986 static newName() { 3987 let id = top[COUNT] || 1; 3988 top[COUNT] = id + 1; 3989 return C + id.toString(36) 3990 } 3991 3992 // :: (union<Document, ShadowRoot>, union<[StyleModule], StyleModule>, ?{nonce: ?string}) 3993 // 3994 // Mount the given set of modules in the given DOM root, which ensures 3995 // that the CSS rules defined by the module are available in that 3996 // context. 3997 // 3998 // Rules are only added to the document once per root. 3999 // 4000 // Rule order will follow the order of the modules, so that rules from 4001 // modules later in the array take precedence of those from earlier 4002 // modules. If you call this function multiple times for the same root 4003 // in a way that changes the order of already mounted modules, the old 4004 // order will be changed. 4005 // 4006 // If a Content Security Policy nonce is provided, it is added to 4007 // the `<style>` tag generated by the library. 4008 static mount(root, modules, options) { 4009 let set = root[SET], nonce = options && options.nonce; 4010 if (!set) set = new StyleSet(root, nonce); 4011 else if (nonce) set.setNonce(nonce); 4012 set.mount(Array.isArray(modules) ? modules : [modules]); 4013 } 4014} 4015 4016let adoptedSet = new Map; //<Document, StyleSet> 4017 4018class StyleSet { 4019 constructor(root, nonce) { 4020 let doc = root.ownerDocument || root, win = doc.defaultView; 4021 if (!root.head && root.adoptedStyleSheets && win.CSSStyleSheet) { 4022 let adopted = adoptedSet.get(doc); 4023 if (adopted) { 4024 root.adoptedStyleSheets = [adopted.sheet, ...root.adoptedStyleSheets]; 4025 return root[SET] = adopted 4026 } 4027 this.sheet = new win.CSSStyleSheet; 4028 root.adoptedStyleSheets = [this.sheet, ...root.adoptedStyleSheets]; 4029 adoptedSet.set(doc, this); 4030 } else { 4031 this.styleTag = doc.createElement("style"); 4032 if (nonce) this.styleTag.setAttribute("nonce", nonce); 4033 let target = root.head || root; 4034 target.insertBefore(this.styleTag, target.firstChild); 4035 } 4036 this.modules = []; 4037 root[SET] = this; 4038 } 4039 4040 mount(modules) { 4041 let sheet = this.sheet; 4042 let pos = 0 /* Current rule offset */, j = 0; /* Index into this.modules */ 4043 for (let i = 0; i < modules.length; i++) { 4044 let mod = modules[i], index = this.modules.indexOf(mod); 4045 if (index < j && index > -1) { // Ordering conflict 4046 this.modules.splice(index, 1); 4047 j--; 4048 index = -1; 4049 } 4050 if (index == -1) { 4051 this.modules.splice(j++, 0, mod); 4052 if (sheet) for (let k = 0; k < mod.rules.length; k++) 4053 sheet.insertRule(mod.rules[k], pos++); 4054 } else { 4055 while (j < index) pos += this.modules[j++].rules.length; 4056 pos += mod.rules.length; 4057 j++; 4058 } 4059 } 4060 4061 if (!sheet) { 4062 let text = ""; 4063 for (let i = 0; i < this.modules.length; i++) 4064 text += this.modules[i].getRules() + "\n"; 4065 this.styleTag.textContent = text; 4066 } 4067 } 4068 4069 setNonce(nonce) { 4070 if (this.styleTag && this.styleTag.getAttribute("nonce") != nonce) 4071 this.styleTag.setAttribute("nonce", nonce); 4072 } 4073} 4074 4075// Style::Object<union<Style,string>> 4076// 4077// A style is an object that, in the simple case, maps CSS property 4078// names to strings holding their values, as in `{color: "red", 4079// fontWeight: "bold"}`. The property names can be given in 4080// camel-caseâthe library will insert a dash before capital letters 4081// when converting them to CSS. 4082// 4083// If you include an underscore in a property name, it and everything 4084// after it will be removed from the output, which can be useful when 4085// providing a property multiple times, for browser compatibility 4086// reasons.
4087// 4088// A property in a style object can also be a sub-selector, which 4089// extends the current context to add a pseudo-selector or a child 4090// selector. Such a property should contain a `&` character, which 4091// will be replaced by the current selector. For example `{"&:before": 4092// {content: '"hi"'}}`. Sub-selectors and regular properties can 4093// freely be mixed in a given object. Any property containing a `&` is 4094// assumed to be a sub-selector. 4095// 4096// Finally, a property can specify an @-block to be wrapped around the 4097// styles defined inside the object that's the property's value. For 4098// example to create a media query you can do `{"@media screen and 4099// (min-width: 400px)": {...}}`. 4100 4101var base = { 4102 8: "Backspace", 4103 9: "Tab", 4104 10: "Enter", 4105 12: "NumLock", 4106 13: "Enter", 4107 16: "Shift", 4108 17: "Control", 4109 18: "Alt", 4110 20: "CapsLock", 4111 27: "Escape", 4112 32: " ", 4113 33: "PageUp", 4114 34: "PageDown", 4115 35: "End", 4116 36: "Home", 4117 37: "ArrowLeft", 4118 38: "ArrowUp", 4119 39: "ArrowRight", 4120 40: "ArrowDown", 4121 44: "PrintScreen", 4122 45: "Insert", 4123 46: "Delete", 4124 59: ";", 4125 61: "=", 4126 91: "Meta", 4127 92: "Meta", 4128 106: "*", 4129 107: "+", 4130 108: ",", 4131 109: "-", 4132 110: ".", 4133 111: "/", 4134 144: "NumLock", 4135 145: "ScrollLock", 4136 160: "Shift", 4137 161: "Shift", 4138 162: "Control", 4139 163: "Control", 4140 164: "Alt", 4141 165: "Alt", 4142 173: "-", 4143 186: ";", 4144 187: "=", 4145 188: ",", 4146 189: "-", 4147 190: ".", 4148 191: "/", 4149 192: "`", 4150 219: "[", 4151 220: "\\", 4152 221: "]", 4153 222: "'" 4154}; 4155 4156var shift = { 4157 48: ")", 4158 49: "!", 4159 50: "@", 4160 51: "#", 4161 52: "$", 4162 53: "%", 4163 54: "^", 4164 55: "&", 4165 56: "*", 4166 57: "(", 4167 59: ":", 4168 61: "+", 4169 173: "_", 4170 186: ":", 4171 187: "+", 4172 188: "<", 4173 189: "_", 4174 190: ">", 4175 191: "?", 4176 192: "~", 4177 219: "{", 4178 220: "|", 4179 221: "}", 4180 222: "\"" 4181}; 4182 4183var mac = typeof navigator != "undefined" && /Mac/.test(navigator.platform); 4184var ie$1 = typeof navigator != "undefined" && /MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); 4185 4186// Fill in the digit keys 4187for (var i = 0; i < 10; i++) base[48 + i] = base[96 + i] = String(i); 4188 4189// The function keys 4190for (var i = 1; i <= 24; i++) base[i + 111] = "F" + i; 4191 4192// And the alphabetic keys 4193for (var i = 65; i <= 90; i++) { 4194 base[i] = String.fromCharCode(i + 32); 4195 shift[i] = String.fromCharCode(i); 4196} 4197 4198// For each code that doesn't have a shift-equivalent, copy the base name 4199for (var code in base) if (!shift.hasOwnProperty(code)) shift[code] = base[code]; 4200 4201function keyName(event) { 4202 // On macOS, keys held with Shift and Cmd don't reflect the effect of Shift in `.key`. 4203 // On IE, shift effect is never included in `.key`. 4204 var ignoreKey = mac && event.metaKey && event.shiftKey && !event.ctrlKey && !event.altKey || 4205 ie$1 && event.shiftKey && event.key && event.key.length == 1 || 4206 event.key == "Unidentified"; 4207 var name = (!ignoreKey && event.key) || 4208 (event.shiftKey ? shift : base)[event.keyCode] || 4209 event.key || "Unidentified"; 4210 // Edge sometimes produces wrong names (Issue #3) 4211 if (name == "Esc") name = "Escape"; 4212 if (name == "Del") name = "Delete"; 4213 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/ 4214 if (name == "Left") name = "ArrowLeft"; 4215 if (name == "Up") name = "ArrowUp"; 4216 if (name == "Right") name = "ArrowRight"; 4217 if (name == "Down") name = "ArrowDown"; 4218 return name 4219} 4220 4221function getSelection(root) { 4222 let target; 4223 // Browsers differ on whether shadow roots have a getSelection 4224 // method. If it exists, use that, otherwise, call it on the 4225 // document. 4226 if (root.nodeType == 11) { // Shadow root 4227 target = root.getSelection ? root : root.ownerDocument; 4228 } 4229 else { 4230 target = root; 4231 } 4232 return target.getSelection(); 4233} 4234function contains(dom, node) { 4235 return node ? dom == node || dom.contains(node.nodeType != 1 ? node.parentNode : node) : false; 4236} 4237function deepActiveElement(doc) { 4238 let elt = doc.activeElement; 4239 while (elt && elt.shadowRoot) 4240 elt = elt.shadowRoot.activeElement; 4241 return elt; 4242} 4243function hasSelection(dom, selection) { 4244 if (!selection.anchorNode) 4245 return false; 4246 try { 4247 // Firefox will raise 'permission denied' errors when accessing 4248 // properties of `sel.anchorNode` when it's in a generated CSS 4249 // element. 4250 return contains(dom, selection.anchorNode); 4251 } 4252 catch (_) { 4253 return false;
4254 } 4255} 4256function clientRectsFor(dom) { 4257 if (dom.nodeType == 3) 4258 return textRange(dom, 0, dom.nodeValue.length).getClientRects(); 4259 else if (dom.nodeType == 1) 4260 return dom.getClientRects(); 4261 else 4262 return []; 4263} 4264// Scans forward and backward through DOM positions equivalent to the 4265// given one to see if the two are in the same place (i.e. after a 4266// text node vs at the end of that text node) 4267function isEquivalentPosition(node, off, targetNode, targetOff) { 4268 return targetNode ? (scanFor(node, off, targetNode, targetOff, -1) || 4269 scanFor(node, off, targetNode, targetOff, 1)) : false; 4270} 4271function domIndex(node) { 4272 for (var index = 0;; index++) { 4273 node = node.previousSibling; 4274 if (!node) 4275 return index; 4276 } 4277} 4278function scanFor(node, off, targetNode, targetOff, dir) { 4279 for (;;) { 4280 if (node == targetNode && off == targetOff) 4281 return true; 4282 if (off == (dir < 0 ? 0 : maxOffset(node))) { 4283 if (node.nodeName == "DIV") 4284 return false; 4285 let parent = node.parentNode; 4286 if (!parent || parent.nodeType != 1) 4287 return false; 4288 off = domIndex(node) + (dir < 0 ? 0 : 1); 4289 node = parent; 4290 } 4291 else if (node.nodeType == 1) { 4292 node = node.childNodes[off + (dir < 0 ? -1 : 0)]; 4293 if (node.nodeType == 1 && node.contentEditable == "false") 4294 return false; 4295 off = dir < 0 ? maxOffset(node) : 0; 4296 } 4297 else { 4298 return false; 4299 } 4300 } 4301} 4302function maxOffset(node) { 4303 return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length; 4304} 4305const Rect0 = { left: 0, right: 0, top: 0, bottom: 0 }; 4306function flattenRect(rect, left) { 4307 let x = left ? rect.left : rect.right; 4308 return { left: x, right: x, top: rect.top, bottom: rect.bottom }; 4309} 4310function windowRect(win) { 4311 return { left: 0, right: win.innerWidth, 4312 top: 0, bottom: win.innerHeight }; 4313} 4314function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) { 4315 let doc = dom.ownerDocument, win = doc.defaultView || window; 4316 for (let cur = dom; cur;) { 4317 if (cur.nodeType == 1) { // Element 4318 let bounding, top = cur == doc.body; 4319 if (top) { 4320 bounding = windowRect(win); 4321 } 4322 else { 4323 if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) { 4324 cur = cur.assignedSlot || cur.parentNode; 4325 continue; 4326 } 4327 let rect = cur.getBoundingClientRect(); 4328 // Make sure scrollbar width isn't included in the rectangle 4329 bounding = { left: rect.left, right: rect.left + cur.clientWidth, 4330 top: rect.top, bottom: rect.top + cur.clientHeight }; 4331 } 4332 let moveX = 0, moveY = 0; 4333 if (y == "nearest") { 4334 if (rect.top < bounding.top) { 4335 moveY = -(bounding.top - rect.top + yMargin); 4336 if (side > 0 && rect.bottom > bounding.bottom + moveY) 4337 moveY = rect.bottom - bounding.bottom + moveY + yMargin; 4338 } 4339 else if (rect.bottom > bounding.bottom) { 4340 moveY = rect.bottom - bounding.bottom + yMargin; 4341 if (side < 0 && (rect.top - moveY) < bounding.top) 4342 moveY = -(bounding.top + moveY - rect.top + yMargin); 4343 } 4344 } 4345 else { 4346 let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top; 4347 let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 : 4348 y == "start" || y == "center" && side < 0 ? rect.top - yMargin : 4349 rect.bottom - boundingHeight + yMargin; 4350 moveY = targetTop - bounding.top; 4351 } 4352 if (x == "nearest") { 4353 if (rect.left < bounding.left) { 4354 moveX = -(bounding.left - rect.left + xMargin); 4355 if (side > 0 && rect.right > bounding.right + moveX) 4356 moveX = rect.right - bounding.right + moveX + xMargin; 4357 } 4358 else if (rect.right > bounding.right) { 4359 moveX = rect.right - bounding.right + xMargin; 4360 if (side < 0 && rect.left < bounding.left + moveX) 4361 moveX = -(bounding.left + moveX - rect.left + xMargin); 4362 } 4363 } 4364 else { 4365 let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 : 4366 (x == "start") == ltr ? rect.left - xMargin : 4367 rect.right - (bounding.right - bounding.left) + xMargin; 4368 moveX = targetLeft - bounding.left; 4369 } 4370 if (moveX || moveY) { 4371 if (top) { 4372 win.scrollBy(moveX, moveY); 4373 } 4374 else { 4375 let movedX = 0, movedY = 0; 4376 if (moveY) { 4377 let start = cur.scrollTop; 4378 cur.scrollTop += moveY; 4379 movedY = cur.scrollTop - start; 4380 } 4381 if (moveX) { 4382 let start = cur.scrollLeft; 4383 cur.scrollLeft += moveX; 4384 movedX = cur.scrollLeft - start; 4385 } 4386 rect = { left: rect.left - movedX, top: rect.top - movedY, 4387 right: rect.right - movedX, bottom: rect.bottom - movedY }; 4388 if (movedX && Math.abs(movedX - moveX) < 1) 4389 x = "nearest"; 4390 if (movedY && Math.abs(movedY - moveY) < 1) 4391 y = "nearest"; 4392 } 4393 } 4394 if (top) 4395 break; 4396 cur = cur.assignedSlot || cur.parentNode; 4397 } 4398 else if (cur.nodeType == 11) { // A shadow root 4399 cur = cur.host; 4400 } 4401 else { 4402 break; 4403 } 4404 } 4405} 4406class DOMSelectionState { 4407 constructor() { 4408 this.anchorNode = null; 4409 this.anchorOffset = 0; 4410 this.focusNode = null; 4411 this.focusOffset = 0; 4412 } 4413 eq(domSel) { 4414 return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset && 4415 this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset; 4416 } 4417 setRange(range) { 4418 this.set(range.anchorNode, range.anchorOffset, range.focusNode, range.focusOffset); 4419 } 4420 set(anchorNode, anchorOffset, focusNode, focusOffset) { 4421 this.anchorNode = anchorNode; 4422 this.anchorOffset = anchorOffset; 4423 this.focusNode = focusNode; 4424 this.focusOffset = focusOffset; 4425 } 4426} 4427let preventScrollSupported = null; 4428// Feature-detects support for .focus({preventScroll: true}), and uses 4429// a fallback kludge when not supported. 4430function focusPreventScroll(dom) { 4431 if (dom.setActive) 4432 return dom.setActive(); // in IE 4433 if (preventScrollSupported) 4434 return dom.focus(preventScrollSupported); 4435 let stack = []; 4436 for (let cur = dom; cur; cur = cur.parentNode) { 4437 stack.push(cur, cur.scrollTop, cur.scrollLeft); 4438 if (cur == cur.ownerDocument) 4439 break; 4440 } 4441 dom.focus(preventScrollSupported == null ? { 4442 get preventScroll() { 4443 preventScrollSupported = { preventScroll: true }; 4444 return true; 4445 } 4446 } : undefined); 4447 if (!preventScrollSupported) { 4448 preventScrollSupported = false;
vendor: 18,793 bytes, lines 4449-4957
4449 for (let i = 0; i < stack.length;) { 4450 let elt = stack[i++], top = stack[i++], left = stack[i++]; 4451 if (elt.scrollTop != top) 4452 elt.scrollTop = top; 4453 if (elt.scrollLeft != left) 4454 elt.scrollLeft = left; 4455 } 4456 } 4457} 4458let scratchRange; 4459function textRange(node, from, to = from) { 4460 let range = scratchRange || (scratchRange = document.createRange()); 4461 range.setEnd(node, to); 4462 range.setStart(node, from); 4463 return range; 4464} 4465function dispatchKey(elt, name, code) { 4466 let options = { key: name, code: name, keyCode: code, which: code, cancelable: true }; 4467 let down = new KeyboardEvent("keydown", options); 4468 down.synthetic = true; 4469 elt.dispatchEvent(down); 4470 let up = new KeyboardEvent("keyup", options); 4471 up.synthetic = true; 4472 elt.dispatchEvent(up); 4473 return down.defaultPrevented || up.defaultPrevented; 4474} 4475function getRoot(node) { 4476 while (node) { 4477 if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host)) 4478 return node; 4479 node = node.assignedSlot || node.parentNode; 4480 } 4481 return null; 4482} 4483function clearAttributes(node) { 4484 while (node.attributes.length) 4485 node.removeAttributeNode(node.attributes[0]); 4486} 4487function atElementStart(doc, selection) { 4488 let node = selection.focusNode, offset = selection.focusOffset; 4489 if (!node || selection.anchorNode != node || selection.anchorOffset != offset) 4490 return false; 4491 for (;;) { 4492 if (offset) { 4493 if (node.nodeType != 1) 4494 return false; 4495 let prev = node.childNodes[offset - 1]; 4496 if (prev.contentEditable == "false") 4497 offset--; 4498 else { 4499 node = prev; 4500 offset = maxOffset(node); 4501 } 4502 } 4503 else if (node == doc) { 4504 return true; 4505 } 4506 else { 4507 offset = domIndex(node); 4508 node = node.parentNode; 4509 } 4510 } 4511} 4512 4513class DOMPos { 4514 constructor(node, offset, precise = true) { 4515 this.node = node; 4516 this.offset = offset; 4517 this.precise = precise; 4518 } 4519 static before(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom), precise); } 4520 static after(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise); } 4521} 4522const noChildren = []; 4523class ContentView { 4524 constructor() { 4525 this.parent = null; 4526 this.dom = null; 4527 this.dirty = 2 /* Dirty.Node */; 4528 } 4529 get editorView() { 4530 if (!this.parent) 4531 throw new Error("Accessing view in orphan content view"); 4532 return this.parent.editorView; 4533 } 4534 get overrideDOMText() { return null; } 4535 get posAtStart() { 4536 return this.parent ? this.parent.posBefore(this) : 0; 4537 } 4538 get posAtEnd() { 4539 return this.posAtStart + this.length; 4540 } 4541 posBefore(view) { 4542 let pos = this.posAtStart; 4543 for (let child of this.children) { 4544 if (child == view) 4545 return pos; 4546 pos += child.length + child.breakAfter; 4547 } 4548 throw new RangeError("Invalid child in posBefore"); 4549 } 4550 posAfter(view) { 4551 return this.posBefore(view) + view.length; 4552 } 4553 // Will return a rectangle directly before (when side < 0), after 4554 // (side > 0) or directly on (when the browser supports it) the 4555 // given position. 4556 coordsAt(_pos, _side) { return null; } 4557 sync(track) { 4558 if (this.dirty & 2 /* Dirty.Node */) { 4559 let parent = this.dom; 4560 let prev = null, next; 4561 for (let child of this.children) { 4562 if (child.dirty) { 4563 if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) { 4564 let contentView = ContentView.get(next); 4565 if (!contentView || !contentView.parent && contentView.canReuseDOM(child)) 4566 child.reuseDOM(next); 4567 } 4568 child.sync(track); 4569 child.dirty = 0 /* Dirty.Not */; 4570 } 4571 next = prev ? prev.nextSibling : parent.firstChild; 4572 if (track && !track.written && track.node == parent && next != child.dom) 4573 track.written = true; 4574 if (child.dom.parentNode == parent) { 4575 while (next && next != child.dom) 4576 next = rm$1(next); 4577 } 4578 else { 4579 parent.insertBefore(child.dom, next); 4580 } 4581 prev = child.dom; 4582 } 4583 next = prev ? prev.nextSibling : parent.firstChild; 4584 if (next && track && track.node == parent) 4585 track.written = true; 4586 while (next) 4587 next = rm$1(next); 4588 } 4589 else if (this.dirty & 1 /* Dirty.Child */) { 4590 for (let child of this.children) 4591 if (child.dirty) { 4592 child.sync(track); 4593 child.dirty = 0 /* Dirty.Not */; 4594 } 4595 } 4596 } 4597 reuseDOM(_dom) { } 4598 localPosFromDOM(node, offset) { 4599 let after; 4600 if (node == this.dom) { 4601 after = this.dom.childNodes[offset]; 4602 } 4603 else { 4604 let bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1; 4605 for (;;) { 4606 let parent = node.parentNode; 4607 if (parent == this.dom) 4608 break; 4609 if (bias == 0 && parent.firstChild != parent.lastChild) { 4610 if (node == parent.firstChild) 4611 bias = -1; 4612 else 4613 bias = 1; 4614 } 4615 node = parent; 4616 } 4617 if (bias < 0) 4618 after = node; 4619 else 4620 after = node.nextSibling; 4621 } 4622 if (after == this.dom.firstChild) 4623 return 0; 4624 while (after && !ContentView.get(after)) 4625 after = after.nextSibling; 4626 if (!after) 4627 return this.length; 4628 for (let i = 0, pos = 0;; i++) { 4629 let child = this.children[i]; 4630 if (child.dom == after) 4631 return pos; 4632 pos += child.length + child.breakAfter; 4633 } 4634 } 4635 domBoundsAround(from, to, offset = 0) { 4636 let fromI = -1, fromStart = -1, toI = -1, toEnd = -1; 4637 for (let i = 0, pos = offset, prevEnd = offset; i < this.children.length; i++) { 4638 let child = this.children[i], end = pos + child.length; 4639 if (pos < from && end > to) 4640 return child.domBoundsAround(from, to, pos); 4641 if (end >= from && fromI == -1) { 4642 fromI = i; 4643 fromStart = pos; 4644 } 4645 if (pos > to && child.dom.parentNode == this.dom) { 4646 toI = i; 4647 toEnd = prevEnd; 4648 break; 4649 } 4650 prevEnd = end; 4651 pos = end + child.breakAfter; 4652 } 4653 return { from: fromStart, to: toEnd < 0 ? offset + this.length : toEnd, 4654 startDOM: (fromI ? this.children[fromI - 1].dom.nextSibling : null) || this.dom.firstChild, 4655 endDOM: toI < this.children.length && toI >= 0 ? this.children[toI].dom : null }; 4656 } 4657 markDirty(andParent = false) { 4658 this.dirty |= 2 /* Dirty.Node */; 4659 this.markParentsDirty(andParent); 4660 } 4661 markParentsDirty(childList) { 4662 for (let parent = this.parent; parent; parent = parent.parent) { 4663 if (childList) 4664 parent.dirty |= 2 /* Dirty.Node */; 4665 if (parent.dirty & 1 /* Dirty.Child */) 4666 return; 4667 parent.dirty |= 1 /* Dirty.Child */; 4668 childList = false; 4669 } 4670 } 4671 setParent(parent) { 4672 if (this.parent != parent) { 4673 this.parent = parent; 4674 if (this.dirty) 4675 this.markParentsDirty(true); 4676 } 4677 } 4678 setDOM(dom) { 4679 if (this.dom) 4680 this.dom.cmView = null; 4681 this.dom = dom; 4682 dom.cmView = this; 4683 } 4684 get rootView() { 4685 for (let v = this;;) { 4686 let parent = v.parent; 4687 if (!parent) 4688 return v; 4689 v = parent; 4690 } 4691 } 4692 replaceChildren(from, to, children = noChildren) { 4693 this.markDirty(); 4694 for (let i = from; i < to; i++) { 4695 let child = this.children[i]; 4696 if (child.parent == this) 4697 child.destroy(); 4698 } 4699 this.children.splice(from, to - from, ...children); 4700 for (let i = 0; i < children.length; i++) 4701 children[i].setParent(this); 4702 } 4703 ignoreMutation(_rec) { return false; } 4704 ignoreEvent(_event) { return false; } 4705 childCursor(pos = this.length) { 4706 return new ChildCursor(this.children, pos, this.children.length); 4707 } 4708 childPos(pos, bias = 1) { 4709 return this.childCursor().findPos(pos, bias); 4710 } 4711 toString() { 4712 let name = this.constructor.name.replace("View", ""); 4713 return name + (this.children.length ? "(" + this.children.join() + ")" : 4714 this.length ? "[" + (name == "Text" ? this.text : this.length) + "]" : "") + 4715 (this.breakAfter ? "#" : ""); 4716 } 4717 static get(node) { return node.cmView; } 4718 get isEditable() { return true; } 4719 merge(from, to, source, hasStart, openStart, openEnd) { 4720 return false; 4721 } 4722 become(other) { return false; } 4723 canReuseDOM(other) { return other.constructor == this.constructor; } 4724 // When this is a zero-length view with a side, this should return a 4725 // number <= 0 to indicate it is before its position, or a 4726 // number > 0 when after its position. 4727 getSide() { return 0; } 4728 destroy() { 4729 this.parent = null; 4730 } 4731} 4732ContentView.prototype.breakAfter = 0; 4733// Remove a DOM node and return its next sibling. 4734function rm$1(dom) { 4735 let next = dom.nextSibling; 4736 dom.parentNode.removeChild(dom); 4737 return next; 4738} 4739class ChildCursor { 4740 constructor(children, pos, i) { 4741 this.children = children; 4742 this.pos = pos; 4743 this.i = i; 4744 this.off = 0; 4745 } 4746 findPos(pos, bias = 1) { 4747 for (;;) { 4748 if (pos > this.pos || pos == this.pos && 4749 (bias > 0 || this.i == 0 || this.children[this.i - 1].breakAfter)) { 4750 this.off = pos - this.pos; 4751 return this; 4752 } 4753 let next = this.children[--this.i]; 4754 this.pos -= next.length + next.breakAfter; 4755 } 4756 } 4757} 4758function replaceRange(parent, fromI, fromOff, toI, toOff, insert, breakAtStart, openStart, openEnd) { 4759 let { children } = parent; 4760 let before = children.length ? children[fromI] : null; 4761 let last = insert.length ? insert[insert.length - 1] : null; 4762 let breakAtEnd = last ? last.breakAfter : breakAtStart; 4763 // Change within a single child 4764 if (fromI == toI && before && !breakAtStart && !breakAtEnd && insert.length < 2 && 4765 before.merge(fromOff, toOff, insert.length ? last : null, fromOff == 0, openStart, openEnd)) 4766 return; 4767 if (toI < children.length) { 4768 let after = children[toI]; 4769 // Make sure the end of the child after the update is preserved in `after` 4770 if (after && toOff < after.length) { 4771 // If we're splitting a child, separate part of it to avoid that 4772 // being mangled when updating the child before the update. 4773 if (fromI == toI) { 4774 after = after.split(toOff); 4775 toOff = 0; 4776 } 4777 // If the element after the replacement should be merged with 4778 // the last replacing element, update `content` 4779 if (!breakAtEnd && last && after.merge(0, toOff, last, true, 0, openEnd)) { 4780 insert[insert.length - 1] = after; 4781 } 4782 else { 4783 // Remove the start of the after element, if necessary, and 4784 // add it to `content`. 4785 if (toOff) 4786 after.merge(0, toOff, null, false, 0, openEnd); 4787 insert.push(after); 4788 } 4789 } 4790 else if (after === null || after === void 0 ? void 0 : after.breakAfter) { 4791 // The element at `toI` is entirely covered by this range. 4792 // Preserve its line break, if any. 4793 if (last) 4794 last.breakAfter = 1; 4795 else 4796 breakAtStart = 1; 4797 } 4798 // Since we've handled the next element from the current elements 4799 // now, make sure `toI` points after that. 4800 toI++; 4801 } 4802 if (before) { 4803 before.breakAfter = breakAtStart; 4804 if (fromOff > 0) { 4805 if (!breakAtStart && insert.length && before.merge(fromOff, before.length, insert[0], false, openStart, 0)) { 4806 before.breakAfter = insert.shift().breakAfter; 4807 } 4808 else if (fromOff < before.length || before.children.length && before.children[before.children.length - 1].length == 0) { 4809 before.merge(fromOff, before.length, null, false, openStart, 0); 4810 } 4811 fromI++; 4812 } 4813 } 4814 // Try to merge widgets on the boundaries of the replacement 4815 while (fromI < toI && insert.length) { 4816 if (children[toI - 1].become(insert[insert.length - 1])) { 4817 toI--; 4818 insert.pop(); 4819 openEnd = insert.length ? 0 : openStart; 4820 } 4821 else if (children[fromI].become(insert[0])) { 4822 fromI++; 4823 insert.shift(); 4824 openStart = insert.length ? 0 : openEnd; 4825 } 4826 else { 4827 break; 4828 } 4829 } 4830 if (!insert.length && fromI && toI < children.length && !children[fromI - 1].breakAfter && 4831 children[toI].merge(0, 0, children[fromI - 1], false, openStart, openEnd)) 4832 fromI--; 4833 if (fromI < toI || insert.length) 4834 parent.replaceChildren(fromI, toI, insert); 4835} 4836function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) { 4837 let cur = parent.childCursor(); 4838 let { i: toI, off: toOff } = cur.findPos(to, 1); 4839 let { i: fromI, off: fromOff } = cur.findPos(from, -1); 4840 let dLen = from - to; 4841 for (let view of insert) 4842 dLen += view.length; 4843 parent.length += dLen; 4844 replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd); 4845} 4846 4847let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" }; 4848let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } }; 4849const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent); 4850const ie_upto10 = /*@__PURE__*//MSIE \d/.test(nav.userAgent); 4851const ie_11up = /*@__PURE__*//Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent); 4852const ie = !!(ie_upto10 || ie_11up || ie_edge); 4853const gecko = !ie && /*@__PURE__*//gecko\/(\d+)/i.test(nav.userAgent); 4854const chrome = !ie && /*@__PURE__*//Chrome\/(\d+)/.exec(nav.userAgent); 4855const webkit = "webkitFontSmoothing" in doc.documentElement.style; 4856const safari = !ie && /*@__PURE__*//Apple Computer/.test(nav.vendor); 4857const ios = safari && (/*@__PURE__*//Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2); 4858var browser = { 4859 mac: ios || /*@__PURE__*//Mac/.test(nav.platform), 4860 windows: /*@__PURE__*//Win/.test(nav.platform), 4861 linux: /*@__PURE__*//Linux|X11/.test(nav.platform), 4862 ie, 4863 ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0, 4864 gecko, 4865 gecko_version: gecko ? +(/*@__PURE__*//Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0, 4866 chrome: !!chrome, 4867 chrome_version: chrome ? +chrome[1] : 0, 4868 ios, 4869 android: /*@__PURE__*//Android\b/.test(nav.userAgent), 4870 webkit, 4871 safari, 4872 webkit_version: webkit ? +(/*@__PURE__*//\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0, 4873 tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size" 4874}; 4875 4876const MaxJoinLen = 256; 4877class TextView extends ContentView { 4878 constructor(text) { 4879 super(); 4880 this.text = text; 4881 } 4882 get length() { return this.text.length; } 4883 createDOM(textDOM) { 4884 this.setDOM(textDOM || document.createTextNode(this.text)); 4885 } 4886 sync(track) { 4887 if (!this.dom) 4888 this.createDOM(); 4889 if (this.dom.nodeValue != this.text) { 4890 if (track && track.node == this.dom) 4891 track.written = true; 4892 this.dom.nodeValue = this.text; 4893 } 4894 } 4895 reuseDOM(dom) { 4896 if (dom.nodeType == 3) 4897 this.createDOM(dom); 4898 } 4899 merge(from, to, source) { 4900 if (source && (!(source instanceof TextView) || this.length - (to - from) + source.length > MaxJoinLen)) 4901 return false; 4902 this.text = this.text.slice(0, from) + (source ? source.text : "") + this.text.slice(to); 4903 this.markDirty(); 4904 return true; 4905 } 4906 split(from) { 4907 let result = new TextView(this.text.slice(from)); 4908 this.text = this.text.slice(0, from); 4909 this.markDirty(); 4910 return result; 4911 } 4912 localPosFromDOM(node, offset) { 4913 return node == this.dom ? offset : offset ? this.text.length : 0; 4914 } 4915 domAtPos(pos) { return new DOMPos(this.dom, pos); } 4916 domBoundsAround(_from, _to, offset) { 4917 return { from: offset, to: offset + this.length, startDOM: this.dom, endDOM: this.dom.nextSibling }; 4918 } 4919 coordsAt(pos, side) { 4920 return textCoords(this.dom, pos, side); 4921 } 4922} 4923class MarkView extends ContentView { 4924 constructor(mark, children = [], length = 0) { 4925 super(); 4926 this.mark = mark; 4927 this.children = children; 4928 this.length = length; 4929 for (let ch of children) 4930 ch.setParent(this); 4931 } 4932 setAttrs(dom) { 4933 clearAttributes(dom); 4934 if (this.mark.class) 4935 dom.className = this.mark.class; 4936 if (this.mark.attrs) 4937 for (let name in this.mark.attrs) 4938 dom.setAttribute(name, this.mark.attrs[name]); 4939 return dom; 4940 } 4941 reuseDOM(node) { 4942 if (node.nodeName == this.mark.tagName.toUpperCase()) { 4943 this.setDOM(node); 4944 this.dirty |= 4 /* Dirty.Attrs */ | 2 /* Dirty.Node */; 4945 } 4946 } 4947 sync(track) { 4948 if (!this.dom) 4949 this.setDOM(this.setAttrs(document.createElement(this.mark.tagName))); 4950 else if (this.dirty & 4 /* Dirty.Attrs */) 4951 this.setAttrs(this.dom); 4952 super.sync(track); 4953 } 4954 merge(from, to, source, _hasStart, openStart, openEnd) { 4955 if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) || 4956 (from && openStart <= 0) || (to < this.length && openEnd <= 0))) 4957 return false;
4958 mergeChildrenInto(this, from, to, source ? source.children : [], openStart - 1, openEnd - 1); 4959 this.markDirty(); 4960 return true; 4961 } 4962 split(from) { 4963 let result = [], off = 0, detachFrom = -1, i = 0; 4964 for (let elt of this.children) { 4965 let end = off + elt.length; 4966 if (end > from) 4967 result.push(off < from ? elt.split(from - off) : elt); 4968 if (detachFrom < 0 && off >= from) 4969 detachFrom = i; 4970 off = end; 4971 i++; 4972 } 4973 let length = this.length - from; 4974 this.length = from; 4975 if (detachFrom > -1) { 4976 this.children.length = detachFrom; 4977 this.markDirty(); 4978 } 4979 return new MarkView(this.mark, result, length); 4980 } 4981 domAtPos(pos) { 4982 return inlineDOMAtPos(this, pos); 4983 } 4984 coordsAt(pos, side) { 4985 return coordsInChildren(this, pos, side); 4986 } 4987} 4988function textCoords(text, pos, side) { 4989 let length = text.nodeValue.length; 4990 if (pos > length) 4991 pos = length; 4992 let from = pos, to = pos, flatten = 0; 4993 if (pos == 0 && side < 0 || pos == length && side >= 0) { 4994 if (!(browser.chrome || browser.gecko)) { // These browsers reliably return valid rectangles for empty ranges 4995 if (pos) { 4996 from--; 4997 flatten = 1; 4998 } // FIXME this is wrong in RTL text 4999 else if (to < length) { 5000 to++; 5001 flatten = -1; 5002 } 5003 } 5004 } 5005 else { 5006 if (side < 0) 5007 from--; 5008 else if (to < length) 5009 to++; 5010 } 5011 let rects = textRange(text, from, to).getClientRects(); 5012 if (!rects.length) 5013 return Rect0; 5014 let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1]; 5015 if (browser.safari && !flatten && rect.width == 0) 5016 rect = Array.prototype.find.call(rects, r => r.width) || rect; 5017 return flatten ? flattenRect(rect, flatten < 0) : rect || null; 5018} 5019// Also used for collapsed ranges that don't have a placeholder widget! 5020class WidgetView extends ContentView { 5021 constructor(widget, length, side) { 5022 super(); 5023 this.widget = widget; 5024 this.length = length; 5025 this.side = side; 5026 this.prevWidget = null; 5027 } 5028 static create(widget, length, side) { 5029 return new (widget.customView || WidgetView)(widget, length, side); 5030 } 5031 split(from) { 5032 let result = WidgetView.create(this.widget, this.length - from, this.side); 5033 this.length -= from; 5034 return result; 5035 } 5036 sync() { 5037 if (!this.dom || !this.widget.updateDOM(this.dom)) { 5038 if (this.dom && this.prevWidget) 5039 this.prevWidget.destroy(this.dom); 5040 this.prevWidget = null; 5041 this.setDOM(this.widget.toDOM(this.editorView)); 5042 this.dom.contentEditable = "false"; 5043 } 5044 } 5045 getSide() { return this.side; } 5046 merge(from, to, source, hasStart, openStart, openEnd) { 5047 if (source && (!(source instanceof WidgetView) || !this.widget.compare(source.widget) || 5048 from > 0 && openStart <= 0 || to < this.length && openEnd <= 0)) 5049 return false; 5050 this.length = from + (source ? source.length : 0) + (this.length - to); 5051 return true; 5052 } 5053 become(other) { 5054 if (other.length == this.length && other instanceof WidgetView && other.side == this.side) { 5055 if (this.widget.constructor == other.widget.constructor) { 5056 if (!this.widget.eq(other.widget)) 5057 this.markDirty(true); 5058 if (this.dom && !this.prevWidget) 5059 this.prevWidget = this.widget; 5060 this.widget = other.widget; 5061 return true; 5062 } 5063 } 5064 return false; 5065 } 5066 ignoreMutation() { return true; } 5067 ignoreEvent(event) { return this.widget.ignoreEvent(event); } 5068 get overrideDOMText() { 5069 if (this.length == 0) 5070 return Text.empty; 5071 let top = this; 5072 while (top.parent) 5073 top = top.parent; 5074 let view = top.editorView, text = view && view.state.doc, start = this.posAtStart; 5075 return text ? text.slice(start, start + this.length) : Text.empty; 5076 } 5077 domAtPos(pos) { 5078 return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length); 5079 } 5080 domBoundsAround() { return null; } 5081 coordsAt(pos, side) { 5082 let rects = this.dom.getClientRects(), rect = null; 5083 if (!rects.length) 5084 return Rect0; 5085 for (let i = pos > 0 ? rects.length - 1 : 0;; i += (pos > 0 ? -1 : 1)) { 5086 rect = rects[i]; 5087 if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom) 5088 break; 5089 } 5090 return this.length ? rect : flattenRect(rect, this.side > 0); 5091 } 5092 get isEditable() { return false; } 5093 destroy() { 5094 super.destroy(); 5095 if (this.dom) 5096 this.widget.destroy(this.dom); 5097 } 5098} 5099class CompositionView extends WidgetView { 5100 domAtPos(pos) { 5101 let { topView, text } = this.widget; 5102 if (!topView) 5103 return new DOMPos(text, Math.min(pos, text.nodeValue.length)); 5104 return scanCompositionTree(pos, 0, topView, text, (v, p) => v.domAtPos(p), p => new DOMPos(text, Math.min(p, text.nodeValue.length))); 5105 } 5106 sync() { this.setDOM(this.widget.toDOM()); } 5107 localPosFromDOM(node, offset) { 5108 let { topView, text } = this.widget; 5109 if (!topView) 5110 return Math.min(offset, this.length); 5111 return posFromDOMInCompositionTree(node, offset, topView, text); 5112 } 5113 ignoreMutation() { return false; } 5114 get overrideDOMText() { return null; } 5115 coordsAt(pos, side) { 5116 let { topView, text } = this.widget; 5117 if (!topView) 5118 return textCoords(text, pos, side); 5119 return scanCompositionTree(pos, side, topView, text, (v, pos, side) => v.coordsAt(pos, side), (pos, side) => textCoords(text, pos, side)); 5120 } 5121 destroy() { 5122 var _a; 5123 super.destroy(); 5124 (_a = this.widget.topView) === null || _a === void 0 ? void 0 : _a.destroy(); 5125 } 5126 get isEditable() { return true; } 5127 canReuseDOM() { return true; } 5128} 5129// Uses the old structure of a chunk of content view frozen for 5130// composition to try and find a reasonable DOM location for the given 5131// offset.
5132function scanCompositionTree(pos, side, view, text, enterView, fromText) { 5133 if (view instanceof MarkView) { 5134 for (let child = view.dom.firstChild; child; child = child.nextSibling) { 5135 let desc = ContentView.get(child); 5136 if (!desc) 5137 return fromText(pos, side); 5138 let hasComp = contains(child, text); 5139 let len = desc.length + (hasComp ? text.nodeValue.length : 0); 5140 if (pos < len || pos == len && desc.getSide() <= 0) 5141 return hasComp ? scanCompositionTree(pos, side, desc, text, enterView, fromText) : enterView(desc, pos, side); 5142 pos -= len; 5143 } 5144 return enterView(view, view.length, -1); 5145 } 5146 else if (view.dom == text) { 5147 return fromText(pos, side); 5148 } 5149 else { 5150 return enterView(view, pos, side); 5151 } 5152} 5153function posFromDOMInCompositionTree(node, offset, view, text) { 5154 if (view instanceof MarkView) { 5155 for (let child of view.children) { 5156 let pos = 0, hasComp = contains(child.dom, text); 5157 if (contains(child.dom, node)) 5158 return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, child, text) : child.localPosFromDOM(node, offset)); 5159 pos += hasComp ? text.nodeValue.length : child.length; 5160 } 5161 } 5162 else if (view.dom == text) { 5163 return Math.min(offset, text.nodeValue.length); 5164 } 5165 return view.localPosFromDOM(node, offset); 5166} 5167// These are drawn around uneditable widgets to avoid a number of 5168// browser bugs that show up when the cursor is directly next to 5169// uneditable inline content. 5170class WidgetBufferView extends ContentView { 5171 constructor(side) { 5172 super(); 5173 this.side = side; 5174 } 5175 get length() { return 0; } 5176 merge() { return false; } 5177 become(other) { 5178 return other instanceof WidgetBufferView && other.side == this.side; 5179 } 5180 split() { return new WidgetBufferView(this.side); } 5181 sync() { 5182 if (!this.dom) { 5183 let dom = document.createElement("img"); 5184 dom.className = "cm-widgetBuffer"; 5185 dom.setAttribute("aria-hidden", "true"); 5186 this.setDOM(dom); 5187 } 5188 } 5189 getSide() { return this.side; } 5190 domAtPos(pos) { return DOMPos.before(this.dom); } 5191 localPosFromDOM() { return 0; } 5192 domBoundsAround() { return null; } 5193 coordsAt(pos) { 5194 let imgRect = this.dom.getBoundingClientRect(); 5195 // Since the <img> height doesn't correspond to text height, try 5196 // to borrow the height from some sibling node. 5197 let siblingRect = inlineSiblingRect(this, this.side > 0 ? -1 : 1); 5198 return siblingRect && siblingRect.top < imgRect.bottom && siblingRect.bottom > imgRect.top 5199 ? { left: imgRect.left, right: imgRect.right, top: siblingRect.top, bottom: siblingRect.bottom } : imgRect; 5200 } 5201 get overrideDOMText() { 5202 return Text.empty; 5203 } 5204} 5205TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren; 5206function inlineSiblingRect(view, side) { 5207 let parent = view.parent, index = parent ? parent.children.indexOf(view) : -1; 5208 while (parent && index >= 0) { 5209 if (side < 0 ? index > 0 : index < parent.children.length) { 5210 let next = parent.children[index + side]; 5211 if (next instanceof TextView) { 5212 let nextRect = next.coordsAt(side < 0 ? next.length : 0, side); 5213 if (nextRect) 5214 return nextRect; 5215 } 5216 index += side; 5217 } 5218 else if (parent instanceof MarkView && parent.parent) { 5219 index = parent.parent.children.indexOf(parent) + (side < 0 ? 0 : 1); 5220 parent = parent.parent; 5221 } 5222 else { 5223 let last = parent.dom.lastChild; 5224 if (last && last.nodeName == "BR") 5225 return last.getClientRects()[0]; 5226 break; 5227 } 5228 } 5229 return undefined; 5230} 5231function inlineDOMAtPos(parent, pos) { 5232 let dom = parent.dom, { children } = parent, i = 0; 5233 for (let off = 0; i < children.length; i++) { 5234 let child = children[i], end = off + child.length;
5235 if (end == off && child.getSide() <= 0) 5236 continue; 5237 if (pos > off && pos < end && child.dom.parentNode == dom) 5238 return child.domAtPos(pos - off); 5239 if (pos <= off) 5240 break; 5241 off = end; 5242 } 5243 for (let j = i; j > 0; j--) { 5244 let prev = children[j - 1]; 5245 if (prev.dom.parentNode == dom) 5246 return prev.domAtPos(prev.length); 5247 } 5248 for (let j = i; j < children.length; j++) { 5249 let next = children[j]; 5250 if (next.dom.parentNode == dom) 5251 return next.domAtPos(0); 5252 } 5253 return new DOMPos(dom, 0); 5254} 5255// Assumes `view`, if a mark view, has precisely 1 child. 5256function joinInlineInto(parent, view, open) { 5257 let last, { children } = parent; 5258 if (open > 0 && view instanceof MarkView && children.length && 5259 (last = children[children.length - 1]) instanceof MarkView && last.mark.eq(view.mark)) { 5260 joinInlineInto(last, view.children[0], open - 1); 5261 } 5262 else { 5263 children.push(view); 5264 view.setParent(parent); 5265 } 5266 parent.length += view.length; 5267} 5268function coordsInChildren(view, pos, side) { 5269 let before = null, beforePos = -1, after = null, afterPos = -1; 5270 function scan(view, pos) { 5271 for (let i = 0, off = 0; i < view.children.length && off <= pos; i++) { 5272 let child = view.children[i], end = off + child.length; 5273 if (end >= pos) { 5274 if (child.children.length) { 5275 scan(child, pos - off); 5276 } 5277 else if (!after && (end > pos || off == end && child.getSide() > 0)) { 5278 after = child; 5279 afterPos = pos - off; 5280 } 5281 else if (off < pos || (off == end && child.getSide() < 0)) { 5282 before = child; 5283 beforePos = pos - off; 5284 } 5285 } 5286 off = end; 5287 } 5288 } 5289 scan(view, pos); 5290 let target = (side < 0 ? before : after) || before || after; 5291 if (target) 5292 return target.coordsAt(Math.max(0, target == before ? beforePos : afterPos), side); 5293 return fallbackRect(view); 5294} 5295function fallbackRect(view) { 5296 let last = view.dom.lastChild; 5297 if (!last) 5298 return view.dom.getBoundingClientRect(); 5299 let rects = clientRectsFor(last); 5300 return rects[rects.length - 1] || null; 5301} 5302 5303function combineAttrs(source, target) { 5304 for (let name in source) { 5305 if (name == "class" && target.class) 5306 target.class += " " + source.class; 5307 else if (name == "style" && target.style) 5308 target.style += ";" + source.style; 5309 else 5310 target[name] = source[name]; 5311 } 5312 return target; 5313} 5314function attrsEq(a, b) { 5315 if (a == b) 5316 return true; 5317 if (!a || !b) 5318 return false; 5319 let keysA = Object.keys(a), keysB = Object.keys(b); 5320 if (keysA.length != keysB.length) 5321 return false; 5322 for (let key of keysA) { 5323 if (keysB.indexOf(key) == -1 || a[key] !== b[key]) 5324 return false; 5325 } 5326 return true; 5327} 5328function updateAttrs(dom, prev, attrs) {
5329 let changed = null; 5330 if (prev) 5331 for (let name in prev) 5332 if (!(attrs && name in attrs)) 5333 dom.removeAttribute(changed = name); 5334 if (attrs) 5335 for (let name in attrs) 5336 if (!(prev && prev[name] == attrs[name])) 5337 dom.setAttribute(changed = name, attrs[name]); 5338 return !!changed; 5339} 5340 5341/** 5342Widgets added to the content are described by subclasses of this 5343class. Using a description object like that makes it possible to 5344delay creating of the DOM structure for a widget until it is 5345needed, and to avoid redrawing widgets even if the decorations 5346that define them are recreated. 5347*/ 5348class WidgetType { 5349 /** 5350 Compare this instance to another instance of the same type. 5351 (TypeScript can't express this, but only instances of the same 5352 specific class will be passed to this method.) This is used to 5353 avoid redrawing widgets when they are replaced by a new 5354 decoration of the same type. The default implementation just 5355 returns `false`, which will cause new instances of the widget to 5356 always be redrawn. 5357 */ 5358 eq(widget) { return false; } 5359 /** 5360 Update a DOM element created by a widget of the same type (but 5361 different, non-`eq` content) to reflect this widget. May return 5362 true to indicate that it could update, false to indicate it 5363 couldn't (in which case the widget will be redrawn). The default 5364 implementation just returns false. 5365 */ 5366 updateDOM(dom) { return false; } 5367 /** 5368 @internal 5369 */ 5370 compare(other) { 5371 return this == other || this.constructor == other.constructor && this.eq(other); 5372 } 5373 /** 5374 The estimated height this widget will have, to be used when 5375 estimating the height of content that hasn't been drawn. May 5376 return -1 to indicate you don't know. The default implementation 5377 returns -1. 5378 */ 5379 get estimatedHeight() { return -1; } 5380 /** 5381 Can be used to configure which kinds of events inside the widget 5382 should be ignored by the editor. The default is to ignore all 5383 events. 5384 */ 5385 ignoreEvent(event) { return true; } 5386 /** 5387 @internal 5388 */ 5389 get customView() { return null; } 5390 /** 5391 This is called when the an instance of the widget is removed 5392 from the editor view. 5393 */ 5394 destroy(dom) { } 5395} 5396/** 5397The different types of blocks that can occur in an editor view. 5398*/ 5399var BlockType = /*@__PURE__*/(function (BlockType) { 5400 /** 5401 A line of text. 5402 */ 5403 BlockType[BlockType["Text"] = 0] = "Text"; 5404 /** 5405 A block widget associated with the position after it. 5406 */ 5407 BlockType[BlockType["WidgetBefore"] = 1] = "WidgetBefore"; 5408 /** 5409 A block widget associated with the position before it. 5410 */ 5411 BlockType[BlockType["WidgetAfter"] = 2] = "WidgetAfter"; 5412 /** 5413 A block widget [replacing](https://codemirror.net/6/docs/ref/#view.Decoration^replace) a range of content. 5414 */ 5415 BlockType[BlockType["WidgetRange"] = 3] = "WidgetRange"; 5416return BlockType})(BlockType || (BlockType = {})); 5417/** 5418A decoration provides information on how to draw or style a piece 5419of content. You'll usually use it wrapped in a 5420[`Range`](https://codemirror.net/6/docs/ref/#state.Range), which adds a start and end position. 5421@nonabstract 5422*/ 5423class Decoration extends RangeValue { 5424 constructor( 5425 /** 5426 @internal 5427 */ 5428 startSide, 5429 /** 5430 @internal 5431 */ 5432 endSide, 5433 /** 5434 @internal 5435 */ 5436 widget, 5437 /** 5438 The config object used to create this decoration. You can 5439 include additional properties in there to store metadata about 5440 your decoration. 5441 */ 5442 spec) { 5443 super(); 5444 this.startSide = startSide; 5445 this.endSide = endSide; 5446 this.widget = widget; 5447 this.spec = spec; 5448 } 5449 /** 5450 @internal 5451 */ 5452 get heightRelevant() { return false; } 5453 /** 5454 Create a mark decoration, which influences the styling of the 5455 content in its range. Nested mark decorations will cause nested 5456 DOM elements to be created. Nesting order is determined by 5457 precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), with 5458 the higher-precedence decorations creating the inner DOM nodes. 5459 Such elements are split on line boundaries and on the boundaries 5460 of lower-precedence decorations. 5461 */ 5462 static mark(spec) { 5463 return new MarkDecoration(spec); 5464 } 5465 /** 5466 Create a widget decoration, which displays a DOM element at the 5467 given position. 5468 */ 5469 static widget(spec) { 5470 let side = spec.side || 0, block = !!spec.block; 5471 side += block ? (side > 0 ? 300000000 /* Side.BlockAfter */ : -400000000 /* Side.BlockBefore */) : (side > 0 ? 100000000 /* Side.InlineAfter */ : -100000000 /* Side.InlineBefore */); 5472 return new PointDecoration(spec, side, side, block, spec.widget || null, false); 5473 } 5474 /** 5475 Create a replace decoration which replaces the given range with 5476 a widget, or simply hides it. 5477 */ 5478 static replace(spec) { 5479 let block = !!spec.block, startSide, endSide; 5480 if (spec.isBlockGap) { 5481 startSide = -500000000 /* Side.GapStart */; 5482 endSide = 400000000 /* Side.GapEnd */; 5483 } 5484 else { 5485 let { start, end } = getInclusive(spec, block); 5486 startSide = (start ? (block ? -300000000 /* Side.BlockIncStart */ : -1 /* Side.InlineIncStart */) : 500000000 /* Side.NonIncStart */) - 1; 5487 endSide = (end ? (block ? 200000000 /* Side.BlockIncEnd */ : 1 /* Side.InlineIncEnd */) : -600000000 /* Side.NonIncEnd */) + 1; 5488 } 5489 return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true); 5490 } 5491 /** 5492 Create a line decoration, which can add DOM attributes to the 5493 line starting at the given position. 5494 */ 5495 static line(spec) { 5496 return new LineDecoration(spec); 5497 } 5498 /** 5499 Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given 5500 decorated range or ranges. If the ranges aren't already sorted, 5501 pass `true` for `sort` to make the library sort them for you. 5502 */ 5503 static set(of, sort = false) { 5504 return RangeSet.of(of, sort); 5505 } 5506 /** 5507 @internal 5508 */ 5509 hasHeight() { return this.widget ? this.widget.estimatedHeight > -1 : false; } 5510} 5511/** 5512The empty set of decorations. 5513*/ 5514Decoration.none = RangeSet.empty; 5515class MarkDecoration extends Decoration { 5516 constructor(spec) { 5517 let { start, end } = getInclusive(spec); 5518 super(start ? -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */, end ? 1 /* Side.InlineIncEnd */ : -600000000 /* Side.NonIncEnd */, null, spec); 5519 this.tagName = spec.tagName || "span"; 5520 this.class = spec.class || ""; 5521 this.attrs = spec.attributes || null; 5522 } 5523 eq(other) { 5524 return this == other || 5525 other instanceof MarkDecoration && 5526 this.tagName == other.tagName && 5527 this.class == other.class && 5528 attrsEq(this.attrs, other.attrs); 5529 } 5530 range(from, to = from) { 5531 if (from >= to) 5532 throw new RangeError("Mark decorations may not be empty"); 5533 return super.range(from, to); 5534 } 5535} 5536MarkDecoration.prototype.point = false;
5537class LineDecoration extends Decoration { 5538 constructor(spec) { 5539 super(-200000000 /* Side.Line */, -200000000 /* Side.Line */, null, spec); 5540 } 5541 eq(other) { 5542 return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes); 5543 } 5544 range(from, to = from) { 5545 if (to != from) 5546 throw new RangeError("Line decoration ranges must be zero-length"); 5547 return super.range(from, to); 5548 } 5549} 5550LineDecoration.prototype.mapMode = MapMode.TrackBefore; 5551LineDecoration.prototype.point = true; 5552class PointDecoration extends Decoration { 5553 constructor(spec, startSide, endSide, block, widget, isReplace) { 5554 super(startSide, endSide, widget, spec); 5555 this.block = block; 5556 this.isReplace = isReplace; 5557 this.mapMode = !block ? MapMode.TrackDel : startSide <= 0 ? MapMode.TrackBefore : MapMode.TrackAfter; 5558 } 5559 // Only relevant when this.block == true 5560 get type() { 5561 return this.startSide < this.endSide ? BlockType.WidgetRange 5562 : this.startSide <= 0 ? BlockType.WidgetBefore : BlockType.WidgetAfter; 5563 } 5564 get heightRelevant() { return this.block || !!this.widget && this.widget.estimatedHeight >= 5; } 5565 eq(other) { 5566 return other instanceof PointDecoration && 5567 widgetsEq(this.widget, other.widget) && 5568 this.block == other.block && 5569 this.startSide == other.startSide && this.endSide == other.endSide; 5570 } 5571 range(from, to = from) { 5572 if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0))) 5573 throw new RangeError("Invalid range for replacement decoration"); 5574 if (!this.isReplace && to != from) 5575 throw new RangeError("Widget decorations can only have zero-length ranges"); 5576 return super.range(from, to); 5577 } 5578} 5579PointDecoration.prototype.point = true; 5580function getInclusive(spec, block = false) { 5581 let { inclusiveStart: start, inclusiveEnd: end } = spec; 5582 if (start == null) 5583 start = spec.inclusive; 5584 if (end == null) 5585 end = spec.inclusive; 5586 return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block }; 5587} 5588function widgetsEq(a, b) { 5589 return a == b || !!(a && b && a.compare(b)); 5590} 5591function addRange(from, to, ranges, margin = 0) { 5592 let last = ranges.length - 1; 5593 if (last >= 0 && ranges[last] + margin >= from) 5594 ranges[last] = Math.max(ranges[last], to); 5595 else 5596 ranges.push(from, to); 5597} 5598 5599class LineView extends ContentView { 5600 constructor() { 5601 super(...arguments); 5602 this.children = []; 5603 this.length = 0; 5604 this.prevAttrs = undefined; 5605 this.attrs = null; 5606 this.breakAfter = 0; 5607 } 5608 // Consumes source 5609 merge(from, to, source, hasStart, openStart, openEnd) { 5610 if (source) { 5611 if (!(source instanceof LineView)) 5612 return false; 5613 if (!this.dom) 5614 source.transferDOM(this); // Reuse source.dom when appropriate 5615 } 5616 if (hasStart) 5617 this.setDeco(source ? source.attrs : null); 5618 mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd); 5619 return true; 5620 } 5621 split(at) { 5622 let end = new LineView; 5623 end.breakAfter = this.breakAfter; 5624 if (this.length == 0) 5625 return end; 5626 let { i, off } = this.childPos(at); 5627 if (off) { 5628 end.append(this.children[i].split(off), 0); 5629 this.children[i].merge(off, this.children[i].length, null, false, 0, 0); 5630 i++; 5631 } 5632 for (let j = i; j < this.children.length; j++) 5633 end.append(this.children[j], 0); 5634 while (i > 0 && this.children[i - 1].length == 0) 5635 this.children[--i].destroy(); 5636 this.children.length = i; 5637 this.markDirty(); 5638 this.length = at; 5639 return end; 5640 } 5641 transferDOM(other) { 5642 if (!this.dom) 5643 return; 5644 this.markDirty(); 5645 other.setDOM(this.dom); 5646 other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs; 5647 this.prevAttrs = undefined; 5648 this.dom = null; 5649 } 5650 setDeco(attrs) { 5651 if (!attrsEq(this.attrs, attrs)) { 5652 if (this.dom) { 5653 this.prevAttrs = this.attrs; 5654 this.markDirty(); 5655 } 5656 this.attrs = attrs; 5657 } 5658 } 5659 append(child, openStart) { 5660 joinInlineInto(this, child, openStart); 5661 } 5662 // Only called when building a line view in ContentBuilder 5663 addLineDeco(deco) { 5664 let attrs = deco.spec.attributes, cls = deco.spec.class; 5665 if (attrs) 5666 this.attrs = combineAttrs(attrs, this.attrs || {}); 5667 if (cls) 5668 this.attrs = combineAttrs({ class: cls }, this.attrs || {}); 5669 } 5670 domAtPos(pos) { 5671 return inlineDOMAtPos(this, pos); 5672 } 5673 reuseDOM(node) { 5674 if (node.nodeName == "DIV") { 5675 this.setDOM(node); 5676 this.dirty |= 4 /* Dirty.Attrs */ | 2 /* Dirty.Node */; 5677 } 5678 } 5679 sync(track) { 5680 var _a; 5681 if (!this.dom) { 5682 this.setDOM(document.createElement("div")); 5683 this.dom.className = "cm-line"; 5684 this.prevAttrs = this.attrs ? null : undefined; 5685 } 5686 else if (this.dirty & 4 /* Dirty.Attrs */) { 5687 clearAttributes(this.dom); 5688 this.dom.className = "cm-line"; 5689 this.prevAttrs = this.attrs ? null : undefined; 5690 } 5691 if (this.prevAttrs !== undefined) { 5692 updateAttrs(this.dom, this.prevAttrs, this.attrs); 5693 this.dom.classList.add("cm-line"); 5694 this.prevAttrs = undefined; 5695 } 5696 super.sync(track); 5697 let last = this.dom.lastChild; 5698 while (last && ContentView.get(last) instanceof MarkView) 5699 last = last.lastChild; 5700 if (!last || !this.length || 5701 last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false && 5702 (!browser.ios || !this.children.some(ch => ch instanceof TextView))) { 5703 let hack = document.createElement("BR"); 5704 hack.cmIgnore = true; 5705 this.dom.appendChild(hack); 5706 } 5707 } 5708 measureTextSize() { 5709 if (this.children.length == 0 || this.length > 20) 5710 return null; 5711 let totalWidth = 0; 5712 for (let child of this.children) { 5713 if (!(child instanceof TextView) || /[^ -~]/.test(child.text)) 5714 return null; 5715 let rects = clientRectsFor(child.dom); 5716 if (rects.length != 1) 5717 return null; 5718 totalWidth += rects[0].width; 5719 } 5720 return !totalWidth ? null : { 5721 lineHeight: this.dom.getBoundingClientRect().height, 5722 charWidth: totalWidth / this.length 5723 }; 5724 } 5725 coordsAt(pos, side) { 5726 return coordsInChildren(this, pos, side); 5727 } 5728 become(_other) { return false; }
5729 get type() { return BlockType.Text; } 5730 static find(docView, pos) { 5731 for (let i = 0, off = 0; i < docView.children.length; i++) { 5732 let block = docView.children[i], end = off + block.length; 5733 if (end >= pos) { 5734 if (block instanceof LineView) 5735 return block; 5736 if (end > pos) 5737 break; 5738 } 5739 off = end + block.breakAfter; 5740 } 5741 return null; 5742 } 5743} 5744class BlockWidgetView extends ContentView { 5745 constructor(widget, length, type) { 5746 super(); 5747 this.widget = widget; 5748 this.length = length; 5749 this.type = type; 5750 this.breakAfter = 0; 5751 this.prevWidget = null; 5752 } 5753 merge(from, to, source, _takeDeco, openStart, openEnd) { 5754 if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) || 5755 from > 0 && openStart <= 0 || to < this.length && openEnd <= 0)) 5756 return false; 5757 this.length = from + (source ? source.length : 0) + (this.length - to); 5758 return true; 5759 } 5760 domAtPos(pos) { 5761 return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length); 5762 } 5763 split(at) { 5764 let len = this.length - at; 5765 this.length = at; 5766 let end = new BlockWidgetView(this.widget, len, this.type); 5767 end.breakAfter = this.breakAfter; 5768 return end; 5769 } 5770 get children() { return noChildren; } 5771 sync() { 5772 if (!this.dom || !this.widget.updateDOM(this.dom)) { 5773 if (this.dom && this.prevWidget) 5774 this.prevWidget.destroy(this.dom); 5775 this.prevWidget = null; 5776 this.setDOM(this.widget.toDOM(this.editorView)); 5777 this.dom.contentEditable = "false"; 5778 } 5779 } 5780 get overrideDOMText() { 5781 return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : Text.empty; 5782 } 5783 domBoundsAround() { return null; } 5784 become(other) { 5785 if (other instanceof BlockWidgetView && other.type == this.type && 5786 other.widget.constructor == this.widget.constructor) { 5787 if (!other.widget.eq(this.widget)) 5788 this.markDirty(true); 5789 if (this.dom && !this.prevWidget) 5790 this.prevWidget = this.widget; 5791 this.widget = other.widget; 5792 this.length = other.length; 5793 this.breakAfter = other.breakAfter; 5794 return true; 5795 } 5796 return false; 5797 } 5798 ignoreMutation() { return true; } 5799 ignoreEvent(event) { return this.widget.ignoreEvent(event); } 5800 destroy() { 5801 super.destroy(); 5802 if (this.dom) 5803 this.widget.destroy(this.dom); 5804 } 5805} 5806 5807class ContentBuilder { 5808 constructor(doc, pos, end, disallowBlockEffectsFor) { 5809 this.doc = doc; 5810 this.pos = pos; 5811 this.end = end; 5812 this.disallowBlockEffectsFor = disallowBlockEffectsFor; 5813 this.content = []; 5814 this.curLine = null; 5815 this.breakAtStart = 0; 5816 this.pendingBuffer = 0 /* Buf.No */; 5817 // Set to false directly after a widget that covers the position after it
5818 this.atCursorPos = true; 5819 this.openStart = -1; 5820 this.openEnd = -1; 5821 this.text = ""; 5822 this.textOff = 0; 5823 this.cursor = doc.iter(); 5824 this.skip = pos; 5825 } 5826 posCovered() { 5827 if (this.content.length == 0) 5828 return !this.breakAtStart && this.doc.lineAt(this.pos).from != this.pos; 5829 let last = this.content[this.content.length - 1]; 5830 return !last.breakAfter && !(last instanceof BlockWidgetView && last.type == BlockType.WidgetBefore); 5831 } 5832 getLine() { 5833 if (!this.curLine) { 5834 this.content.push(this.curLine = new LineView); 5835 this.atCursorPos = true; 5836 } 5837 return this.curLine; 5838 } 5839 flushBuffer(active) { 5840 if (this.pendingBuffer) { 5841 this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length); 5842 this.pendingBuffer = 0 /* Buf.No */; 5843 } 5844 } 5845 addBlockWidget(view) { 5846 this.flushBuffer([]); 5847 this.curLine = null; 5848 this.content.push(view); 5849 } 5850 finish(openEnd) { 5851 if (!openEnd) 5852 this.flushBuffer([]); 5853 else 5854 this.pendingBuffer = 0 /* Buf.No */; 5855 if (!this.posCovered()) 5856 this.getLine(); 5857 } 5858 buildText(length, active, openStart) { 5859 while (length > 0) { 5860 if (this.textOff == this.text.length) { 5861 let { value, lineBreak, done } = this.cursor.next(this.skip); 5862 this.skip = 0; 5863 if (done) 5864 throw new Error("Ran out of text content when drawing inline views"); 5865 if (lineBreak) { 5866 if (!this.posCovered()) 5867 this.getLine(); 5868 if (this.content.length) 5869 this.content[this.content.length - 1].breakAfter = 1; 5870 else 5871 this.breakAtStart = 1; 5872 this.flushBuffer([]); 5873 this.curLine = null; 5874 length--; 5875 continue; 5876 } 5877 else { 5878 this.text = value; 5879 this.textOff = 0; 5880 } 5881 } 5882 let take = Math.min(this.text.length - this.textOff, length, 512 /* T.Chunk */); 5883 this.flushBuffer(active.slice(0, openStart)); 5884 this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
5885 this.atCursorPos = true; 5886 this.textOff += take; 5887 length -= take; 5888 openStart = 0; 5889 } 5890 } 5891 span(from, to, active, openStart) { 5892 this.buildText(to - from, active, openStart); 5893 this.pos = to; 5894 if (this.openStart < 0) 5895 this.openStart = openStart; 5896 } 5897 point(from, to, deco, active, openStart, index) { 5898 if (this.disallowBlockEffectsFor[index] && deco instanceof PointDecoration) { 5899 if (deco.block) 5900 throw new RangeError("Block decorations may not be specified via plugins"); 5901 if (to > this.doc.lineAt(this.pos).to) 5902 throw new RangeError("Decorations that replace line breaks may not be specified via plugins"); 5903 } 5904 let len = to - from; 5905 if (deco instanceof PointDecoration) { 5906 if (deco.block) { 5907 let { type } = deco; 5908 if (type == BlockType.WidgetAfter && !this.posCovered()) 5909 this.getLine(); 5910 this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type)); 5911 } 5912 else { 5913 let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide); 5914 let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0); 5915 let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0); 5916 let line = this.getLine(); 5917 if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore) 5918 this.pendingBuffer = 0 /* Buf.No */; 5919 this.flushBuffer(active); 5920 if (cursorBefore) { 5921 line.append(wrapMarks(new WidgetBufferView(1), active), openStart); 5922 openStart = active.length + Math.max(0, openStart - active.length); 5923 } 5924 line.append(wrapMarks(view, active), openStart);
vendor: 10,891 bytes, lines 5925-6240
5925 this.atCursorPos = cursorAfter; 5926 this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */; 5927 } 5928 } 5929 else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration 5930 this.getLine().addLineDeco(deco); 5931 } 5932 if (len) { 5933 // Advance the iterator past the replaced content 5934 if (this.textOff + len <= this.text.length) { 5935 this.textOff += len; 5936 } 5937 else { 5938 this.skip += len - (this.text.length - this.textOff); 5939 this.text = ""; 5940 this.textOff = 0; 5941 } 5942 this.pos = to; 5943 } 5944 if (this.openStart < 0) 5945 this.openStart = openStart; 5946 } 5947 static build(text, from, to, decorations, dynamicDecorationMap) { 5948 let builder = new ContentBuilder(text, from, to, dynamicDecorationMap); 5949 builder.openEnd = RangeSet.spans(decorations, from, to, builder); 5950 if (builder.openStart < 0) 5951 builder.openStart = builder.openEnd; 5952 builder.finish(builder.openEnd); 5953 return builder; 5954 } 5955} 5956function wrapMarks(view, active) { 5957 for (let mark of active) 5958 view = new MarkView(mark, [view], view.length); 5959 return view; 5960} 5961class NullWidget extends WidgetType { 5962 constructor(tag) { 5963 super(); 5964 this.tag = tag; 5965 } 5966 eq(other) { return other.tag == this.tag; } 5967 toDOM() { return document.createElement(this.tag); } 5968 updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; } 5969} 5970 5971const clickAddsSelectionRange = /*@__PURE__*/Facet.define(); 5972const dragMovesSelection$1 = /*@__PURE__*/Facet.define(); 5973const mouseSelectionStyle = /*@__PURE__*/Facet.define(); 5974const exceptionSink = /*@__PURE__*/Facet.define(); 5975const updateListener = /*@__PURE__*/Facet.define(); 5976const inputHandler$1 = /*@__PURE__*/Facet.define(); 5977const perLineTextDirection = /*@__PURE__*/Facet.define({ 5978 combine: values => values.some(x => x) 5979}); 5980const nativeSelectionHidden = /*@__PURE__*/Facet.define({ 5981 combine: values => values.some(x => x) 5982}); 5983class ScrollTarget { 5984 constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) { 5985 this.range = range; 5986 this.y = y; 5987 this.x = x; 5988 this.yMargin = yMargin; 5989 this.xMargin = xMargin; 5990 } 5991 map(changes) { 5992 return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin); 5993 } 5994} 5995const scrollIntoView$1 = /*@__PURE__*/StateEffect.define({ map: (t, ch) => t.map(ch) }); 5996/** 5997Log or report an unhandled exception in client code. Should 5998probably only be used by extension code that allows client code to 5999provide functions, and calls those functions in a context where an 6000exception can't be propagated to calling code in a reasonable way 6001(for example when in an event handler). 6002 6003Either calls a handler registered with 6004[`EditorView.exceptionSink`](https://codemirror.net/6/docs/ref/#view.EditorView^exceptionSink), 6005`window.onerror`, if defined, or `console.error` (in which case 6006it'll pass `context`, when given, as first argument). 6007*/ 6008function logException(state, exception, context) { 6009 let handler = state.facet(exceptionSink); 6010 if (handler.length) 6011 handler[0](exception); 6012 else if (window.onerror) 6013 window.onerror(String(exception), context, undefined, undefined, exception); 6014 else if (context) 6015 console.error(context + ":", exception); 6016 else 6017 console.error(exception); 6018} 6019const editable = /*@__PURE__*/Facet.define({ combine: values => values.length ? values[0] : true }); 6020let nextPluginID = 0; 6021const viewPlugin = /*@__PURE__*/Facet.define(); 6022/** 6023View plugins associate stateful values with a view. They can 6024influence the way the content is drawn, and are notified of things 6025that happen in the view. 6026*/ 6027class ViewPlugin { 6028 constructor( 6029 /** 6030 @internal 6031 */ 6032 id, 6033 /** 6034 @internal 6035 */ 6036 create, 6037 /** 6038 @internal 6039 */ 6040 domEventHandlers, buildExtensions) { 6041 this.id = id; 6042 this.create = create; 6043 this.domEventHandlers = domEventHandlers; 6044 this.extension = buildExtensions(this); 6045 } 6046 /** 6047 Define a plugin from a constructor function that creates the 6048 plugin's value, given an editor view. 6049 */ 6050 static define(create, spec) { 6051 const { eventHandlers, provide, decorations: deco } = spec || {}; 6052 return new ViewPlugin(nextPluginID++, create, eventHandlers, plugin => { 6053 let ext = [viewPlugin.of(plugin)]; 6054 if (deco) 6055 ext.push(decorations.of(view => { 6056 let pluginInst = view.plugin(plugin); 6057 return pluginInst ? deco(pluginInst) : Decoration.none; 6058 })); 6059 if (provide) 6060 ext.push(provide(plugin)); 6061 return ext; 6062 }); 6063 } 6064 /** 6065 Create a plugin for a class whose constructor takes a single 6066 editor view as argument. 6067 */ 6068 static fromClass(cls, spec) { 6069 return ViewPlugin.define(view => new cls(view), spec); 6070 } 6071} 6072class PluginInstance { 6073 constructor(spec) { 6074 this.spec = spec; 6075 // When starting an update, all plugins have this field set to the 6076 // update object, indicating they need to be updated. When finished 6077 // updating, it is set to `false`. Retrieving a plugin that needs to 6078 // be updated with `view.plugin` forces an eager update. 6079 this.mustUpdate = null; 6080 // This is null when the plugin is initially created, but 6081 // initialized on the first update. 6082 this.value = null; 6083 } 6084 update(view) { 6085 if (!this.value) { 6086 if (this.spec) { 6087 try { 6088 this.value = this.spec.create(view); 6089 } 6090 catch (e) { 6091 logException(view.state, e, "CodeMirror plugin crashed"); 6092 this.deactivate(); 6093 } 6094 } 6095 } 6096 else if (this.mustUpdate) { 6097 let update = this.mustUpdate; 6098 this.mustUpdate = null; 6099 if (this.value.update) { 6100 try { 6101 this.value.update(update); 6102 } 6103 catch (e) { 6104 logException(update.state, e, "CodeMirror plugin crashed"); 6105 if (this.value.destroy) 6106 try { 6107 this.value.destroy(); 6108 } 6109 catch (_) { } 6110 this.deactivate(); 6111 } 6112 } 6113 } 6114 return this; 6115 } 6116 destroy(view) { 6117 var _a; 6118 if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.destroy) { 6119 try { 6120 this.value.destroy(); 6121 } 6122 catch (e) { 6123 logException(view.state, e, "CodeMirror plugin crashed"); 6124 } 6125 } 6126 } 6127 deactivate() { 6128 this.spec = this.value = null; 6129 } 6130} 6131const editorAttributes = /*@__PURE__*/Facet.define(); 6132const contentAttributes = /*@__PURE__*/Facet.define(); 6133// Provide decorations 6134const decorations = /*@__PURE__*/Facet.define(); 6135const atomicRanges = /*@__PURE__*/Facet.define(); 6136const scrollMargins = /*@__PURE__*/Facet.define(); 6137const styleModule = /*@__PURE__*/Facet.define(); 6138class ChangedRange { 6139 constructor(fromA, toA, fromB, toB) { 6140 this.fromA = fromA; 6141 this.toA = toA; 6142 this.fromB = fromB; 6143 this.toB = toB; 6144 } 6145 join(other) { 6146 return new ChangedRange(Math.min(this.fromA, other.fromA), Math.max(this.toA, other.toA), Math.min(this.fromB, other.fromB), Math.max(this.toB, other.toB)); 6147 } 6148 addToSet(set) { 6149 let i = set.length, me = this; 6150 for (; i > 0; i--) { 6151 let range = set[i - 1]; 6152 if (range.fromA > me.toA) 6153 continue; 6154 if (range.toA < me.fromA) 6155 break; 6156 me = me.join(range); 6157 set.splice(i - 1, 1); 6158 } 6159 set.splice(i, 0, me); 6160 return set; 6161 } 6162 static extendWithRanges(diff, ranges) { 6163 if (ranges.length == 0) 6164 return diff; 6165 let result = []; 6166 for (let dI = 0, rI = 0, posA = 0, posB = 0;; dI++) { 6167 let next = dI == diff.length ? null : diff[dI], off = posA - posB; 6168 let end = next ? next.fromB : 1e9; 6169 while (rI < ranges.length && ranges[rI] < end) { 6170 let from = ranges[rI], to = ranges[rI + 1]; 6171 let fromB = Math.max(posB, from), toB = Math.min(end, to); 6172 if (fromB <= toB) 6173 new ChangedRange(fromB + off, toB + off, fromB, toB).addToSet(result); 6174 if (to > end) 6175 break; 6176 else 6177 rI += 2; 6178 } 6179 if (!next) 6180 return result; 6181 new ChangedRange(next.fromA, next.toA, next.fromB, next.toB).addToSet(result); 6182 posA = next.toA; 6183 posB = next.toB; 6184 } 6185 } 6186} 6187/** 6188View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this 6189class, which describe what happened, whenever the view is updated. 6190*/ 6191class ViewUpdate { 6192 constructor( 6193 /** 6194 The editor view that the update is associated with. 6195 */ 6196 view, 6197 /** 6198 The new editor state. 6199 */ 6200 state, 6201 /** 6202 The transactions involved in the update. May be empty. 6203 */ 6204 transactions) { 6205 this.view = view; 6206 this.state = state; 6207 this.transactions = transactions; 6208 /** 6209 @internal 6210 */ 6211 this.flags = 0; 6212 this.startState = view.state; 6213 this.changes = ChangeSet.empty(this.startState.doc.length); 6214 for (let tr of transactions) 6215 this.changes = this.changes.compose(tr.changes); 6216 let changedRanges = []; 6217 this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB))); 6218 this.changedRanges = changedRanges; 6219 let focus = view.hasFocus; 6220 if (focus != view.inputState.notifiedFocused) { 6221 view.inputState.notifiedFocused = focus; 6222 this.flags |= 1 /* UpdateFlag.Focus */; 6223 } 6224 } 6225 /** 6226 @internal 6227 */ 6228 static create(view, state, transactions) { 6229 return new ViewUpdate(view, state, transactions); 6230 } 6231 /** 6232 Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or 6233 [visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this 6234 update. 6235 */ 6236 get viewportChanged() { 6237 return (this.flags & 4 /* UpdateFlag.Viewport */) > 0; 6238 } 6239 /** 6240 Indicates whether the height of a block element in the editor
6241 changed in this update. 6242 */ 6243 get heightChanged() { 6244 return (this.flags & 2 /* UpdateFlag.Height */) > 0; 6245 } 6246 /** 6247 Returns true when the document was modified or the size of the 6248 editor, or elements within the editor, changed. 6249 */ 6250 get geometryChanged() { 6251 return this.docChanged || (this.flags & (8 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0; 6252 } 6253 /** 6254 True when this update indicates a focus change. 6255 */ 6256 get focusChanged() { 6257 return (this.flags & 1 /* UpdateFlag.Focus */) > 0; 6258 } 6259 /** 6260 Whether the document changed in this update. 6261 */ 6262 get docChanged() { 6263 return !this.changes.empty; 6264 } 6265 /** 6266 Whether the selection was explicitly set in this update. 6267 */ 6268 get selectionSet() { 6269 return this.transactions.some(tr => tr.selection); 6270 } 6271 /** 6272 @internal 6273 */ 6274 get empty() { return this.flags == 0 && this.transactions.length == 0; } 6275} 6276 6277/** 6278Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). 6279*/ 6280var Direction = /*@__PURE__*/(function (Direction) { 6281 // (These are chosen to match the base levels, in bidi algorithm 6282 // terms, of spans in that direction.) 6283 /** 6284 Left-to-right. 6285 */ 6286 Direction[Direction["LTR"] = 0] = "LTR"; 6287 /** 6288 Right-to-left. 6289 */ 6290 Direction[Direction["RTL"] = 1] = "RTL"; 6291return Direction})(Direction || (Direction = {})); 6292const LTR = Direction.LTR, RTL = Direction.RTL; 6293// Decode a string with each type encoded as log2(type) 6294function dec(str) { 6295 let result = []; 6296 for (let i = 0; i < str.length; i++) 6297 result.push(1 << +str[i]); 6298 return result; 6299} 6300// Character types for codepoints 0 to 0xf8 6301const LowTypes = /*@__PURE__*/dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008"); 6302// Character types for codepoints 0x600 to 0x6f9 6303const ArabicTypes = /*@__PURE__*/dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333"); 6304const Brackets = /*@__PURE__*/Object.create(null), BracketStack = []; 6305// There's a lot more in 6306// https://www.unicode.org/Public/UCD/latest/ucd/BidiBrackets.txt, 6307// which are left out to keep code size down. 6308for (let p of ["()", "[]", "{}"]) { 6309 let l = /*@__PURE__*/p.charCodeAt(0), r = /*@__PURE__*/p.charCodeAt(1); 6310 Brackets[l] = r; 6311 Brackets[r] = -l; 6312} 6313function charType(ch) { 6314 return ch <= 0xf7 ? LowTypes[ch] : 6315 0x590 <= ch && ch <= 0x5f4 ? 2 /* T.R */ : 6316 0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] : 6317 0x6ee <= ch && ch <= 0x8ac ? 4 /* T.AL */ : 6318 0x2000 <= ch && ch <= 0x200b ? 256 /* T.NI */ : 6319 0xfb50 <= ch && ch <= 0xfdff ? 4 /* T.AL */ : 6320 ch == 0x200c ? 256 /* T.NI */ : 1 /* T.L */; 6321} 6322const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\ufb50-\ufdff]/; 6323/** 6324Represents a contiguous range of text that has a single direction 6325(as in left-to-right or right-to-left). 6326*/ 6327class BidiSpan { 6328 /** 6329 @internal 6330 */ 6331 constructor( 6332 /** 6333 The start of the span (relative to the start of the line). 6334 */ 6335 from, 6336 /** 6337 The end of the span. 6338 */ 6339 to, 6340 /** 6341 The ["bidi 6342 level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm) 6343 of the span (in this context, 0 means 6344 left-to-right, 1 means right-to-left, 2 means left-to-right 6345 number inside right-to-left text). 6346 */ 6347 level) { 6348 this.from = from; 6349 this.to = to; 6350 this.level = level; 6351 } 6352 /** 6353 The direction of this span. 6354 */ 6355 get dir() { return this.level % 2 ? RTL : LTR; } 6356 /** 6357 @internal 6358 */ 6359 side(end, dir) { return (this.dir == dir) == end ? this.to : this.from; } 6360 /** 6361 @internal 6362 */ 6363 static find(order, index, level, assoc) { 6364 let maybe = -1; 6365 for (let i = 0; i < order.length; i++) { 6366 let span = order[i]; 6367 if (span.from <= index && span.to >= index) { 6368 if (span.level == level) 6369 return i; 6370 // When multiple spans match, if assoc != 0, take the one that 6371 // covers that side, otherwise take the one with the minimum 6372 // level. 6373 if (maybe < 0 || (assoc != 0 ? (assoc < 0 ? span.from < index : span.to > index) : order[maybe].level > span.level)) 6374 maybe = i; 6375 } 6376 } 6377 if (maybe < 0) 6378 throw new RangeError("Index out of range"); 6379 return maybe; 6380 } 6381} 6382// Reused array of character types 6383const types = []; 6384function computeOrder(line, direction) { 6385 let len = line.length, outerType = direction == LTR ? 1 /* T.L */ : 2 /* T.R */, oppositeType = direction == LTR ? 2 /* T.R */ : 1 /* T.L */; 6386 if (!line || outerType == 1 /* T.L */ && !BidiRE.test(line)) 6387 return trivialOrder(len); 6388 // W1. Examine each non-spacing mark (NSM) in the level run, and 6389 // change the type of the NSM to the type of the previous 6390 // character. If the NSM is at the start of the level run, it will 6391 // get the type of sor. 6392 // W2. Search backwards from each instance of a European number 6393 // until the first strong type (R, L, AL, or sor) is found. If an 6394 // AL is found, change the type of the European number to Arabic 6395 // number. 6396 // W3. Change all ALs to R. 6397 // (Left after this: L, R, EN, AN, ET, CS, NI) 6398 for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) { 6399 let type = charType(line.charCodeAt(i)); 6400 if (type == 512 /* T.NSM */) 6401 type = prev; 6402 else if (type == 8 /* T.EN */ && prevStrong == 4 /* T.AL */) 6403 type = 16 /* T.AN */; 6404 types[i] = type == 4 /* T.AL */ ? 2 /* T.R */ : type; 6405 if (type & 7 /* T.Strong */) 6406 prevStrong = type; 6407 prev = type; 6408 } 6409 // W5. A sequence of European terminators adjacent to European 6410 // numbers changes to all European numbers. 6411 // W6. Otherwise, separators and terminators change to Other 6412 // Neutral. 6413 // W7. Search backwards from each instance of a European number 6414 // until the first strong type (R, L, or sor) is found. If an L is 6415 // found, then change the type of the European number to L. 6416 // (Left after this: L, R, EN+AN, NI) 6417 for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) { 6418 let type = types[i]; 6419 if (type == 128 /* T.CS */) { 6420 if (i < len - 1 && prev == types[i + 1] && (prev & 24 /* T.Num */)) 6421 type = types[i] = prev; 6422 else 6423 types[i] = 256 /* T.NI */; 6424 } 6425 else if (type == 64 /* T.ET */) { 6426 let end = i + 1; 6427 while (end < len && types[end] == 64 /* T.ET */) 6428 end++; 6429 let replace = (i && prev == 8 /* T.EN */) || (end < len && types[end] == 8 /* T.EN */) ? (prevStrong == 1 /* T.L */ ? 1 /* T.L */ : 8 /* T.EN */) : 256 /* T.NI */; 6430 for (let j = i; j < end; j++) 6431 types[j] = replace; 6432 i = end - 1; 6433 } 6434 else if (type == 8 /* T.EN */ && prevStrong == 1 /* T.L */) { 6435 types[i] = 1 /* T.L */; 6436 } 6437 prev = type; 6438 if (type & 7 /* T.Strong */) 6439 prevStrong = type; 6440 } 6441 // N0. Process bracket pairs in an isolating run sequence 6442 // sequentially in the logical order of the text positions of the 6443 // opening paired brackets using the logic given below. Within this 6444 // scope, bidirectional types EN and AN are treated as R. 6445 for (let i = 0, sI = 0, context = 0, ch, br, type; i < len; i++) { 6446 // Keeps [startIndex, type, strongSeen] triples for each open 6447 // bracket on BracketStack. 6448 if (br = Brackets[ch = line.charCodeAt(i)]) { 6449 if (br < 0) { // Closing bracket 6450 for (let sJ = sI - 3; sJ >= 0; sJ -= 3) { 6451 if (BracketStack[sJ + 1] == -br) { 6452 let flags = BracketStack[sJ + 2]; 6453 let type = (flags & 2 /* Bracketed.EmbedInside */) ? outerType : 6454 !(flags & 4 /* Bracketed.OppositeInside */) ? 0 : 6455 (flags & 1 /* Bracketed.OppositeBefore */) ? oppositeType : outerType; 6456 if (type) 6457 types[i] = types[BracketStack[sJ]] = type; 6458 sI = sJ; 6459 break; 6460 } 6461 } 6462 } 6463 else if (BracketStack.length == 189 /* Bracketed.MaxDepth */) { 6464 break; 6465 } 6466 else { 6467 BracketStack[sI++] = i; 6468 BracketStack[sI++] = ch; 6469 BracketStack[sI++] = context; 6470 } 6471 } 6472 else if ((type = types[i]) == 2 /* T.R */ || type == 1 /* T.L */) { 6473 let embed = type == outerType; 6474 context = embed ? 0 : 1 /* Bracketed.OppositeBefore */; 6475 for (let sJ = sI - 3; sJ >= 0; sJ -= 3) { 6476 let cur = BracketStack[sJ + 2]; 6477 if (cur & 2 /* Bracketed.EmbedInside */) 6478 break; 6479 if (embed) { 6480 BracketStack[sJ + 2] |= 2 /* Bracketed.EmbedInside */; 6481 } 6482 else { 6483 if (cur & 4 /* Bracketed.OppositeInside */) 6484 break; 6485 BracketStack[sJ + 2] |= 4 /* Bracketed.OppositeInside */; 6486 } 6487 } 6488 } 6489 } 6490 // N1. A sequence of neutrals takes the direction of the 6491 // surrounding strong text if the text on both sides has the same 6492 // direction. European and Arabic numbers act as if they were R in 6493 // terms of their influence on neutrals. Start-of-level-run (sor) 6494 // and end-of-level-run (eor) are used at level run boundaries. 6495 // N2. Any remaining neutrals take the embedding direction. 6496 // (Left after this: L, R, EN+AN) 6497 for (let i = 0; i < len; i++) { 6498 if (types[i] == 256 /* T.NI */) { 6499 let end = i + 1; 6500 while (end < len && types[end] == 256 /* T.NI */) 6501 end++; 6502 let beforeL = (i ? types[i - 1] : outerType) == 1 /* T.L */; 6503 let afterL = (end < len ? types[end] : outerType) == 1 /* T.L */; 6504 let replace = beforeL == afterL ? (beforeL ? 1 /* T.L */ : 2 /* T.R */) : outerType; 6505 for (let j = i; j < end; j++) 6506 types[j] = replace; 6507 i = end - 1; 6508 } 6509 } 6510 // Here we depart from the documented algorithm, in order to avoid 6511 // building up an actual levels array. Since there are only three 6512 // levels (0, 1, 2) in an implementation that doesn't take 6513 // explicit embedding into account, we can build up the order on 6514 // the fly, without following the level-based algorithm. 6515 let order = []; 6516 if (outerType == 1 /* T.L */) { 6517 for (let i = 0; i < len;) { 6518 let start = i, rtl = types[i++] != 1 /* T.L */; 6519 while (i < len && rtl == (types[i] != 1 /* T.L */)) 6520 i++; 6521 if (rtl) { 6522 for (let j = i; j > start;) { 6523 let end = j, l = types[--j] != 2 /* T.R */; 6524 while (j > start && l == (types[j - 1] != 2 /* T.R */)) 6525 j--; 6526 order.push(new BidiSpan(j, end, l ? 2 : 1)); 6527 } 6528 } 6529 else { 6530 order.push(new BidiSpan(start, i, 0)); 6531 } 6532 } 6533 } 6534 else { 6535 for (let i = 0; i < len;) { 6536 let start = i, rtl = types[i++] == 2 /* T.R */; 6537 while (i < len && rtl == (types[i] == 2 /* T.R */)) 6538 i++; 6539 order.push(new BidiSpan(start, i, rtl ? 1 : 2)); 6540 } 6541 } 6542 return order; 6543} 6544function trivialOrder(length) { 6545 return [new BidiSpan(0, length, 0)]; 6546} 6547let movedOver = ""; 6548function moveVisually(line, order, dir, start, forward) { 6549 var _a; 6550 let startIndex = start.head - line.from, spanI = -1; 6551 if (startIndex == 0) { 6552 if (!forward || !line.length) 6553 return null; 6554 if (order[0].level != dir) { 6555 startIndex = order[0].side(false, dir); 6556 spanI = 0; 6557 } 6558 } 6559 else if (startIndex == line.length) { 6560 if (forward) 6561 return null; 6562 let last = order[order.length - 1]; 6563 if (last.level != dir) { 6564 startIndex = last.side(true, dir); 6565 spanI = order.length - 1; 6566 } 6567 } 6568 if (spanI < 0) 6569 spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc); 6570 let span = order[spanI]; 6571 // End of span. (But not end of line--that was checked for above.) 6572 if (startIndex == span.side(forward, dir)) { 6573 span = order[spanI += forward ? 1 : -1]; 6574 startIndex = span.side(!forward, dir); 6575 } 6576 let indexForward = forward == (span.dir == dir); 6577 let nextIndex = findClusterBreak(line.text, startIndex, indexForward); 6578 movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex)); 6579 if (nextIndex != span.side(forward, dir)) 6580 return EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level); 6581 let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)]; 6582 if (!nextSpan && span.level != dir)
6583 return EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1, dir); 6584 if (nextSpan && nextSpan.level < span.level) 6585 return EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, forward ? 1 : -1, nextSpan.level); 6586 return EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level); 6587} 6588 6589const LineBreakPlaceholder = "\uffff"; 6590class DOMReader { 6591 constructor(points, state) { 6592 this.points = points; 6593 this.text = ""; 6594 this.lineSeparator = state.facet(EditorState.lineSeparator); 6595 } 6596 append(text) { 6597 this.text += text; 6598 } 6599 lineBreak() { 6600 this.text += LineBreakPlaceholder; 6601 } 6602 readRange(start, end) { 6603 if (!start) 6604 return this; 6605 let parent = start.parentNode; 6606 for (let cur = start;;) { 6607 this.findPointBefore(parent, cur); 6608 this.readNode(cur); 6609 let next = cur.nextSibling; 6610 if (next == end) 6611 break; 6612 let view = ContentView.get(cur), nextView = ContentView.get(next); 6613 if (view && nextView ? view.breakAfter : 6614 (view ? view.breakAfter : isBlockElement(cur)) || 6615 (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore))) 6616 this.lineBreak(); 6617 cur = next; 6618 } 6619 this.findPointBefore(parent, end); 6620 return this; 6621 } 6622 readTextNode(node) { 6623 let text = node.nodeValue; 6624 for (let point of this.points) 6625 if (point.node == node) 6626 point.pos = this.text.length + Math.min(point.offset, text.length); 6627 for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) { 6628 let nextBreak = -1, breakSize = 1, m; 6629 if (this.lineSeparator) { 6630 nextBreak = text.indexOf(this.lineSeparator, off); 6631 breakSize = this.lineSeparator.length; 6632 } 6633 else if (m = re.exec(text)) { 6634 nextBreak = m.index; 6635 breakSize = m[0].length; 6636 } 6637 this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak)); 6638 if (nextBreak < 0) 6639 break; 6640 this.lineBreak(); 6641 if (breakSize > 1) 6642 for (let point of this.points) 6643 if (point.node == node && point.pos > this.text.length) 6644 point.pos -= breakSize - 1; 6645 off = nextBreak + breakSize; 6646 } 6647 } 6648 readNode(node) { 6649 if (node.cmIgnore) 6650 return; 6651 let view = ContentView.get(node); 6652 let fromView = view && view.overrideDOMText; 6653 if (fromView != null) { 6654 this.findPointInside(node, fromView.length); 6655 for (let i = fromView.iter(); !i.next().done;) { 6656 if (i.lineBreak) 6657 this.lineBreak(); 6658 else 6659 this.append(i.value); 6660 } 6661 } 6662 else if (node.nodeType == 3) { 6663 this.readTextNode(node); 6664 } 6665 else if (node.nodeName == "BR") { 6666 if (node.nextSibling) 6667 this.lineBreak(); 6668 } 6669 else if (node.nodeType == 1) { 6670 this.readRange(node.firstChild, null); 6671 } 6672 } 6673 findPointBefore(node, next) { 6674 for (let point of this.points) 6675 if (point.node == node && node.childNodes[point.offset] == next) 6676 point.pos = this.text.length; 6677 } 6678 findPointInside(node, maxLen) { 6679 for (let point of this.points) 6680 if (node.nodeType == 3 ? point.node == node : node.contains(point.node)) 6681 point.pos = this.text.length + Math.min(maxLen, point.offset); 6682 } 6683} 6684function isBlockElement(node) { 6685 return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName); 6686} 6687class DOMPoint { 6688 constructor(node, offset) { 6689 this.node = node; 6690 this.offset = offset; 6691 this.pos = -1; 6692 } 6693} 6694 6695class DocView extends ContentView { 6696 constructor(view) { 6697 super(); 6698 this.view = view; 6699 this.compositionDeco = Decoration.none; 6700 this.decorations = []; 6701 this.dynamicDecorationMap = []; 6702 // Track a minimum width for the editor. When measuring sizes in 6703 // measureVisibleLineHeights, this is updated to point at the width 6704 // of a given element and its extent in the document. When a change 6705 // happens in that range, these are reset. That way, once we've seen 6706 // a line/element of a given length, we keep the editor wide enough 6707 // to fit at least that element, until it is changed, at which point 6708 // we forget it again. 6709 this.minWidth = 0; 6710 this.minWidthFrom = 0; 6711 this.minWidthTo = 0; 6712 // Track whether the DOM selection was set in a lossy way, so that 6713 // we don't mess it up when reading it back it 6714 this.impreciseAnchor = null; 6715 this.impreciseHead = null; 6716 this.forceSelection = false;
6717 // Used by the resize observer to ignore resizes that we caused 6718 // ourselves 6719 this.lastUpdate = Date.now(); 6720 this.setDOM(view.contentDOM); 6721 this.children = [new LineView]; 6722 this.children[0].setParent(this); 6723 this.updateDeco(); 6724 this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0); 6725 } 6726 get editorView() { return this.view; } 6727 get length() { return this.view.state.doc.length; } 6728 // Update the document view to a given state. scrollIntoView can be 6729 // used as a hint to compute a new viewport that includes that 6730 // position, if we know the editor is going to scroll that position 6731 // into view. 6732 update(update) { 6733 let changedRanges = update.changedRanges; 6734 if (this.minWidth > 0 && changedRanges.length) { 6735 if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) { 6736 this.minWidth = this.minWidthFrom = this.minWidthTo = 0; 6737 } 6738 else { 6739 this.minWidthFrom = update.changes.mapPos(this.minWidthFrom, 1); 6740 this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1); 6741 } 6742 } 6743 if (this.view.inputState.composing < 0) 6744 this.compositionDeco = Decoration.none; 6745 else if (update.transactions.length || this.dirty) 6746 this.compositionDeco = computeCompositionDeco(this.view, update.changes); 6747 // When the DOM nodes around the selection are moved to another 6748 // parent, Chrome sometimes reports a different selection through 6749 // getSelection than the one that it actually shows to the user. 6750 // This forces a selection update when lines are joined to work 6751 // around that. Issue #54 6752 if ((browser.ie || browser.chrome) && !this.compositionDeco.size && update && 6753 update.state.doc.lines != update.startState.doc.lines) 6754 this.forceSelection = true; 6755 let prevDeco = this.decorations, deco = this.updateDeco(); 6756 let decoDiff = findChangedDeco(prevDeco, deco, update.changes); 6757 changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff); 6758 if (this.dirty == 0 /* Dirty.Not */ && changedRanges.length == 0) { 6759 return false; 6760 } 6761 else { 6762 this.updateInner(changedRanges, update.startState.doc.length); 6763 if (update.transactions.length) 6764 this.lastUpdate = Date.now(); 6765 return true; 6766 } 6767 } 6768 // Used by update and the constructor do perform the actual DOM 6769 // update 6770 updateInner(changes, oldLength) { 6771 this.view.viewState.mustMeasureContent = true; 6772 this.updateChildren(changes, oldLength); 6773 let { observer } = this.view; 6774 observer.ignore(() => { 6775 // Lock the height during redrawing, since Chrome sometimes 6776 // messes with the scroll position during DOM mutation (though 6777 // no relayout is triggered and I cannot imagine how it can 6778 // recompute the scroll position without a layout) 6779 this.dom.style.height = this.view.viewState.contentHeight + "px"; 6780 this.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : ""; 6781 // Chrome will sometimes, when DOM mutations occur directly 6782 // around the selection, get confused and report a different 6783 // selection from the one it displays (issue #218). This tries 6784 // to detect that situation. 6785 let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined; 6786 this.sync(track); 6787 this.dirty = 0 /* Dirty.Not */; 6788 if (track && (track.written || observer.selectionRange.focusNode != track.node)) 6789 this.forceSelection = true; 6790 this.dom.style.height = ""; 6791 }); 6792 let gaps = []; 6793 if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length) 6794 for (let child of this.children) 6795 if (child instanceof BlockWidgetView && child.widget instanceof BlockGapWidget) 6796 gaps.push(child.dom); 6797 observer.updateGaps(gaps); 6798 } 6799 updateChildren(changes, oldLength) { 6800 let cursor = this.childCursor(oldLength); 6801 for (let i = changes.length - 1;; i--) { 6802 let next = i >= 0 ? changes[i] : null; 6803 if (!next) 6804 break; 6805 let { fromA, toA, fromB, toB } = next; 6806 let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap); 6807 let { i: toI, off: toOff } = cursor.findPos(toA, 1); 6808 let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1); 6809 replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd); 6810 } 6811 } 6812 // Sync the DOM selection to this.state.selection 6813 updateSelection(mustRead = false, fromPointer = false) { 6814 if (mustRead || !this.view.observer.selectionRange.focusNode) 6815 this.view.observer.readSelectionRange(); 6816 if (!(fromPointer || this.mayControlSelection())) 6817 return; 6818 let force = this.forceSelection; 6819 this.forceSelection = false;
6820 let main = this.view.state.selection.main; 6821 // FIXME need to handle the case where the selection falls inside a block range 6822 let anchor = this.domAtPos(main.anchor); 6823 let head = main.empty ? anchor : this.domAtPos(main.head); 6824 // Always reset on Firefox when next to an uneditable node to 6825 // avoid invisible cursor bugs (#111) 6826 if (browser.gecko && main.empty && betweenUneditable(anchor)) { 6827 let dummy = document.createTextNode(""); 6828 this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null)); 6829 anchor = head = new DOMPos(dummy, 0); 6830 force = true; 6831 } 6832 let domSel = this.view.observer.selectionRange; 6833 // If the selection is already here, or in an equivalent position, don't touch it 6834 if (force || !domSel.focusNode || 6835 !isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) || 6836 !isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) { 6837 this.view.observer.ignore(() => { 6838 // Chrome Android will hide the virtual keyboard when tapping 6839 // inside an uneditable node, and not bring it back when we 6840 // move the cursor to its proper position. This tries to 6841 // restore the keyboard by cycling focus. 6842 if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) && 6843 inUneditable(domSel.focusNode, this.dom)) { 6844 this.dom.blur(); 6845 this.dom.focus({ preventScroll: true }); 6846 } 6847 let rawSel = getSelection(this.view.root); 6848 if (!rawSel) ; 6849 else if (main.empty) { 6850 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076 6851 if (browser.gecko) { 6852 let nextTo = nextToUneditable(anchor.node, anchor.offset); 6853 if (nextTo && nextTo != (1 /* NextTo.Before */ | 2 /* NextTo.After */)) { 6854 let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 /* NextTo.Before */ ? 1 : -1); 6855 if (text) 6856 anchor = new DOMPos(text, nextTo == 1 /* NextTo.Before */ ? 0 : text.nodeValue.length); 6857 } 6858 } 6859 rawSel.collapse(anchor.node, anchor.offset); 6860 if (main.bidiLevel != null && domSel.cursorBidiLevel != null) 6861 domSel.cursorBidiLevel = main.bidiLevel; 6862 } 6863 else if (rawSel.extend) { 6864 // Selection.extend can be used to create an 'inverted' selection 6865 // (one where the focus is before the anchor), but not all 6866 // browsers support it yet. 6867 rawSel.collapse(anchor.node, anchor.offset); 6868 // Safari will ignore the call above when the editor is 6869 // hidden, and then raise an error on the call to extend 6870 // (#940). 6871 try { 6872 rawSel.extend(head.node, head.offset); 6873 } 6874 catch (_) { } 6875 } 6876 else { 6877 // Primitive (IE) way 6878 let range = document.createRange(); 6879 if (main.anchor > main.head) 6880 [anchor, head] = [head, anchor]; 6881 range.setEnd(head.node, head.offset); 6882 range.setStart(anchor.node, anchor.offset); 6883 rawSel.removeAllRanges(); 6884 rawSel.addRange(range); 6885 } 6886 }); 6887 this.view.observer.setSelectionRange(anchor, head); 6888 } 6889 this.impreciseAnchor = anchor.precise ? null : new DOMPos(domSel.anchorNode, domSel.anchorOffset); 6890 this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset); 6891 } 6892 enforceCursorAssoc() { 6893 if (this.compositionDeco.size) 6894 return; 6895 let { view } = this, cursor = view.state.selection.main; 6896 let sel = getSelection(view.root); 6897 let { anchorNode, anchorOffset } = view.observer.selectionRange; 6898 if (!sel || !cursor.empty || !cursor.assoc || !sel.modify) 6899 return; 6900 let line = LineView.find(this, cursor.head); 6901 if (!line) 6902 return; 6903 let lineStart = line.posAtStart; 6904 if (cursor.head == lineStart || cursor.head == lineStart + line.length) 6905 return; 6906 let before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1); 6907 if (!before || !after || before.bottom > after.top) 6908 return;
6909 let dom = this.domAtPos(cursor.head + cursor.assoc); 6910 sel.collapse(dom.node, dom.offset); 6911 sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary"); 6912 // This can go wrong in corner cases like single-character lines, 6913 // so check and reset if necessary. 6914 view.observer.readSelectionRange(); 6915 let newRange = view.observer.selectionRange; 6916 if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from) 6917 sel.collapse(anchorNode, anchorOffset); 6918 } 6919 mayControlSelection() { 6920 let active = this.view.root.activeElement; 6921 return active == this.dom || 6922 hasSelection(this.dom, this.view.observer.selectionRange) && !(active && this.dom.contains(active)); 6923 } 6924 nearest(dom) { 6925 for (let cur = dom; cur;) { 6926 let domView = ContentView.get(cur); 6927 if (domView && domView.rootView == this) 6928 return domView; 6929 cur = cur.parentNode; 6930 } 6931 return null; 6932 } 6933 posFromDOM(node, offset) { 6934 let view = this.nearest(node); 6935 if (!view) 6936 throw new RangeError("Trying to find position for a DOM position outside of the document"); 6937 return view.localPosFromDOM(node, offset) + view.posAtStart; 6938 } 6939 domAtPos(pos) { 6940 let { i, off } = this.childCursor().findPos(pos, -1); 6941 for (; i < this.children.length - 1;) { 6942 let child = this.children[i]; 6943 if (off < child.length || child instanceof LineView) 6944 break; 6945 i++; 6946 off = 0; 6947 } 6948 return this.children[i].domAtPos(off); 6949 } 6950 coordsAt(pos, side) { 6951 for (let off = this.length, i = this.children.length - 1;; i--) { 6952 let child = this.children[i], start = off - child.breakAfter - child.length; 6953 if (pos > start || 6954 (pos == start && child.type != BlockType.WidgetBefore && child.type != BlockType.WidgetAfter && 6955 (!i || side == 2 || this.children[i - 1].breakAfter || 6956 (this.children[i - 1].type == BlockType.WidgetBefore && side > -2)))) 6957 return child.coordsAt(pos - start, side); 6958 off = start; 6959 } 6960 } 6961 measureVisibleLineHeights(viewport) { 6962 let result = [], { from, to } = viewport; 6963 let contentWidth = this.view.contentDOM.clientWidth; 6964 let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1; 6965 let widest = -1, ltr = this.view.textDirection == Direction.LTR; 6966 for (let pos = 0, i = 0; i < this.children.length; i++) { 6967 let child = this.children[i], end = pos + child.length; 6968 if (end > to) 6969 break; 6970 if (pos >= from) { 6971 let childRect = child.dom.getBoundingClientRect(); 6972 result.push(childRect.height); 6973 if (isWider) { 6974 let last = child.dom.lastChild; 6975 let rects = last ? clientRectsFor(last) : []; 6976 if (rects.length) { 6977 let rect = rects[rects.length - 1]; 6978 let width = ltr ? rect.right - childRect.left : childRect.right - rect.left; 6979 if (width > widest) { 6980 widest = width; 6981 this.minWidth = contentWidth; 6982 this.minWidthFrom = pos; 6983 this.minWidthTo = end; 6984 } 6985 } 6986 } 6987 } 6988 pos = end + child.breakAfter; 6989 } 6990 return result; 6991 } 6992 textDirectionAt(pos) { 6993 let { i } = this.childPos(pos, 1); 6994 return getComputedStyle(this.children[i].dom).direction == "rtl" ? Direction.RTL : Direction.LTR; 6995 } 6996 measureTextSize() { 6997 for (let child of this.children) { 6998 if (child instanceof LineView) { 6999 let measure = child.measureTextSize(); 7000 if (measure) 7001 return measure; 7002 } 7003 }
7004 // If no workable line exists, force a layout of a measurable element 7005 let dummy = document.createElement("div"), lineHeight, charWidth; 7006 dummy.className = "cm-line"; 7007 dummy.style.width = "99999px"; 7008 dummy.textContent = "abc def ghi jkl mno pqr stu"; 7009 this.view.observer.ignore(() => { 7010 this.dom.appendChild(dummy); 7011 let rect = clientRectsFor(dummy.firstChild)[0]; 7012 lineHeight = dummy.getBoundingClientRect().height; 7013 charWidth = rect ? rect.width / 27 : 7; 7014 dummy.remove(); 7015 }); 7016 return { lineHeight, charWidth }; 7017 } 7018 childCursor(pos = this.length) { 7019 // Move back to start of last element when possible, so that 7020 // `ChildCursor.findPos` doesn't have to deal with the edge case 7021 // of being after the last element. 7022 let i = this.children.length; 7023 if (i) 7024 pos -= this.children[--i].length; 7025 return new ChildCursor(this.children, pos, i); 7026 } 7027 computeBlockGapDeco() { 7028 let deco = [], vs = this.view.viewState; 7029 for (let pos = 0, i = 0;; i++) { 7030 let next = i == vs.viewports.length ? null : vs.viewports[i]; 7031 let end = next ? next.from - 1 : this.length; 7032 if (end > pos) { 7033 let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top; 7034 deco.push(Decoration.replace({ 7035 widget: new BlockGapWidget(height), 7036 block: true, 7037 inclusive: true, 7038 isBlockGap: true, 7039 }).range(pos, end)); 7040 } 7041 if (!next) 7042 break; 7043 pos = next.to + 1; 7044 } 7045 return Decoration.set(deco); 7046 } 7047 updateDeco() { 7048 let allDeco = this.view.state.facet(decorations).map((d, i) => { 7049 let dynamic = this.dynamicDecorationMap[i] = typeof d == "function"; 7050 return dynamic ? d(this.view) : d; 7051 }); 7052 for (let i = allDeco.length; i < allDeco.length + 3; i++) 7053 this.dynamicDecorationMap[i] = false; 7054 return this.decorations = [ 7055 ...allDeco, 7056 this.compositionDeco, 7057 this.computeBlockGapDeco(), 7058 this.view.viewState.lineGapDeco 7059 ]; 7060 } 7061 scrollIntoView(target) { 7062 let { range } = target; 7063 let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other; 7064 if (!rect) 7065 return; 7066 if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1))) 7067 rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top), 7068 right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) }; 7069 let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0; 7070 for (let margins of this.view.state.facet(scrollMargins).map(f => f(this.view))) 7071 if (margins) { 7072 let { left, right, top, bottom } = margins; 7073 if (left != null) 7074 mLeft = Math.max(mLeft, left); 7075 if (right != null) 7076 mRight = Math.max(mRight, right); 7077 if (top != null) 7078 mTop = Math.max(mTop, top); 7079 if (bottom != null) 7080 mBottom = Math.max(mBottom, bottom); 7081 } 7082 let targetRect = { 7083 left: rect.left - mLeft, top: rect.top - mTop, 7084 right: rect.right + mRight, bottom: rect.bottom + mBottom 7085 }; 7086 scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, target.xMargin, target.yMargin, this.view.textDirection == Direction.LTR); 7087 } 7088} 7089function betweenUneditable(pos) { 7090 return pos.node.nodeType == 1 && pos.node.firstChild && 7091 (pos.offset == 0 || pos.node.childNodes[pos.offset - 1].contentEditable == "false") && 7092 (pos.offset == pos.node.childNodes.length || pos.node.childNodes[pos.offset].contentEditable == "false"); 7093} 7094class BlockGapWidget extends WidgetType { 7095 constructor(height) { 7096 super(); 7097 this.height = height; 7098 } 7099 toDOM() { 7100 let elt = document.createElement("div"); 7101 this.updateDOM(elt); 7102 return elt; 7103 } 7104 eq(other) { return other.height == this.height; } 7105 updateDOM(elt) { 7106 elt.style.height = this.height + "px"; 7107 return true; 7108 } 7109 get estimatedHeight() { return this.height; } 7110} 7111function compositionSurroundingNode(view) { 7112 let sel = view.observer.selectionRange; 7113 let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0); 7114 if (!textNode) 7115 return null;
7116 let cView = view.docView.nearest(textNode); 7117 if (!cView) 7118 return null; 7119 if (cView instanceof LineView) { 7120 let topNode = textNode; 7121 while (topNode.parentNode != cView.dom) 7122 topNode = topNode.parentNode; 7123 let prev = topNode.previousSibling; 7124 while (prev && !ContentView.get(prev)) 7125 prev = prev.previousSibling; 7126 let pos = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart; 7127 return { from: pos, to: pos, node: topNode, text: textNode }; 7128 } 7129 else { 7130 for (;;) { 7131 let { parent } = cView; 7132 if (!parent) 7133 return null; 7134 if (parent instanceof LineView) 7135 break; 7136 cView = parent; 7137 } 7138 let from = cView.posAtStart; 7139 return { from, to: from + cView.length, node: cView.dom, text: textNode }; 7140 } 7141} 7142function computeCompositionDeco(view, changes) { 7143 let surrounding = compositionSurroundingNode(view); 7144 if (!surrounding) 7145 return Decoration.none; 7146 let { from, to, node, text: textNode } = surrounding; 7147 let newFrom = changes.mapPos(from, 1), newTo = Math.max(newFrom, changes.mapPos(to, -1)); 7148 let { state } = view, text = node.nodeType == 3 ? node.nodeValue : 7149 new DOMReader([], state).readRange(node.firstChild, null).text; 7150 if (newTo - newFrom < text.length) { 7151 if (state.doc.sliceString(newFrom, Math.min(state.doc.length, newFrom + text.length), LineBreakPlaceholder) == text) 7152 newTo = newFrom + text.length; 7153 else if (state.doc.sliceString(Math.max(0, newTo - text.length), newTo, LineBreakPlaceholder) == text) 7154 newFrom = newTo - text.length; 7155 else 7156 return Decoration.none; 7157 } 7158 else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) { 7159 return Decoration.none; 7160 } 7161 let topView = ContentView.get(node); 7162 if (topView instanceof CompositionView) 7163 topView = topView.widget.topView; 7164 else if (topView) 7165 topView.parent = null; 7166 return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode, topView), inclusive: true }) 7167 .range(newFrom, newTo)); 7168} 7169class CompositionWidget extends WidgetType { 7170 constructor(top, text, topView) { 7171 super(); 7172 this.top = top; 7173 this.text = text; 7174 this.topView = topView; 7175 } 7176 eq(other) { return this.top == other.top && this.text == other.text; } 7177 toDOM() { return this.top; } 7178 ignoreEvent() { return false; } 7179 get customView() { return CompositionView; } 7180} 7181function nearbyTextNode(node, offset, side) { 7182 for (;;) { 7183 if (node.nodeType == 3) 7184 return node; 7185 if (node.nodeType == 1 && offset > 0 && side <= 0) { 7186 node = node.childNodes[offset - 1]; 7187 offset = maxOffset(node); 7188 } 7189 else if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) { 7190 node = node.childNodes[offset]; 7191 offset = 0; 7192 } 7193 else { 7194 return null; 7195 } 7196 } 7197} 7198function nextToUneditable(node, offset) { 7199 if (node.nodeType != 1) 7200 return 0; 7201 return (offset && node.childNodes[offset - 1].contentEditable == "false" ? 1 /* NextTo.Before */ : 0) | 7202 (offset < node.childNodes.length && node.childNodes[offset].contentEditable == "false" ? 2 /* NextTo.After */ : 0); 7203} 7204class DecorationComparator$1 { 7205 constructor() { 7206 this.changes = []; 7207 } 7208 compareRange(from, to) { addRange(from, to, this.changes); } 7209 comparePoint(from, to) { addRange(from, to, this.changes); } 7210} 7211function findChangedDeco(a, b, diff) { 7212 let comp = new DecorationComparator$1; 7213 RangeSet.compare(a, b, diff, comp); 7214 return comp.changes; 7215} 7216function inUneditable(node, inside) { 7217 for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) { 7218 if (cur.nodeType == 1 && cur.contentEditable == 'false') { 7219 return true; 7220 } 7221 } 7222 return false; 7223} 7224 7225function groupAt(state, pos, bias = 1) {
vendor: 9,436 bytes, lines 7226-7440
7226 let categorize = state.charCategorizer(pos); 7227 let line = state.doc.lineAt(pos), linePos = pos - line.from; 7228 if (line.length == 0) 7229 return EditorSelection.cursor(pos); 7230 if (linePos == 0) 7231 bias = 1; 7232 else if (linePos == line.length) 7233 bias = -1; 7234 let from = linePos, to = linePos; 7235 if (bias < 0) 7236 from = findClusterBreak(line.text, linePos, false); 7237 else 7238 to = findClusterBreak(line.text, linePos); 7239 let cat = categorize(line.text.slice(from, to)); 7240 while (from > 0) { 7241 let prev = findClusterBreak(line.text, from, false); 7242 if (categorize(line.text.slice(prev, from)) != cat) 7243 break; 7244 from = prev; 7245 } 7246 while (to < line.length) { 7247 let next = findClusterBreak(line.text, to); 7248 if (categorize(line.text.slice(to, next)) != cat) 7249 break; 7250 to = next; 7251 } 7252 return EditorSelection.range(from + line.from, to + line.from); 7253} 7254// Search the DOM for the {node, offset} position closest to the given 7255// coordinates. Very inefficient and crude, but can usually be avoided 7256// by calling caret(Position|Range)FromPoint instead. 7257function getdx(x, rect) { 7258 return rect.left > x ? rect.left - x : Math.max(0, x - rect.right); 7259} 7260function getdy(y, rect) { 7261 return rect.top > y ? rect.top - y : Math.max(0, y - rect.bottom); 7262} 7263function yOverlap(a, b) { 7264 return a.top < b.bottom - 1 && a.bottom > b.top + 1; 7265} 7266function upTop(rect, top) { 7267 return top < rect.top ? { top, left: rect.left, right: rect.right, bottom: rect.bottom } : rect; 7268} 7269function upBot(rect, bottom) { 7270 return bottom > rect.bottom ? { top: rect.top, left: rect.left, right: rect.right, bottom } : rect; 7271} 7272function domPosAtCoords(parent, x, y) { 7273 let closest, closestRect, closestX, closestY, closestOverlap = false; 7274 let above, below, aboveRect, belowRect; 7275 for (let child = parent.firstChild; child; child = child.nextSibling) { 7276 let rects = clientRectsFor(child); 7277 for (let i = 0; i < rects.length; i++) { 7278 let rect = rects[i]; 7279 if (closestRect && yOverlap(closestRect, rect)) 7280 rect = upTop(upBot(rect, closestRect.bottom), closestRect.top); 7281 let dx = getdx(x, rect), dy = getdy(y, rect); 7282 if (dx == 0 && dy == 0) 7283 return child.nodeType == 3 ? domPosInText(child, x, y) : domPosAtCoords(child, x, y); 7284 if (!closest || closestY > dy || closestY == dy && closestX > dx) { 7285 closest = child; 7286 closestRect = rect; 7287 closestX = dx; 7288 closestY = dy; 7289 closestOverlap = !dx || (dx > 0 ? i < rects.length - 1 : i > 0); 7290 } 7291 if (dx == 0) { 7292 if (y > rect.bottom && (!aboveRect || aboveRect.bottom < rect.bottom)) { 7293 above = child; 7294 aboveRect = rect; 7295 } 7296 else if (y < rect.top && (!belowRect || belowRect.top > rect.top)) { 7297 below = child; 7298 belowRect = rect; 7299 } 7300 } 7301 else if (aboveRect && yOverlap(aboveRect, rect)) { 7302 aboveRect = upBot(aboveRect, rect.bottom); 7303 } 7304 else if (belowRect && yOverlap(belowRect, rect)) { 7305 belowRect = upTop(belowRect, rect.top); 7306 } 7307 } 7308 } 7309 if (aboveRect && aboveRect.bottom >= y) { 7310 closest = above; 7311 closestRect = aboveRect; 7312 } 7313 else if (belowRect && belowRect.top <= y) { 7314 closest = below; 7315 closestRect = belowRect; 7316 } 7317 if (!closest) 7318 return { node: parent, offset: 0 }; 7319 let clipX = Math.max(closestRect.left, Math.min(closestRect.right, x)); 7320 if (closest.nodeType == 3) 7321 return domPosInText(closest, clipX, y); 7322 if (closestOverlap && closest.contentEditable != "false") 7323 return domPosAtCoords(closest, clipX, y); 7324 let offset = Array.prototype.indexOf.call(parent.childNodes, closest) + 7325 (x >= (closestRect.left + closestRect.right) / 2 ? 1 : 0); 7326 return { node: parent, offset }; 7327} 7328function domPosInText(node, x, y) { 7329 let len = node.nodeValue.length; 7330 let closestOffset = -1, closestDY = 1e9, generalSide = 0; 7331 for (let i = 0; i < len; i++) { 7332 let rects = textRange(node, i, i + 1).getClientRects(); 7333 for (let j = 0; j < rects.length; j++) { 7334 let rect = rects[j]; 7335 if (rect.top == rect.bottom) 7336 continue; 7337 if (!generalSide) 7338 generalSide = x - rect.left; 7339 let dy = (rect.top > y ? rect.top - y : y - rect.bottom) - 1; 7340 if (rect.left - 1 <= x && rect.right + 1 >= x && dy < closestDY) { 7341 let right = x >= (rect.left + rect.right) / 2, after = right; 7342 if (browser.chrome || browser.gecko) { 7343 // Check for RTL on browsers that support getting client 7344 // rects for empty ranges. 7345 let rectBefore = textRange(node, i).getBoundingClientRect(); 7346 if (rectBefore.left == rect.right) 7347 after = !right; 7348 } 7349 if (dy <= 0) 7350 return { node, offset: i + (after ? 1 : 0) }; 7351 closestOffset = i + (after ? 1 : 0); 7352 closestDY = dy; 7353 } 7354 } 7355 } 7356 return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 }; 7357} 7358function posAtCoords(view, { x, y }, precise, bias = -1) { 7359 var _a; 7360 let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop; 7361 let block, { docHeight } = view.viewState; 7362 let yOffset = y - docTop; 7363 if (yOffset < 0) 7364 return 0; 7365 if (yOffset > docHeight) 7366 return view.state.doc.length; 7367 // Scan for a text block near the queried y position 7368 for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) { 7369 block = view.elementAtHeight(yOffset); 7370 if (block.type == BlockType.Text) 7371 break; 7372 for (;;) { 7373 // Move the y position out of this block 7374 yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine; 7375 if (yOffset >= 0 && yOffset <= docHeight) 7376 break; 7377 // If the document consists entirely of replaced widgets, we 7378 // won't find a text block, so return 0 7379 if (bounced) 7380 return precise ? null : 0; 7381 bounced = true; 7382 bias = -bias; 7383 } 7384 } 7385 y = docTop + yOffset; 7386 let lineStart = block.from; 7387 // If this is outside of the rendered viewport, we can't determine a position 7388 if (lineStart < view.viewport.from) 7389 return view.viewport.from == 0 ? 0 : precise ? null : posAtCoordsImprecise(view, content, block, x, y); 7390 if (lineStart > view.viewport.to) 7391 return view.viewport.to == view.state.doc.length ? view.state.doc.length : 7392 precise ? null : posAtCoordsImprecise(view, content, block, x, y); 7393 // Prefer ShadowRootOrDocument.elementFromPoint if present, fall back to document if not 7394 let doc = view.dom.ownerDocument; 7395 let root = view.root.elementFromPoint ? view.root : doc; 7396 let element = root.elementFromPoint(x, y); 7397 if (element && !view.contentDOM.contains(element)) 7398 element = null; 7399 // If the element is unexpected, clip x at the sides of the content area and try again 7400 if (!element) { 7401 x = Math.max(content.left + 1, Math.min(content.right - 1, x)); 7402 element = root.elementFromPoint(x, y); 7403 if (element && !view.contentDOM.contains(element)) 7404 element = null; 7405 } 7406 // There's visible editor content under the point, so we can try 7407 // using caret(Position|Range)FromPoint as a shortcut 7408 let node, offset = -1; 7409 if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) { 7410 if (doc.caretPositionFromPoint) { 7411 let pos = doc.caretPositionFromPoint(x, y); 7412 if (pos) 7413 ({ offsetNode: node, offset } = pos); 7414 } 7415 else if (doc.caretRangeFromPoint) { 7416 let range = doc.caretRangeFromPoint(x, y); 7417 if (range) { 7418 ({ startContainer: node, startOffset: offset } = range); 7419 if (!view.contentDOM.contains(node) || 7420 browser.safari && isSuspiciousSafariCaretResult(node, offset, x) || 7421 browser.chrome && isSuspiciousChromeCaretResult(node, offset, x)) 7422 node = undefined; 7423 } 7424 } 7425 } 7426 // No luck, do our own (potentially expensive) search 7427 if (!node || !view.docView.dom.contains(node)) { 7428 let line = LineView.find(view.docView, lineStart); 7429 if (!line) 7430 return yOffset > block.top + block.height / 2 ? block.to : block.from; 7431 ({ node, offset } = domPosAtCoords(line.dom, x, y)); 7432 } 7433 return view.docView.posFromDOM(node, offset); 7434} 7435function posAtCoordsImprecise(view, contentRect, block, x, y) { 7436 let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth); 7437 if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) { 7438 let line = Math.floor((y - block.top) / view.defaultLineHeight); 7439 into += line * view.viewState.heightOracle.lineLength; 7440 }
7441 let content = view.state.sliceDoc(block.from, block.to); 7442 return block.from + findColumn(content, into, view.state.tabSize); 7443} 7444// In case of a high line height, Safari's caretRangeFromPoint treats 7445// the space between lines as belonging to the last character of the 7446// line before. This is used to detect such a result so that it can be 7447// ignored (issue #401). 7448function isSuspiciousSafariCaretResult(node, offset, x) { 7449 let len; 7450 if (node.nodeType != 3 || offset != (len = node.nodeValue.length)) 7451 return false; 7452 for (let next = node.nextSibling; next; next = next.nextSibling) 7453 if (next.nodeType != 1 || next.nodeName != "BR") 7454 return false; 7455 return textRange(node, len - 1, len).getBoundingClientRect().left > x; 7456} 7457// Chrome will move positions between lines to the start of the next line 7458function isSuspiciousChromeCaretResult(node, offset, x) { 7459 if (offset != 0) 7460 return false; 7461 for (let cur = node;;) { 7462 let parent = cur.parentNode; 7463 if (!parent || parent.nodeType != 1 || parent.firstChild != cur) 7464 return false; 7465 if (parent.classList.contains("cm-line")) 7466 break; 7467 cur = parent; 7468 } 7469 let rect = node.nodeType == 1 ? node.getBoundingClientRect() 7470 : textRange(node, 0, Math.max(node.nodeValue.length, 1)).getBoundingClientRect(); 7471 return x - rect.left > 5; 7472} 7473function moveToLineBoundary(view, start, forward, includeWrap) { 7474 let line = view.state.doc.lineAt(start.head); 7475 let coords = !includeWrap || !view.lineWrapping ? null 7476 : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head); 7477 if (coords) { 7478 let editorRect = view.dom.getBoundingClientRect(); 7479 let direction = view.textDirectionAt(line.from); 7480 let pos = view.posAtCoords({ x: forward == (direction == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1, 7481 y: (coords.top + coords.bottom) / 2 }); 7482 if (pos != null) 7483 return EditorSelection.cursor(pos, forward ? -1 : 1); 7484 } 7485 let lineView = LineView.find(view.docView, start.head); 7486 let end = lineView ? (forward ? lineView.posAtEnd : lineView.posAtStart) : (forward ? line.to : line.from); 7487 return EditorSelection.cursor(end, forward ? -1 : 1); 7488} 7489function moveByChar(view, start, forward, by) { 7490 let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line); 7491 let direction = view.textDirectionAt(line.from); 7492 for (let cur = start, check = null;;) { 7493 let next = moveVisually(line, spans, direction, cur, forward), char = movedOver; 7494 if (!next) { 7495 if (line.number == (forward ? view.state.doc.lines : 1)) 7496 return cur; 7497 char = "\n"; 7498 line = view.state.doc.line(line.number + (forward ? 1 : -1)); 7499 spans = view.bidiSpans(line); 7500 next = EditorSelection.cursor(forward ? line.from : line.to); 7501 } 7502 if (!check) { 7503 if (!by) 7504 return next; 7505 check = by(char); 7506 } 7507 else if (!check(char)) { 7508 return cur; 7509 } 7510 cur = next; 7511 } 7512} 7513function byGroup(view, pos, start) { 7514 let categorize = view.state.charCategorizer(pos); 7515 let cat = categorize(start); 7516 return (next) => { 7517 let nextCat = categorize(next); 7518 if (cat == CharCategory.Space) 7519 cat = nextCat; 7520 return cat == nextCat; 7521 }; 7522} 7523function moveVertically(view, start, forward, distance) { 7524 let startPos = start.head, dir = forward ? 1 : -1; 7525 if (startPos == (forward ? view.state.doc.length : 0)) 7526 return EditorSelection.cursor(startPos, start.assoc); 7527 let goal = start.goalColumn, startY; 7528 let rect = view.contentDOM.getBoundingClientRect(); 7529 let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop; 7530 if (startCoords) { 7531 if (goal == null) 7532 goal = startCoords.left - rect.left; 7533 startY = dir < 0 ? startCoords.top : startCoords.bottom; 7534 } 7535 else { 7536 let line = view.viewState.lineBlockAt(startPos); 7537 if (goal == null) 7538 goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from)); 7539 startY = (dir < 0 ? line.top : line.bottom) + docTop; 7540 } 7541 let resolvedGoal = rect.left + goal; 7542 let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1); 7543 for (let extra = 0;; extra += 10) { 7544 let curY = startY + (dist + extra) * dir; 7545 let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir); 7546 if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos)) 7547 return EditorSelection.cursor(pos, start.assoc, undefined, goal); 7548 } 7549} 7550function skipAtoms(view, oldPos, pos) { 7551 let atoms = view.state.facet(atomicRanges).map(f => f(view)); 7552 for (;;) { 7553 let moved = false;
7554 for (let set of atoms) { 7555 set.between(pos.from - 1, pos.from + 1, (from, to, value) => { 7556 if (pos.from > from && pos.from < to) { 7557 pos = oldPos.head > pos.from ? EditorSelection.cursor(from, 1) : EditorSelection.cursor(to, -1); 7558 moved = true; 7559 } 7560 }); 7561 } 7562 if (!moved) 7563 return pos; 7564 } 7565} 7566 7567// This will also be where dragging info and such goes 7568class InputState { 7569 constructor(view) { 7570 this.lastKeyCode = 0; 7571 this.lastKeyTime = 0; 7572 this.lastTouchTime = 0; 7573 this.lastFocusTime = 0; 7574 this.lastScrollTop = 0; 7575 this.lastScrollLeft = 0; 7576 this.chromeScrollHack = -1; 7577 // On iOS, some keys need to have their default behavior happen 7578 // (after which we retroactively handle them and reset the DOM) to 7579 // avoid messing up the virtual keyboard state. 7580 this.pendingIOSKey = undefined; 7581 this.lastSelectionOrigin = null; 7582 this.lastSelectionTime = 0; 7583 this.lastEscPress = 0; 7584 this.lastContextMenu = 0; 7585 this.scrollHandlers = []; 7586 this.registeredEvents = []; 7587 this.customHandlers = []; 7588 // -1 means not in a composition. Otherwise, this counts the number 7589 // of changes made during the composition. The count is used to 7590 // avoid treating the start state of the composition, before any 7591 // changes have been made, as part of the composition. 7592 this.composing = -1; 7593 // Tracks whether the next change should be marked as starting the 7594 // composition (null means no composition, true means next is the 7595 // first, false means first has already been marked for this 7596 // composition) 7597 this.compositionFirstChange = null; 7598 this.compositionEndedAt = 0; 7599 this.mouseSelection = null; 7600 for (let type in handlers) { 7601 let handler = handlers[type]; 7602 view.contentDOM.addEventListener(type, (event) => { 7603 if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event)) 7604 return; 7605 if (type == "keydown" && this.keydown(view, event)) 7606 return; 7607 if (this.mustFlushObserver(event)) 7608 view.observer.forceFlush(); 7609 if (this.runCustomHandlers(type, view, event)) 7610 event.preventDefault(); 7611 else 7612 handler(view, event); 7613 }, handlerOptions[type]); 7614 this.registeredEvents.push(type); 7615 } 7616 if (browser.chrome && browser.chrome_version == 102) { // FIXME remove at some point 7617 // On Chrome 102, viewport updates somehow stop wheel-based 7618 // scrolling. Turning off pointer events during the scroll seems 7619 // to avoid the issue. 7620 view.scrollDOM.addEventListener("wheel", () => { 7621 if (this.chromeScrollHack < 0) 7622 view.contentDOM.style.pointerEvents = "none"; 7623 else 7624 window.clearTimeout(this.chromeScrollHack); 7625 this.chromeScrollHack = setTimeout(() => { 7626 this.chromeScrollHack = -1; 7627 view.contentDOM.style.pointerEvents = ""; 7628 }, 100); 7629 }, { passive: true }); 7630 } 7631 this.notifiedFocused = view.hasFocus; 7632 // On Safari adding an input event handler somehow prevents an 7633 // issue where the composition vanishes when you press enter. 7634 if (browser.safari) 7635 view.contentDOM.addEventListener("input", () => null); 7636 } 7637 setSelectionOrigin(origin) { 7638 this.lastSelectionOrigin = origin; 7639 this.lastSelectionTime = Date.now(); 7640 } 7641 ensureHandlers(view, plugins) { 7642 var _a; 7643 let handlers; 7644 this.customHandlers = []; 7645 for (let plugin of plugins) 7646 if (handlers = (_a = plugin.update(view).spec) === null || _a === void 0 ? void 0 : _a.domEventHandlers) { 7647 this.customHandlers.push({ plugin: plugin.value, handlers }); 7648 for (let type in handlers) 7649 if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") { 7650 this.registeredEvents.push(type); 7651 view.contentDOM.addEventListener(type, (event) => { 7652 if (!eventBelongsToEditor(view, event)) 7653 return; 7654 if (this.runCustomHandlers(type, view, event)) 7655 event.preventDefault(); 7656 }); 7657 } 7658 } 7659 } 7660 runCustomHandlers(type, view, event) { 7661 for (let set of this.customHandlers) { 7662 let handler = set.handlers[type]; 7663 if (handler) { 7664 try { 7665 if (handler.call(set.plugin, event, view) || event.defaultPrevented) 7666 return true; 7667 } 7668 catch (e) { 7669 logException(view.state, e); 7670 } 7671 } 7672 } 7673 return false;
7674 } 7675 runScrollHandlers(view, event) { 7676 this.lastScrollTop = view.scrollDOM.scrollTop; 7677 this.lastScrollLeft = view.scrollDOM.scrollLeft; 7678 for (let set of this.customHandlers) { 7679 let handler = set.handlers.scroll; 7680 if (handler) { 7681 try { 7682 handler.call(set.plugin, event, view); 7683 } 7684 catch (e) { 7685 logException(view.state, e); 7686 } 7687 } 7688 } 7689 } 7690 keydown(view, event) { 7691 // Must always run, even if a custom handler handled the event 7692 this.lastKeyCode = event.keyCode; 7693 this.lastKeyTime = Date.now(); 7694 if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000) 7695 return true; 7696 // Chrome for Android usually doesn't fire proper key events, but 7697 // occasionally does, usually surrounded by a bunch of complicated 7698 // composition changes. When an enter or backspace key event is 7699 // seen, hold off on handling DOM events for a bit, and then 7700 // dispatch it. 7701 if (browser.android && browser.chrome && !event.synthetic && 7702 (event.keyCode == 13 || event.keyCode == 8)) { 7703 view.observer.delayAndroidKey(event.key, event.keyCode); 7704 return true; 7705 } 7706 // Prevent the default behavior of Enter on iOS makes the 7707 // virtual keyboard get stuck in the wrong (lowercase) 7708 // state. So we let it go through, and then, in 7709 // applyDOMChange, notify key handlers of it and reset to 7710 // the state they produce. 7711 let pending; 7712 if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey && 7713 ((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey || 7714 EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey && !event.shiftKey)) { 7715 this.pendingIOSKey = pending || event; 7716 setTimeout(() => this.flushIOSKey(view), 250); 7717 return true; 7718 } 7719 return false; 7720 } 7721 flushIOSKey(view) { 7722 let key = this.pendingIOSKey; 7723 if (!key) 7724 return false; 7725 this.pendingIOSKey = undefined; 7726 return dispatchKey(view.contentDOM, key.key, key.keyCode); 7727 } 7728 ignoreDuringComposition(event) { 7729 if (!/^key/.test(event.type)) 7730 return false; 7731 if (this.composing > 0) 7732 return true; 7733 // See https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/. 7734 // On some input method editors (IMEs), the Enter key is used to 7735 // confirm character selection. On Safari, when Enter is pressed, 7736 // compositionend and keydown events are sometimes emitted in the 7737 // wrong order. The key event should still be ignored, even when 7738 // it happens after the compositionend event. 7739 if (browser.safari && !browser.ios && Date.now() - this.compositionEndedAt < 100) { 7740 this.compositionEndedAt = 0; 7741 return true; 7742 } 7743 return false; 7744 } 7745 mustFlushObserver(event) { 7746 return event.type == "keydown" && event.keyCode != 229; 7747 } 7748 startMouseSelection(mouseSelection) { 7749 if (this.mouseSelection) 7750 this.mouseSelection.destroy(); 7751 this.mouseSelection = mouseSelection; 7752 } 7753 update(update) { 7754 if (this.mouseSelection) 7755 this.mouseSelection.update(update); 7756 if (update.transactions.length) 7757 this.lastKeyCode = this.lastSelectionTime = 0; 7758 } 7759 destroy() { 7760 if (this.mouseSelection) 7761 this.mouseSelection.destroy(); 7762 } 7763} 7764const PendingKeys = [ 7765 { key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" }, 7766 { key: "Enter", keyCode: 13, inputType: "insertParagraph" }, 7767 { key: "Delete", keyCode: 46, inputType: "deleteContentForward" } 7768]; 7769const EmacsyPendingKeys = "dthko"; 7770// Key codes for modifier keys 7771const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225]; 7772class MouseSelection { 7773 constructor(view, startEvent, style, mustSelect) { 7774 this.view = view; 7775 this.style = style; 7776 this.mustSelect = mustSelect; 7777 this.lastEvent = startEvent; 7778 let doc = view.contentDOM.ownerDocument; 7779 doc.addEventListener("mousemove", this.move = this.move.bind(this)); 7780 doc.addEventListener("mouseup", this.up = this.up.bind(this)); 7781 this.extend = startEvent.shiftKey; 7782 this.multiple = view.state.facet(EditorState.allowMultipleSelections) && addsSelectionRange(view, startEvent); 7783 this.dragMove = dragMovesSelection(view, startEvent); 7784 this.dragging = isInPrimarySelection(view, startEvent) && getClickType(startEvent) == 1 ? null : false;
7785 // When clicking outside of the selection, immediately apply the 7786 // effect of starting the selection 7787 if (this.dragging === false) { 7788 startEvent.preventDefault(); 7789 this.select(startEvent); 7790 } 7791 } 7792 move(event) { 7793 if (event.buttons == 0) 7794 return this.destroy(); 7795 if (this.dragging !== false) 7796 return; 7797 this.select(this.lastEvent = event); 7798 } 7799 up(event) { 7800 if (this.dragging == null) 7801 this.select(this.lastEvent); 7802 if (!this.dragging) 7803 event.preventDefault(); 7804 this.destroy(); 7805 } 7806 destroy() { 7807 let doc = this.view.contentDOM.ownerDocument; 7808 doc.removeEventListener("mousemove", this.move); 7809 doc.removeEventListener("mouseup", this.up); 7810 this.view.inputState.mouseSelection = null; 7811 } 7812 select(event) { 7813 let selection = this.style.get(event, this.extend, this.multiple); 7814 if (this.mustSelect || !selection.eq(this.view.state.selection) || 7815 selection.main.assoc != this.view.state.selection.main.assoc) 7816 this.view.dispatch({ 7817 selection, 7818 userEvent: "select.pointer", 7819 scrollIntoView: true 7820 }); 7821 this.mustSelect = false; 7822 } 7823 update(update) { 7824 if (update.docChanged && this.dragging) 7825 this.dragging = this.dragging.map(update.changes); 7826 if (this.style.update(update)) 7827 setTimeout(() => this.select(this.lastEvent), 20); 7828 } 7829} 7830function addsSelectionRange(view, event) { 7831 let facet = view.state.facet(clickAddsSelectionRange); 7832 return facet.length ? facet[0](event) : browser.mac ? event.metaKey : event.ctrlKey; 7833} 7834function dragMovesSelection(view, event) { 7835 let facet = view.state.facet(dragMovesSelection$1); 7836 return facet.length ? facet[0](event) : browser.mac ? !event.altKey : !event.ctrlKey; 7837} 7838function isInPrimarySelection(view, event) { 7839 let { main } = view.state.selection; 7840 if (main.empty) 7841 return false; 7842 // On boundary clicks, check whether the coordinates are inside the 7843 // selection's client rectangles 7844 let sel = getSelection(view.root); 7845 if (!sel || sel.rangeCount == 0) 7846 return true; 7847 let rects = sel.getRangeAt(0).getClientRects(); 7848 for (let i = 0; i < rects.length; i++) { 7849 let rect = rects[i]; 7850 if (rect.left <= event.clientX && rect.right >= event.clientX && 7851 rect.top <= event.clientY && rect.bottom >= event.clientY) 7852 return true; 7853 } 7854 return false; 7855} 7856function eventBelongsToEditor(view, event) { 7857 if (!event.bubbles) 7858 return true; 7859 if (event.defaultPrevented) 7860 return false; 7861 for (let node = event.target, cView; node != view.contentDOM; node = node.parentNode) 7862 if (!node || node.nodeType == 11 || ((cView = ContentView.get(node)) && cView.ignoreEvent(event))) 7863 return false; 7864 return true; 7865} 7866const handlers = /*@__PURE__*/Object.create(null); 7867const handlerOptions = /*@__PURE__*/Object.create(null); 7868// This is very crude, but unfortunately both these browsers _pretend_ 7869// that they have a clipboard APIâall the objects and methods are 7870// there, they just don't work, and they are hard to test. 7871const brokenClipboardAPI = (browser.ie && browser.ie_version < 15) || 7872 (browser.ios && browser.webkit_version < 604); 7873function capturePaste(view) { 7874 let parent = view.dom.parentNode; 7875 if (!parent) 7876 return; 7877 let target = parent.appendChild(document.createElement("textarea")); 7878 target.style.cssText = "position: fixed; left: -10000px; top: 10px"; 7879 target.focus(); 7880 setTimeout(() => { 7881 view.focus(); 7882 target.remove(); 7883 doPaste(view, target.value); 7884 }, 50); 7885} 7886function doPaste(view, input) { 7887 let { state } = view, changes, i = 1, text = state.toText(input); 7888 let byLine = text.lines == state.selection.ranges.length; 7889 let linewise = lastLinewiseCopy != null && state.selection.ranges.every(r => r.empty) && lastLinewiseCopy == text.toString(); 7890 if (linewise) { 7891 let lastLine = -1; 7892 changes = state.changeByRange(range => { 7893 let line = state.doc.lineAt(range.from); 7894 if (line.from == lastLine) 7895 return { range }; 7896 lastLine = line.from; 7897 let insert = state.toText((byLine ? text.line(i++).text : input) + state.lineBreak); 7898 return { changes: { from: line.from, insert }, 7899 range: EditorSelection.cursor(range.from + insert.length) }; 7900 }); 7901 } 7902 else if (byLine) { 7903 changes = state.changeByRange(range => { 7904 let line = text.line(i++); 7905 return { changes: { from: range.from, to: range.to, insert: line.text }, 7906 range: EditorSelection.cursor(range.from + line.length) }; 7907 }); 7908 } 7909 else { 7910 changes = state.replaceSelection(text); 7911 } 7912 view.dispatch(changes, { 7913 userEvent: "input.paste", 7914 scrollIntoView: true 7915 }); 7916} 7917handlers.keydown = (view, event) => { 7918 view.inputState.setSelectionOrigin("select"); 7919 if (event.keyCode == 27) 7920 view.inputState.lastEscPress = Date.now(); 7921 else if (modifierCodes.indexOf(event.keyCode) < 0) 7922 view.inputState.lastEscPress = 0; 7923}; 7924handlers.touchstart = (view, e) => { 7925 view.inputState.lastTouchTime = Date.now(); 7926 view.inputState.setSelectionOrigin("select.pointer"); 7927}; 7928handlers.touchmove = view => { 7929 view.inputState.setSelectionOrigin("select.pointer"); 7930}; 7931handlerOptions.touchstart = handlerOptions.touchmove = { passive: true }; 7932handlers.mousedown = (view, event) => { 7933 view.observer.flush(); 7934 if (view.inputState.lastTouchTime > Date.now() - 2000) 7935 return; // Ignore touch interaction 7936 let style = null; 7937 for (let makeStyle of view.state.facet(mouseSelectionStyle)) { 7938 style = makeStyle(view, event); 7939 if (style) 7940 break; 7941 } 7942 if (!style && event.button == 0) 7943 style = basicMouseSelection(view, event); 7944 if (style) { 7945 let mustFocus = view.root.activeElement != view.contentDOM; 7946 if (mustFocus) 7947 view.observer.ignore(() => focusPreventScroll(view.contentDOM)); 7948 view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus)); 7949 } 7950}; 7951function rangeForClick(view, pos, bias, type) { 7952 if (type == 1) { // Single click
7953 return EditorSelection.cursor(pos, bias); 7954 } 7955 else if (type == 2) { // Double click 7956 return groupAt(view.state, pos, bias); 7957 } 7958 else { // Triple click 7959 let visual = LineView.find(view.docView, pos), line = view.state.doc.lineAt(visual ? visual.posAtEnd : pos); 7960 let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to; 7961 if (to < view.state.doc.length && to == line.to) 7962 to++; 7963 return EditorSelection.range(from, to); 7964 } 7965} 7966let insideY = (y, rect) => y >= rect.top && y <= rect.bottom; 7967let inside = (x, y, rect) => insideY(y, rect) && x >= rect.left && x <= rect.right; 7968// Try to determine, for the given coordinates, associated with the 7969// given position, whether they are related to the element before or 7970// the element after the position. 7971function findPositionSide(view, pos, x, y) { 7972 let line = LineView.find(view.docView, pos); 7973 if (!line) 7974 return 1; 7975 let off = pos - line.posAtStart; 7976 // Line boundaries point into the line 7977 if (off == 0) 7978 return 1; 7979 if (off == line.length) 7980 return -1; 7981 // Positions on top of an element point at that element 7982 let before = line.coordsAt(off, -1); 7983 if (before && inside(x, y, before)) 7984 return -1; 7985 let after = line.coordsAt(off, 1); 7986 if (after && inside(x, y, after)) 7987 return 1; 7988 // This is probably a line wrap point. Pick before if the point is 7989 // beside it. 7990 return before && insideY(y, before) ? -1 : 1; 7991} 7992function queryPos(view, event) { 7993 let pos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false); 7994 return { pos, bias: findPositionSide(view, pos, event.clientX, event.clientY) }; 7995} 7996const BadMouseDetail = browser.ie && browser.ie_version <= 11; 7997let lastMouseDown = null, lastMouseDownCount = 0, lastMouseDownTime = 0; 7998function getClickType(event) { 7999 if (!BadMouseDetail) 8000 return event.detail; 8001 let last = lastMouseDown, lastTime = lastMouseDownTime; 8002 lastMouseDown = event; 8003 lastMouseDownTime = Date.now(); 8004 return lastMouseDownCount = !last || (lastTime > Date.now() - 400 && Math.abs(last.clientX - event.clientX) < 2 && 8005 Math.abs(last.clientY - event.clientY) < 2) ? (lastMouseDownCount + 1) % 3 : 1; 8006} 8007function basicMouseSelection(view, event) { 8008 let start = queryPos(view, event), type = getClickType(event); 8009 let startSel = view.state.selection; 8010 let last = start, lastEvent = event; 8011 return { 8012 update(update) { 8013 if (update.docChanged) { 8014 start.pos = update.changes.mapPos(start.pos); 8015 startSel = startSel.map(update.changes); 8016 lastEvent = null; 8017 } 8018 }, 8019 get(event, extend, multiple) { 8020 let cur; 8021 if (lastEvent && event.clientX == lastEvent.clientX && event.clientY == lastEvent.clientY) 8022 cur = last; 8023 else { 8024 cur = last = queryPos(view, event); 8025 lastEvent = event; 8026 } 8027 let range = rangeForClick(view, cur.pos, cur.bias, type); 8028 if (start.pos != cur.pos && !extend) { 8029 let startRange = rangeForClick(view, start.pos, start.bias, type); 8030 let from = Math.min(startRange.from, range.from), to = Math.max(startRange.to, range.to); 8031 range = from < range.from ? EditorSelection.range(from, to) : EditorSelection.range(to, from); 8032 } 8033 if (extend) 8034 return startSel.replaceRange(startSel.main.extend(range.from, range.to)); 8035 else if (multiple && startSel.ranges.length > 1 && startSel.ranges.some(r => r.eq(range))) 8036 return removeRange(startSel, range); 8037 else if (multiple) 8038 return startSel.addRange(range); 8039 else 8040 return EditorSelection.create([range]); 8041 } 8042 }; 8043} 8044function removeRange(sel, range) { 8045 for (let i = 0;; i++) { 8046 if (sel.ranges[i].eq(range)) 8047 return EditorSelection.create(sel.ranges.slice(0, i).concat(sel.ranges.slice(i + 1)), sel.mainIndex == i ? 0 : sel.mainIndex - (sel.mainIndex > i ? 1 : 0)); 8048 } 8049} 8050handlers.dragstart = (view, event) => { 8051 let { selection: { main } } = view.state; 8052 let { mouseSelection } = view.inputState; 8053 if (mouseSelection) 8054 mouseSelection.dragging = main; 8055 if (event.dataTransfer) { 8056 event.dataTransfer.setData("Text", view.state.sliceDoc(main.from, main.to)); 8057 event.dataTransfer.effectAllowed = "copyMove"; 8058 } 8059}; 8060function dropText(view, event, text, direct) { 8061 if (!text) 8062 return; 8063 let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false); 8064 event.preventDefault(); 8065 let { mouseSelection } = view.inputState; 8066 let del = direct && mouseSelection && mouseSelection.dragging && mouseSelection.dragMove ? 8067 { from: mouseSelection.dragging.from, to: mouseSelection.dragging.to } : null; 8068 let ins = { from: dropPos, insert: text };
8069 let changes = view.state.changes(del ? [del, ins] : ins); 8070 view.focus(); 8071 view.dispatch({ 8072 changes, 8073 selection: { anchor: changes.mapPos(dropPos, -1), head: changes.mapPos(dropPos, 1) }, 8074 userEvent: del ? "move.drop" : "input.drop" 8075 }); 8076} 8077handlers.drop = (view, event) => { 8078 if (!event.dataTransfer) 8079 return; 8080 if (view.state.readOnly) 8081 return event.preventDefault(); 8082 let files = event.dataTransfer.files; 8083 if (files && files.length) { // For a file drop, read the file's text. 8084 event.preventDefault(); 8085 let text = Array(files.length), read = 0; 8086 let finishFile = () => { 8087 if (++read == files.length) 8088 dropText(view, event, text.filter(s => s != null).join(view.state.lineBreak), false); 8089 }; 8090 for (let i = 0; i < files.length; i++) { 8091 let reader = new FileReader; 8092 reader.onerror = finishFile; 8093 reader.onload = () => { 8094 if (!/[\x00-\x08\x0e-\x1f]{2}/.test(reader.result)) 8095 text[i] = reader.result; 8096 finishFile(); 8097 }; 8098 reader.readAsText(files[i]); 8099 } 8100 } 8101 else { 8102 dropText(view, event, event.dataTransfer.getData("Text"), true); 8103 } 8104}; 8105handlers.paste = (view, event) => { 8106 if (view.state.readOnly) 8107 return event.preventDefault(); 8108 view.observer.flush(); 8109 let data = brokenClipboardAPI ? null : event.clipboardData; 8110 if (data) { 8111 doPaste(view, data.getData("text/plain")); 8112 event.preventDefault(); 8113 } 8114 else { 8115 capturePaste(view); 8116 } 8117}; 8118function captureCopy(view, text) { 8119 // The extra wrapper is somehow necessary on IE/Edge to prevent the 8120 // content from being mangled when it is put onto the clipboard 8121 let parent = view.dom.parentNode; 8122 if (!parent) 8123 return; 8124 let target = parent.appendChild(document.createElement("textarea")); 8125 target.style.cssText = "position: fixed; left: -10000px; top: 10px"; 8126 target.value = text; 8127 target.focus(); 8128 target.selectionEnd = text.length; 8129 target.selectionStart = 0; 8130 setTimeout(() => { 8131 target.remove(); 8132 view.focus(); 8133 }, 50); 8134} 8135function copiedRange(state) { 8136 let content = [], ranges = [], linewise = false; 8137 for (let range of state.selection.ranges) 8138 if (!range.empty) { 8139 content.push(state.sliceDoc(range.from, range.to)); 8140 ranges.push(range); 8141 } 8142 if (!content.length) { 8143 // Nothing selected, do a line-wise copy 8144 let upto = -1; 8145 for (let { from } of state.selection.ranges) { 8146 let line = state.doc.lineAt(from); 8147 if (line.number > upto) { 8148 content.push(line.text); 8149 ranges.push({ from: line.from, to: Math.min(state.doc.length, line.to + 1) }); 8150 } 8151 upto = line.number; 8152 } 8153 linewise = true; 8154 } 8155 return { text: content.join(state.lineBreak), ranges, linewise }; 8156} 8157let lastLinewiseCopy = null; 8158handlers.copy = handlers.cut = (view, event) => { 8159 let { text, ranges, linewise } = copiedRange(view.state); 8160 if (!text && !linewise) 8161 return; 8162 lastLinewiseCopy = linewise ? text : null; 8163 let data = brokenClipboardAPI ? null : event.clipboardData; 8164 if (data) { 8165 event.preventDefault(); 8166 data.clearData(); 8167 data.setData("text/plain", text); 8168 } 8169 else { 8170 captureCopy(view, text); 8171 } 8172 if (event.type == "cut" && !view.state.readOnly) 8173 view.dispatch({ 8174 changes: ranges, 8175 scrollIntoView: true, 8176 userEvent: "delete.cut" 8177 }); 8178}; 8179function updateForFocusChange(view) { 8180 setTimeout(() => { 8181 if (view.hasFocus != view.inputState.notifiedFocused) 8182 view.update([]); 8183 }, 10); 8184} 8185handlers.focus = view => { 8186 view.inputState.lastFocusTime = Date.now(); 8187 // When focusing reset the scroll position, move it back to where it was 8188 if (!view.scrollDOM.scrollTop && (view.inputState.lastScrollTop || view.inputState.lastScrollLeft)) { 8189 view.scrollDOM.scrollTop = view.inputState.lastScrollTop; 8190 view.scrollDOM.scrollLeft = view.inputState.lastScrollLeft; 8191 } 8192 updateForFocusChange(view); 8193}; 8194handlers.blur = view => { 8195 view.observer.clearSelectionRange(); 8196 updateForFocusChange(view); 8197}; 8198handlers.compositionstart = handlers.compositionupdate = view => { 8199 if (view.inputState.compositionFirstChange == null) 8200 view.inputState.compositionFirstChange = true; 8201 if (view.inputState.composing < 0) { 8202 // FIXME possibly set a timeout to clear it again on Android 8203 view.inputState.composing = 0; 8204 } 8205}; 8206handlers.compositionend = view => { 8207 view.inputState.composing = -1; 8208 view.inputState.compositionEndedAt = Date.now(); 8209 view.inputState.compositionFirstChange = null; 8210 if (browser.chrome && browser.android) 8211 view.observer.flushSoon(); 8212 setTimeout(() => { 8213 // Force the composition state to be cleared if it hasn't already been 8214 if (view.inputState.composing < 0 && view.docView.compositionDeco.size) 8215 view.update([]); 8216 }, 50); 8217}; 8218handlers.contextmenu = view => { 8219 view.inputState.lastContextMenu = Date.now(); 8220}; 8221handlers.beforeinput = (view, event) => { 8222 var _a; 8223 // Because Chrome Android doesn't fire useful key events, use 8224 // beforeinput to detect backspace (and possibly enter and delete, 8225 // but those usually don't even seem to fire beforeinput events at 8226 // the moment) and fake a key event for it. 8227 // 8228 // (preventDefault on beforeinput, though supported in the spec, 8229 // seems to do nothing at all on Chrome). 8230 let pending; 8231 if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) { 8232 view.observer.delayAndroidKey(pending.key, pending.keyCode); 8233 if (pending.key == "Backspace" || pending.key == "Delete") {
8234 let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0; 8235 setTimeout(() => { 8236 var _a; 8237 // Backspacing near uneditable nodes on Chrome Android sometimes 8238 // closes the virtual keyboard. This tries to crudely detect 8239 // that and refocus to get it back. 8240 if ((((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0) > startViewHeight + 10 && view.hasFocus) { 8241 view.contentDOM.blur(); 8242 view.focus(); 8243 } 8244 }, 100); 8245 } 8246 } 8247}; 8248 8249const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"]; 8250class HeightOracle { 8251 constructor() { 8252 this.doc = Text.empty; 8253 this.lineWrapping = false; 8254 this.heightSamples = {}; 8255 this.lineHeight = 14; 8256 this.charWidth = 7; 8257 this.lineLength = 30; 8258 // Used to track, during updateHeight, if any actual heights changed 8259 this.heightChanged = false; 8260 } 8261 heightForGap(from, to) { 8262 let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1; 8263 if (this.lineWrapping) 8264 lines += Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength); 8265 return this.lineHeight * lines; 8266 } 8267 heightForLine(length) { 8268 if (!this.lineWrapping) 8269 return this.lineHeight; 8270 let lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / (this.lineLength - 5))); 8271 return lines * this.lineHeight; 8272 } 8273 setDoc(doc) { this.doc = doc; return this; } 8274 mustRefreshForWrapping(whiteSpace) { 8275 return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping; 8276 } 8277 mustRefreshForHeights(lineHeights) { 8278 let newHeight = false; 8279 for (let i = 0; i < lineHeights.length; i++) { 8280 let h = lineHeights[i]; 8281 if (h < 0) { 8282 i++; 8283 } 8284 else if (!this.heightSamples[Math.floor(h * 10)]) { // Round to .1 pixels 8285 newHeight = true; 8286 this.heightSamples[Math.floor(h * 10)] = true; 8287 } 8288 } 8289 return newHeight; 8290 } 8291 refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) { 8292 let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1; 8293 let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping; 8294 this.lineWrapping = lineWrapping; 8295 this.lineHeight = lineHeight; 8296 this.charWidth = charWidth; 8297 this.lineLength = lineLength; 8298 if (changed) { 8299 this.heightSamples = {}; 8300 for (let i = 0; i < knownHeights.length; i++) { 8301 let h = knownHeights[i]; 8302 if (h < 0) 8303 i++; 8304 else 8305 this.heightSamples[Math.floor(h * 10)] = true; 8306 } 8307 } 8308 return changed; 8309 } 8310} 8311// This object is used by `updateHeight` to make DOM measurements 8312// arrive at the right nides. The `heights` array is a sequence of 8313// block heights, starting from position `from`. 8314class MeasuredHeights { 8315 constructor(from, heights) { 8316 this.from = from; 8317 this.heights = heights; 8318 this.index = 0; 8319 } 8320 get more() { return this.index < this.heights.length; } 8321} 8322/** 8323Record used to represent information about a block-level element 8324in the editor view. 8325*/ 8326class BlockInfo { 8327 /** 8328 @internal 8329 */ 8330 constructor( 8331 /** 8332 The start of the element in the document. 8333 */ 8334 from, 8335 /** 8336 The length of the element. 8337 */ 8338 length, 8339 /** 8340 The top position of the element (relative to the top of the 8341 document). 8342 */ 8343 top, 8344 /** 8345 Its height. 8346 */ 8347 height, 8348 /** 8349 The type of element this is. When querying lines, this may be 8350 an array of all the blocks that make up the line. 8351 */ 8352 type) { 8353 this.from = from; 8354 this.length = length; 8355 this.top = top; 8356 this.height = height; 8357 this.type = type; 8358 } 8359 /** 8360 The end of the element as a document position. 8361 */ 8362 get to() { return this.from + this.length; } 8363 /** 8364 The bottom position of the element. 8365 */ 8366 get bottom() { return this.top + this.height; } 8367 /** 8368 @internal 8369 */ 8370 join(other) { 8371 let detail = (Array.isArray(this.type) ? this.type : [this]) 8372 .concat(Array.isArray(other.type) ? other.type : [other]); 8373 return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail); 8374 } 8375} 8376var QueryType = /*@__PURE__*/(function (QueryType) { 8377 QueryType[QueryType["ByPos"] = 0] = "ByPos"; 8378 QueryType[QueryType["ByHeight"] = 1] = "ByHeight"; 8379 QueryType[QueryType["ByPosNoHeight"] = 2] = "ByPosNoHeight"; 8380return QueryType})(QueryType || (QueryType = {})); 8381const Epsilon = 1e-3; 8382class HeightMap { 8383 constructor(length, // The number of characters covered 8384 height, // Height of this part of the document 8385 flags = 2 /* Flag.Outdated */) { 8386 this.length = length; 8387 this.height = height; 8388 this.flags = flags; 8389 } 8390 get outdated() { return (this.flags & 2 /* Flag.Outdated */) > 0; } 8391 set outdated(value) { this.flags = (value ? 2 /* Flag.Outdated */ : 0) | (this.flags & ~2 /* Flag.Outdated */); } 8392 setHeight(oracle, height) { 8393 if (this.height != height) { 8394 if (Math.abs(this.height - height) > Epsilon) 8395 oracle.heightChanged = true; 8396 this.height = height; 8397 } 8398 } 8399 // Base case is to replace a leaf node, which simply builds a tree 8400 // from the new nodes and returns that (HeightMapBranch and 8401 // HeightMapGap override this to actually use from/to) 8402 replace(_from, _to, nodes) { 8403 return HeightMap.of(nodes); 8404 } 8405 // Again, these are base cases, and are overridden for branch and gap nodes. 8406 decomposeLeft(_to, result) { result.push(this); } 8407 decomposeRight(_from, result) { result.push(this); } 8408 applyChanges(decorations, oldDoc, oracle, changes) { 8409 let me = this; 8410 for (let i = changes.length - 1; i >= 0; i--) { 8411 let { fromA, toA, fromB, toB } = changes[i]; 8412 let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0); 8413 let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oldDoc, 0, 0); 8414 toB += end.to - toA; 8415 toA = end.to; 8416 while (i > 0 && start.from <= changes[i - 1].toA) { 8417 fromA = changes[i - 1].fromA; 8418 fromB = changes[i - 1].fromB; 8419 i--; 8420 if (fromA < start.from) 8421 start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0); 8422 } 8423 fromB += start.from - fromA; 8424 fromA = start.from; 8425 let nodes = NodeBuilder.build(oracle, decorations, fromB, toB); 8426 me = me.replace(fromA, toA, nodes); 8427 } 8428 return me.updateHeight(oracle, 0); 8429 } 8430 static empty() { return new HeightMapText(0, 0); } 8431 // nodes uses null values to indicate the position of line breaks. 8432 // There are never line breaks at the start or end of the array, or 8433 // two line breaks next to each other, and the array isn't allowed 8434 // to be empty (same restrictions as return value from the builder). 8435 static of(nodes) { 8436 if (nodes.length == 1) 8437 return nodes[0]; 8438 let i = 0, j = nodes.length, before = 0, after = 0; 8439 for (;;) { 8440 if (i == j) { 8441 if (before > after * 2) { 8442 let split = nodes[i - 1]; 8443 if (split.break) 8444 nodes.splice(--i, 1, split.left, null, split.right); 8445 else 8446 nodes.splice(--i, 1, split.left, split.right); 8447 j += 1 + split.break; 8448 before -= split.size; 8449 } 8450 else if (after > before * 2) { 8451 let split = nodes[j]; 8452 if (split.break) 8453 nodes.splice(j, 1, split.left, null, split.right); 8454 else 8455 nodes.splice(j, 1, split.left, split.right); 8456 j += 2 + split.break; 8457 after -= split.size; 8458 } 8459 else { 8460 break; 8461 } 8462 } 8463 else if (before < after) { 8464 let next = nodes[i++]; 8465 if (next) 8466 before += next.size; 8467 } 8468 else { 8469 let next = nodes[--j]; 8470 if (next) 8471 after += next.size; 8472 } 8473 } 8474 let brk = 0; 8475 if (nodes[i - 1] == null) { 8476 brk = 1; 8477 i--; 8478 } 8479 else if (nodes[i] == null) { 8480 brk = 1; 8481 j++; 8482 } 8483 return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)
8483), brk, HeightMap.of(nodes.slice(j))); 8484 } 8485} 8486HeightMap.prototype.size = 1; 8487class HeightMapBlock extends HeightMap { 8488 constructor(length, height, type) { 8489 super(length, height); 8490 this.type = type; 8491 } 8492 blockAt(_height, _doc, top, offset) { 8493 return new BlockInfo(offset, this.length, top, this.height, this.type); 8494 } 8495 lineAt(_value, _type, doc, top, offset) { 8496 return this.blockAt(0, doc, top, offset); 8497 } 8498 forEachLine(from, to, doc, top, offset, f) { 8499 if (from <= offset + this.length && to >= offset) 8500 f(this.blockAt(0, doc, top, offset)); 8501 } 8502 updateHeight(oracle, offset = 0, _force = false, measured) { 8503 if (measured && measured.from <= offset && measured.more) 8504 this.setHeight(oracle, measured.heights[measured.index++]); 8505 this.outdated = false; 8506 return this; 8507 } 8508 toString() { return `block(${this.length})`; } 8509} 8510class HeightMapText extends HeightMapBlock { 8511 constructor(length, height) { 8512 super(length, height, BlockType.Text); 8513 this.collapsed = 0; // Amount of collapsed content in the line 8514 this.widgetHeight = 0; // Maximum inline widget height 8515 } 8516 replace(_from, _to, nodes) { 8517 let node = nodes[0]; 8518 if (nodes.length == 1 && (node instanceof HeightMapText || node instanceof HeightMapGap && (node.flags & 4 /* Flag.SingleLine */)) && 8519 Math.abs(this.length - node.length) < 10) { 8520 if (node instanceof HeightMapGap) 8521 node = new HeightMapText(node.length, this.height); 8522 else 8523 node.height = this.height; 8524 if (!this.outdated) 8525 node.outdated = false; 8526 return node; 8527 } 8528 else { 8529 return HeightMap.of(nodes); 8530 } 8531 } 8532 updateHeight(oracle, offset = 0, force = false, measured) { 8533 if (measured && measured.from <= offset && measured.more) 8534 this.setHeight(oracle, measured.heights[measured.index++]); 8535 else if (force || this.outdated) 8536 this.setHeight(oracle, Math.max(this.widgetHeight, oracle.heightForLine(this.length - this.collapsed))); 8537 this.outdated = false; 8538 return this; 8539 } 8540 toString() { 8541 return `line(${this.length}${this.collapsed ? -this.collapsed : ""}${this.widgetHeight ? ":" + this.widgetHeight : ""})`; 8542 } 8543} 8544class HeightMapGap extends HeightMap { 8545 constructor(length) { super(length, 0); } 8546 lines(doc, offset) { 8547 let firstLine = doc.lineAt(offset).number, lastLine = doc.lineAt(offset + this.length).number; 8548 return { firstLine, lastLine, lineHeight: this.height / (lastLine - firstLine + 1) }; 8549 } 8550 blockAt(height, doc, top, offset) { 8551 let { firstLine, lastLine, lineHeight } = this.lines(doc, offset); 8552 let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / lineHeight))); 8553 let { from, length } = doc.line(firstLine + line); 8554 return new BlockInfo(from, length, top + lineHeight * line, lineHeight, BlockType.Text); 8555 } 8556 lineAt(value, type, doc, top, offset) { 8557 if (type == QueryType.ByHeight) 8558 return this.blockAt(value, doc, top, offset); 8559 if (type == QueryType.ByPosNoHeight) { 8560 let { from, to } = doc.lineAt(value); 8561 return new BlockInfo(from, to - from, 0, 0, BlockType.Text); 8562 } 8563 let { firstLine, lineHeight } = this.lines(doc, offset); 8564 let { from, length, number } = doc.lineAt(value); 8565 return new BlockInfo(from, length, top + lineHeight * (number - firstLine), lineHeight, BlockType.Text); 8566 } 8567 forEachLine(from, to, doc, top, offset, f) { 8568 let { firstLine, lineHeight } = this.lines(doc, offset); 8569 for (let pos = Math.max(from, offset), end = Math.min(offset + this.length, to); pos <= end;) { 8570 let line = doc.lineAt(pos); 8571 if (pos == from) 8572 top += lineHeight * (line.number - firstLine); 8573 f(new BlockInfo(line.from, line.length, top, lineHeight, BlockType.Text)); 8574 top += lineHeight; 8575 pos = line.to + 1; 8576 } 8577 } 8578 replace(from, to, nodes) { 8579 let after = this.length - to; 8580 if (after > 0) { 8581 let last = nodes[nodes.length - 1]; 8582 if (last instanceof HeightMapGap) 8583 nodes[nodes.length - 1] = new HeightMapGap(last.length + after); 8584 else 8585 nodes.push(null, new HeightMapGap(after - 1)); 8586 } 8587 if (from > 0) { 8588 let first = nodes[0]; 8589 if (first instanceof HeightMapGap) 8590 nodes[0] = new HeightMapGap(from + first.length); 8591 else 8592 nodes.unshift(new HeightMapGap(from - 1), null); 8593 } 8594 return HeightMap.of(nodes); 8595 } 8596 decomposeLeft(to, result) { 8597 result.push(new HeightMapGap(to - 1), null); 8598 } 8599 decomposeRight(from, result) { 8600 result.push(null, new HeightMapGap(this.length - from - 1)); 8601 } 8602 updateHeight(oracle, offset = 0, force = false, measured) { 8603 let end = offset + this.length; 8604 if (measured && measured.from <= offset + this.length && measured.more) { 8605 // Fill in part of this gap with measured lines. We know there 8606 // can't be widgets or collapsed ranges in those lines, because 8607 // they would already have been added to the heightmap (gaps 8608 // only contain plain text). 8609 let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1; 8610 let wasChanged = oracle.heightChanged; 8611 if (measured.from > offset) 8612 nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset)); 8613 while (pos <= end && measured.more) { 8614 let len = oracle.doc.lineAt(pos).length; 8615 if (nodes.length) 8616 nodes.push(null); 8617 let height = measured.heights[measured.index++]; 8618 if (singleHeight == -1) 8619 singleHeight = height; 8620 else if (Math.abs(height - singleHeight) >= Epsilon) 8621 singleHeight = -2; 8622 let line = new HeightMapText(len, height); 8623 line.outdated = false;
vendor: 5,881 bytes, lines 8624-8754
8624 nodes.push(line); 8625 pos += len + 1; 8626 } 8627 if (pos <= end) 8628 nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos)); 8629 let result = HeightMap.of(nodes); 8630 oracle.heightChanged = wasChanged || singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon || 8631 Math.abs(singleHeight - this.lines(oracle.doc, offset).lineHeight) >= Epsilon; 8632 return result; 8633 } 8634 else if (force || this.outdated) { 8635 this.setHeight(oracle, oracle.heightForGap(offset, offset + this.length)); 8636 this.outdated = false; 8637 } 8638 return this; 8639 } 8640 toString() { return `gap(${this.length})`; } 8641} 8642class HeightMapBranch extends HeightMap { 8643 constructor(left, brk, right) { 8644 super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0)); 8645 this.left = left; 8646 this.right = right; 8647 this.size = left.size + right.size; 8648 } 8649 get break() { return this.flags & 1 /* Flag.Break */; } 8650 blockAt(height, doc, top, offset) { 8651 let mid = top + this.left.height; 8652 return height < mid ? this.left.blockAt(height, doc, top, offset) 8653 : this.right.blockAt(height, doc, mid, offset + this.left.length + this.break); 8654 } 8655 lineAt(value, type, doc, top, offset) { 8656 let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break; 8657 let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset; 8658 let base = left ? this.left.lineAt(value, type, doc, top, offset) 8659 : this.right.lineAt(value, type, doc, rightTop, rightOffset); 8660 if (this.break || (left ? base.to < rightOffset : base.from > rightOffset)) 8661 return base; 8662 let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos; 8663 if (left) 8664 return base.join(this.right.lineAt(rightOffset, subQuery, doc, rightTop, rightOffset)); 8665 else 8666 return this.left.lineAt(rightOffset, subQuery, doc, top, offset).join(base); 8667 } 8668 forEachLine(from, to, doc, top, offset, f) { 8669 let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break; 8670 if (this.break) { 8671 if (from < rightOffset) 8672 this.left.forEachLine(from, to, doc, top, offset, f); 8673 if (to >= rightOffset) 8674 this.right.forEachLine(from, to, doc, rightTop, rightOffset, f); 8675 } 8676 else { 8677 let mid = this.lineAt(rightOffset, QueryType.ByPos, doc, top, offset); 8678 if (from < mid.from) 8679 this.left.forEachLine(from, mid.from - 1, doc, top, offset, f); 8680 if (mid.to >= from && mid.from <= to) 8681 f(mid); 8682 if (to > mid.to) 8683 this.right.forEachLine(mid.to + 1, to, doc, rightTop, rightOffset, f); 8684 } 8685 } 8686 replace(from, to, nodes) { 8687 let rightStart = this.left.length + this.break; 8688 if (to < rightStart) 8689 return this.balanced(this.left.replace(from, to, nodes), this.right); 8690 if (from > this.left.length) 8691 return this.balanced(this.left, this.right.replace(from - rightStart, to - rightStart, nodes)); 8692 let result = []; 8693 if (from > 0) 8694 this.decomposeLeft(from, result); 8695 let left = result.length; 8696 for (let node of nodes) 8697 result.push(node); 8698 if (from > 0) 8699 mergeGaps(result, left - 1); 8700 if (to < this.length) { 8701 let right = result.length; 8702 this.decomposeRight(to, result); 8703 mergeGaps(result, right); 8704 } 8705 return HeightMap.of(result); 8706 } 8707 decomposeLeft(to, result) { 8708 let left = this.left.length; 8709 if (to <= left) 8710 return this.left.decomposeLeft(to, result); 8711 result.push(this.left); 8712 if (this.break) { 8713 left++; 8714 if (to >= left) 8715 result.push(null); 8716 } 8717 if (to > left) 8718 this.right.decomposeLeft(to - left, result); 8719 } 8720 decomposeRight(from, result) { 8721 let left = this.left.length, right = left + this.break; 8722 if (from >= right) 8723 return this.right.decomposeRight(from - right, result); 8724 if (from < left) 8725 this.left.decomposeRight(from, result); 8726 if (this.break && from < right) 8727 result.push(null); 8728 result.push(this.right); 8729 } 8730 balanced(left, right) { 8731 if (left.size > 2 * right.size || right.size > 2 * left.size) 8732 return HeightMap.of(this.break ? [left, null, right] : [left, right]); 8733 this.left = left; 8734 this.right = right; 8735 this.height = left.height + right.height; 8736 this.outdated = left.outdated || right.outdated; 8737 this.size = left.size + right.size; 8738 this.length = left.length + this.break + right.length; 8739 return this; 8740 } 8741 updateHeight(oracle, offset = 0, force = false, measured) { 8742 let { left, right } = this, rightStart = offset + left.length + this.break, rebalance = null; 8743 if (measured && measured.from <= offset + left.length && measured.more) 8744 rebalance = left = left.updateHeight(oracle, offset, force, measured); 8745 else 8746 left.updateHeight(oracle, offset, force); 8747 if (measured && measured.from <= rightStart + right.length && measured.more) 8748 rebalance = right = right.updateHeight(oracle, rightStart, force, measured); 8749 else 8750 right.updateHeight(oracle, rightStart, force); 8751 if (rebalance) 8752 return this.balanced(left, right); 8753 this.height = this.left.height + this.right.height; 8754 this.outdated = false;
vendor: 9,134 bytes, lines 8755-8997
8755 return this; 8756 } 8757 toString() { return this.left + (this.break ? " " : "-") + this.right; } 8758} 8759function mergeGaps(nodes, around) { 8760 let before, after; 8761 if (nodes[around] == null && 8762 (before = nodes[around - 1]) instanceof HeightMapGap && 8763 (after = nodes[around + 1]) instanceof HeightMapGap) 8764 nodes.splice(around - 1, 3, new HeightMapGap(before.length + 1 + after.length)); 8765} 8766const relevantWidgetHeight = 5; 8767class NodeBuilder { 8768 constructor(pos, oracle) { 8769 this.pos = pos; 8770 this.oracle = oracle; 8771 this.nodes = []; 8772 this.lineStart = -1; 8773 this.lineEnd = -1; 8774 this.covering = null; 8775 this.writtenTo = pos; 8776 } 8777 get isCovered() { 8778 return this.covering && this.nodes[this.nodes.length - 1] == this.covering; 8779 } 8780 span(_from, to) { 8781 if (this.lineStart > -1) { 8782 let end = Math.min(to, this.lineEnd), last = this.nodes[this.nodes.length - 1]; 8783 if (last instanceof HeightMapText) 8784 last.length += end - this.pos; 8785 else if (end > this.pos || !this.isCovered) 8786 this.nodes.push(new HeightMapText(end - this.pos, -1)); 8787 this.writtenTo = end; 8788 if (to > end) { 8789 this.nodes.push(null); 8790 this.writtenTo++; 8791 this.lineStart = -1; 8792 } 8793 } 8794 this.pos = to; 8795 } 8796 point(from, to, deco) { 8797 if (from < to || deco.heightRelevant) { 8798 let height = deco.widget ? deco.widget.estimatedHeight : 0; 8799 if (height < 0) 8800 height = this.oracle.lineHeight; 8801 let len = to - from; 8802 if (deco.block) { 8803 this.addBlock(new HeightMapBlock(len, height, deco.type)); 8804 } 8805 else if (len || height >= relevantWidgetHeight) { 8806 this.addLineDeco(height, len); 8807 } 8808 } 8809 else if (to > from) { 8810 this.span(from, to); 8811 } 8812 if (this.lineEnd > -1 && this.lineEnd < this.pos) 8813 this.lineEnd = this.oracle.doc.lineAt(this.pos).to; 8814 } 8815 enterLine() { 8816 if (this.lineStart > -1) 8817 return; 8818 let { from, to } = this.oracle.doc.lineAt(this.pos); 8819 this.lineStart = from; 8820 this.lineEnd = to; 8821 if (this.writtenTo < from) { 8822 if (this.writtenTo < from - 1 || this.nodes[this.nodes.length - 1] == null) 8823 this.nodes.push(this.blankContent(this.writtenTo, from - 1)); 8824 this.nodes.push(null); 8825 } 8826 if (this.pos > from) 8827 this.nodes.push(new HeightMapText(this.pos - from, -1)); 8828 this.writtenTo = this.pos; 8829 } 8830 blankContent(from, to) { 8831 let gap = new HeightMapGap(to - from); 8832 if (this.oracle.doc.lineAt(from).to == to) 8833 gap.flags |= 4 /* Flag.SingleLine */; 8834 return gap; 8835 } 8836 ensureLine() { 8837 this.enterLine(); 8838 let last = this.nodes.length ? this.nodes[this.nodes.length - 1] : null; 8839 if (last instanceof HeightMapText) 8840 return last; 8841 let line = new HeightMapText(0, -1); 8842 this.nodes.push(line); 8843 return line; 8844 } 8845 addBlock(block) { 8846 this.enterLine(); 8847 if (block.type == BlockType.WidgetAfter && !this.isCovered) 8848 this.ensureLine(); 8849 this.nodes.push(block); 8850 this.writtenTo = this.pos = this.pos + block.length; 8851 if (block.type != BlockType.WidgetBefore) 8852 this.covering = block; 8853 } 8854 addLineDeco(height, length) { 8855 let line = this.ensureLine(); 8856 line.length += length; 8857 line.collapsed += length; 8858 line.widgetHeight = Math.max(line.widgetHeight, height); 8859 this.writtenTo = this.pos = this.pos + length; 8860 } 8861 finish(from) { 8862 let last = this.nodes.length == 0 ? null : this.nodes[this.nodes.length - 1]; 8863 if (this.lineStart > -1 && !(last instanceof HeightMapText) && !this.isCovered) 8864 this.nodes.push(new HeightMapText(0, -1)); 8865 else if (this.writtenTo < this.pos || last == null) 8866 this.nodes.push(this.blankContent(this.writtenTo, this.pos)); 8867 let pos = from; 8868 for (let node of this.nodes) { 8869 if (node instanceof HeightMapText) 8870 node.updateHeight(this.oracle, pos); 8871 pos += node ? node.length : 1; 8872 } 8873 return this.nodes; 8874 } 8875 // Always called with a region that on both sides either stretches 8876 // to a line break or the end of the document. 8877 // The returned array uses null to indicate line breaks, but never 8878 // starts or ends in a line break, or has multiple line breaks next 8879 // to each other. 8880 static build(oracle, decorations, from, to) { 8881 let builder = new NodeBuilder(from, oracle); 8882 RangeSet.spans(decorations, from, to, builder, 0); 8883 return builder.finish(from); 8884 } 8885} 8886function heightRelevantDecoChanges(a, b, diff) { 8887 let comp = new DecorationComparator; 8888 RangeSet.compare(a, b, diff, comp, 0); 8889 return comp.changes; 8890} 8891class DecorationComparator { 8892 constructor() { 8893 this.changes = []; 8894 } 8895 compareRange() { } 8896 comparePoint(from, to, a, b) { 8897 if (from < to || a && a.heightRelevant || b && b.heightRelevant) 8898 addRange(from, to, this.changes, 5); 8899 } 8900} 8901 8902function visiblePixelRange(dom, paddingTop) { 8903 let rect = dom.getBoundingClientRect(); 8904 let doc = dom.ownerDocument, win = doc.defaultView || window; 8905 let left = Math.max(0, rect.left), right = Math.min(win.innerWidth, rect.right); 8906 let top = Math.max(0, rect.top), bottom = Math.min(win.innerHeight, rect.bottom); 8907 for (let parent = dom.parentNode; parent && parent != doc.body;) { 8908 if (parent.nodeType == 1) { 8909 let elt = parent; 8910 let style = window.getComputedStyle(elt); 8911 if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) && 8912 style.overflow != "visible") { 8913 let parentRect = elt.getBoundingClientRect(); 8914 left = Math.max(left, parentRect.left); 8915 right = Math.min(right, parentRect.right); 8916 top = Math.max(top, parentRect.top); 8917 bottom = parent == dom.parentNode ? parentRect.bottom : Math.min(bottom, parentRect.bottom); 8918 } 8919 parent = style.position == "absolute" || style.position == "fixed" ? elt.offsetParent : elt.parentNode; 8920 } 8921 else if (parent.nodeType == 11) { // Shadow root 8922 parent = parent.host; 8923 } 8924 else { 8925 break; 8926 } 8927 } 8928 return { left: left - rect.left, right: Math.max(left, right) - rect.left, 8929 top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) }; 8930} 8931function fullPixelRange(dom, paddingTop) { 8932 let rect = dom.getBoundingClientRect(); 8933 return { left: 0, right: rect.right - rect.left, 8934 top: paddingTop, bottom: rect.bottom - (rect.top + paddingTop) }; 8935} 8936// Line gaps are placeholder widgets used to hide pieces of overlong 8937// lines within the viewport, as a kludge to keep the editor 8938// responsive when a ridiculously long line is loaded into it. 8939class LineGap { 8940 constructor(from, to, size) { 8941 this.from = from; 8942 this.to = to; 8943 this.size = size; 8944 } 8945 static same(a, b) { 8946 if (a.length != b.length) 8947 return false; 8948 for (let i = 0; i < a.length; i++) { 8949 let gA = a[i], gB = b[i]; 8950 if (gA.from != gB.from || gA.to != gB.to || gA.size != gB.size) 8951 return false; 8952 } 8953 return true; 8954 } 8955 draw(wrapping) { 8956 return Decoration.replace({ widget: new LineGapWidget(this.size, wrapping) }).range(this.from, this.to); 8957 } 8958} 8959class LineGapWidget extends WidgetType { 8960 constructor(size, vertical) { 8961 super(); 8962 this.size = size; 8963 this.vertical = vertical; 8964 } 8965 eq(other) { return other.size == this.size && other.vertical == this.vertical; } 8966 toDOM() { 8967 let elt = document.createElement("div"); 8968 if (this.vertical) { 8969 elt.style.height = this.size + "px"; 8970 } 8971 else { 8972 elt.style.width = this.size + "px"; 8973 elt.style.height = "2px"; 8974 elt.style.display = "inline-block"; 8975 } 8976 return elt; 8977 } 8978 get estimatedHeight() { return this.vertical ? this.size : -1; } 8979} 8980class ViewState { 8981 constructor(state) { 8982 this.state = state; 8983 // These are contentDOM-local coordinates 8984 this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 }; 8985 this.inView = true; 8986 this.paddingTop = 0; 8987 this.paddingBottom = 0; 8988 this.contentDOMWidth = 0; 8989 this.contentDOMHeight = 0; 8990 this.editorHeight = 0; 8991 this.editorWidth = 0; 8992 this.heightOracle = new HeightOracle; 8993 // See VP.MaxDOMHeight 8994 this.scaler = IdScaler; 8995 this.scrollTarget = null; 8996 // Briefly set to true when printing, to disable viewport limiting 8997 this.printing = false;
8998 // Flag set when editor content was redrawn, so that the next 8999 // measure stage knows it must read DOM layout 9000 this.mustMeasureContent = true; 9001 this.defaultTextDirection = Direction.LTR; 9002 this.visibleRanges = []; 9003 // Cursor 'assoc' is only significant when the cursor is on a line 9004 // wrap point, where it must stick to the character that it is 9005 // associated with. Since browsers don't provide a reasonable 9006 // interface to set or query this, when a selection is set that 9007 // might cause this to be significant, this flag is set. The next 9008 // measure phase will check whether the cursor is on a line-wrapping 9009 // boundary and, if so, reset it to make sure it is positioned in 9010 // the right place. 9011 this.mustEnforceCursorAssoc = false; 9012 this.stateDeco = state.facet(decorations).filter(d => typeof d != "function"); 9013 this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]); 9014 this.viewport = this.getViewport(0, null); 9015 this.updateViewportLines(); 9016 this.updateForViewport(); 9017 this.lineGaps = this.ensureLineGaps([]); 9018 this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false))); 9019 this.computeVisibleRanges(); 9020 } 9021 updateForViewport() { 9022 let viewports = [this.viewport], { main } = this.state.selection; 9023 for (let i = 0; i <= 1; i++) { 9024 let pos = i ? main.head : main.anchor; 9025 if (!viewports.some(({ from, to }) => pos >= from && pos <= to)) { 9026 let { from, to } = this.lineBlockAt(pos); 9027 viewports.push(new Viewport(from, to)); 9028 } 9029 } 9030 this.viewports = viewports.sort((a, b) => a.from - b.from); 9031 this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler : 9032 new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports); 9033 } 9034 updateViewportLines() { 9035 this.viewportLines = []; 9036 this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => { 9037 this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler)); 9038 }); 9039 } 9040 update(update, scrollTarget = null) { 9041 this.state = update.state; 9042 let prevDeco = this.stateDeco; 9043 this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function"); 9044 let contentChanges = update.changedRanges; 9045 let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length))); 9046 let prevHeight = this.heightMap.height; 9047 this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges); 9048 if (this.heightMap.height != prevHeight) 9049 update.flags |= 2 /* UpdateFlag.Height */; 9050 let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport; 9051 if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) || 9052 !this.viewportIsAppropriate(viewport)) 9053 viewport = this.getViewport(0, scrollTarget); 9054 let updateLines = !update.changes.empty || (update.flags & 2 /* UpdateFlag.Height */) || 9055 viewport.from != this.viewport.from || viewport.to != this.viewport.to; 9056 this.viewport = viewport; 9057 this.updateForViewport(); 9058 if (updateLines) 9059 this.updateViewportLines(); 9060 if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1)) 9061 this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes))); 9062 update.flags |= this.computeVisibleRanges(); 9063 if (scrollTarget) 9064 this.scrollTarget = scrollTarget; 9065 if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping && 9066 update.state.selection.main.empty && update.state.selection.main.assoc && 9067 !update.state.facet(nativeSelectionHidden))
9068 this.mustEnforceCursorAssoc = true; 9069 } 9070 measure(view) { 9071 let dom = view.contentDOM, style = window.getComputedStyle(dom); 9072 let oracle = this.heightOracle; 9073 let whiteSpace = style.whiteSpace; 9074 this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR; 9075 let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace); 9076 let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight; 9077 this.contentDOMHeight = dom.clientHeight; 9078 this.mustMeasureContent = false; 9079 let result = 0, bias = 0; 9080 // Vertical padding 9081 let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0; 9082 if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) { 9083 this.paddingTop = paddingTop; 9084 this.paddingBottom = paddingBottom; 9085 result |= 8 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */; 9086 } 9087 if (this.editorWidth != view.scrollDOM.clientWidth) { 9088 if (oracle.lineWrapping) 9089 measureContent = true; 9090 this.editorWidth = view.scrollDOM.clientWidth; 9091 result |= 8 /* UpdateFlag.Geometry */; 9092 } 9093 // Pixel viewport 9094 let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop); 9095 let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom; 9096 this.pixelViewport = pixelViewport; 9097 let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left; 9098 if (inView != this.inView) { 9099 this.inView = inView; 9100 if (inView) 9101 measureContent = true; 9102 } 9103 if (!this.inView && !this.scrollTarget) 9104 return 0; 9105 let contentWidth = dom.clientWidth; 9106 if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) { 9107 this.contentDOMWidth = contentWidth; 9108 this.editorHeight = view.scrollDOM.clientHeight; 9109 result |= 8 /* UpdateFlag.Geometry */; 9110 } 9111 if (measureContent) { 9112 let lineHeights = view.docView.measureVisibleLineHeights(this.viewport); 9113 if (oracle.mustRefreshForHeights(lineHeights)) 9114 refresh = true; 9115 if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) { 9116 let { lineHeight, charWidth } = view.docView.measureTextSize(); 9117 refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights); 9118 if (refresh) { 9119 view.docView.minWidth = 0; 9120 result |= 8 /* UpdateFlag.Geometry */; 9121 } 9122 } 9123 if (dTop > 0 && dBottom > 0) 9124 bias = Math.max(dTop, dBottom); 9125 else if (dTop < 0 && dBottom < 0) 9126 bias = Math.min(dTop, dBottom); 9127 oracle.heightChanged = false; 9128 for (let vp of this.viewports) { 9129 let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp); 9130 this.heightMap = refresh 9131 ? HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle, [new ChangedRange(0, 0, 0, view.state.doc.length)]) 9132 : this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights)); 9133 } 9134 if (oracle.heightChanged) 9135 result |= 2 /* UpdateFlag.Height */; 9136 } 9137 let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) || 9138 this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to); 9139 if (viewportChange) 9140 this.viewport = this.getViewport(bias, this.scrollTarget); 9141 this.updateForViewport(); 9142 if ((result & 2 /* UpdateFlag.Height */) || viewportChange) 9143 this.updateViewportLines(); 9144 if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1)) 9145 this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps, view)); 9146 result |= this.computeVisibleRanges();
vendor: 6,897 bytes, lines 9147-9264
9147 if (this.mustEnforceCursorAssoc) { 9148 this.mustEnforceCursorAssoc = false; 9149 // This is done in the read stage, because moving the selection 9150 // to a line end is going to trigger a layout anyway, so it 9151 // can't be a pure write. It should be rare that it does any 9152 // writing. 9153 view.docView.enforceCursorAssoc(); 9154 } 9155 return result; 9156 } 9157 get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top); } 9158 get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom); } 9159 getViewport(bias, scrollTarget) { 9160 // This will divide VP.Margin between the top and the 9161 // bottom, depending on the bias (the change in viewport position 9162 // since the last update). It'll hold a number between 0 and 1 9163 let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* VP.Margin */ / 2)); 9164 let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this; 9165 let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* VP.Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* VP.Margin */, QueryType.ByHeight, doc, 0, 0).to); 9166 // If scrollTarget is given, make sure the viewport includes that position 9167 if (scrollTarget) { 9168 let { head } = scrollTarget.range; 9169 if (head < viewport.from || head > viewport.to) { 9170 let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top); 9171 let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos; 9172 if (scrollTarget.y == "center") 9173 topPos = (block.top + block.bottom) / 2 - viewHeight / 2; 9174 else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from) 9175 topPos = block.top; 9176 else 9177 topPos = block.bottom - viewHeight; 9178 viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* VP.Margin */ / 2, QueryType.ByHeight, doc, 0, 0).to); 9179 } 9180 } 9181 return viewport; 9182 } 9183 mapViewport(viewport, changes) { 9184 let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1); 9185 return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0).to); 9186 } 9187 // Checks if a given viewport covers the visible part of the 9188 // document and not too much beyond that. 9189 viewportIsAppropriate({ from, to }, bias = 0) { 9190 if (!this.inView) 9191 return true; 9192 let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0); 9193 let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0); 9194 let { visibleTop, visibleBottom } = this; 9195 return (from == 0 || top <= visibleTop - Math.max(10 /* VP.MinCoverMargin */, Math.min(-bias, 250 /* VP.MaxCoverMargin */))) && 9196 (to == this.state.doc.length || 9197 bottom >= visibleBottom + Math.max(10 /* VP.MinCoverMargin */, Math.min(bias, 250 /* VP.MaxCoverMargin */))) && 9198 (top > visibleTop - 2 * 1000 /* VP.Margin */ && bottom < visibleBottom + 2 * 1000 /* VP.Margin */); 9199 } 9200 mapLineGaps(gaps, changes) { 9201 if (!gaps.length || changes.empty) 9202 return gaps; 9203 let mapped = []; 9204 for (let gap of gaps) 9205 if (!changes.touchesRange(gap.from, gap.to)) 9206 mapped.push(new LineGap(changes.mapPos(gap.from), changes.mapPos(gap.to), gap.size)); 9207 return mapped; 9208 } 9209 // Computes positions in the viewport where the start or end of a 9210 // line should be hidden, trying to reuse existing line gaps when 9211 // appropriate to avoid unneccesary redraws. 9212 // Uses crude character-counting for the positioning and sizing, 9213 // since actual DOM coordinates aren't always available and 9214 // predictable. Relies on generous margins (see LG.Margin) to hide 9215 // the artifacts this might produce from the user. 9216 ensureLineGaps(current, mayMeasure) { 9217 let wrapping = this.heightOracle.lineWrapping; 9218 let margin = wrapping ? 10000 /* LG.MarginWrap */ : 2000 /* LG.Margin */, halfMargin = margin >> 1, doubleMargin = margin << 1; 9219 // The non-wrapping logic won't work at all in predominantly right-to-left text. 9220 if (this.defaultTextDirection != Direction.LTR && !wrapping) 9221 return []; 9222 let gaps = []; 9223 let addGap = (from, to, line, structure) => { 9224 if (to - from < halfMargin) 9225 return; 9226 let sel = this.state.selection.main, avoid = [sel.from]; 9227 if (!sel.empty) 9228 avoid.push(sel.to); 9229 for (let pos of avoid) { 9230 if (pos > from && pos < to) { 9231 addGap(from, pos - 10 /* LG.SelectionMargin */, line, structure); 9232 addGap(pos + 10 /* LG.SelectionMargin */, to, line, structure); 9233 return; 9234 } 9235 } 9236 let gap = find(current, gap => gap.from >= line.from && gap.to <= line.to && 9237 Math.abs(gap.from - from) < halfMargin && Math.abs(gap.to - to) < halfMargin && 9238 !avoid.some(pos => gap.from < pos && gap.to > pos)); 9239 if (!gap) { 9240 // When scrolling down, snap gap ends to line starts to avoid shifts in wrapping 9241 if (to < line.to && mayMeasure && wrapping && 9242 mayMeasure.visibleRanges.some(r => r.from <= to && r.to >= to)) { 9243 let lineStart = mayMeasure.moveToLineBoundary(EditorSelection.cursor(to), false, true).head; 9244 if (lineStart > from) 9245 to = lineStart; 9246 } 9247 gap = new LineGap(from, to, this.gapSize(line, from, to, structure)); 9248 } 9249 gaps.push(gap); 9250 }; 9251 for (let line of this.viewportLines) { 9252 if (line.length < doubleMargin) 9253 continue; 9254 let structure = lineStructure(line.from, line.to, this.stateDeco); 9255 if (structure.total < doubleMargin) 9256 continue; 9257 let target = this.scrollTarget ? this.scrollTarget.range.head : null; 9258 let viewFrom, viewTo; 9259 if (wrapping) { 9260 let marginHeight = (margin / this.heightOracle.lineLength) * this.heightOracle.lineHeight; 9261 let top, bot; 9262 if (target != null) { 9263 let targetFrac = findFraction(structure, target); 9264 let spaceFrac = ((this.visibleBottom - this.visibleTop) / 2 + marginHeight) / line.he
9264ight; 9265 top = targetFrac - spaceFrac; 9266 bot = targetFrac + spaceFrac; 9267 } 9268 else { 9269 top = (this.visibleTop - line.top - marginHeight) / line.height; 9270 bot = (this.visibleBottom - line.top + marginHeight) / line.height; 9271 } 9272 viewFrom = findPosition(structure, top); 9273 viewTo = findPosition(structure, bot); 9274 } 9275 else { 9276 let totalWidth = structure.total * this.heightOracle.charWidth; 9277 let marginWidth = margin * this.heightOracle.charWidth; 9278 let left, right; 9279 if (target != null) { 9280 let targetFrac = findFraction(structure, target); 9281 let spaceFrac = ((this.pixelViewport.right - this.pixelViewport.left) / 2 + marginWidth) / totalWidth; 9282 left = targetFrac - spaceFrac; 9283 right = targetFrac + spaceFrac; 9284 } 9285 else { 9286 left = (this.pixelViewport.left - marginWidth) / totalWidth; 9287 right = (this.pixelViewport.right + marginWidth) / totalWidth; 9288 } 9289 viewFrom = findPosition(structure, left); 9290 viewTo = findPosition(structure, right); 9291 } 9292 if (viewFrom > line.from) 9293 addGap(line.from, viewFrom, line, structure); 9294 if (viewTo < line.to) 9295 addGap(viewTo, line.to, line, structure); 9296 } 9297 return gaps; 9298 } 9299 gapSize(line, from, to, structure) { 9300 let fraction = findFraction(structure, to) - findFraction(structure, from); 9301 if (this.heightOracle.lineWrapping) { 9302 return line.height * fraction; 9303 } 9304 else { 9305 return structure.total * this.heightOracle.charWidth * fraction; 9306 } 9307 } 9308 updateLineGaps(gaps) { 9309 if (!LineGap.same(gaps, this.lineGaps)) { 9310 this.lineGaps = gaps; 9311 this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this.heightOracle.lineWrapping))); 9312 } 9313 } 9314 computeVisibleRanges() { 9315 let deco = this.stateDeco; 9316 if (this.lineGaps.length) 9317 deco = deco.concat(this.lineGapDeco); 9318 let ranges = []; 9319 RangeSet.spans(deco, this.viewport.from, this.viewport.to, { 9320 span(from, to) { ranges.push({ from, to }); }, 9321 point() { } 9322 }, 20); 9323 let changed = ranges.length != this.visibleRanges.length || 9324 this.visibleRanges.some((r, i) => r.from != ranges[i].from || r.to != ranges[i].to); 9325 this.visibleRanges = ranges; 9326 return changed ? 4 /* UpdateFlag.Viewport */ : 0; 9327 } 9328 lineBlockAt(pos) { 9329 return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) || 9330 scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, 0, 0), this.scaler); 9331 } 9332 lineBlockAtHeight(height) { 9333 return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.state.doc, 0, 0), this.scaler); 9334 } 9335 elementAtHeight(height) { 9336 return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler); 9337 } 9338 get docHeight() { 9339 return this.scaler.toDOM(this.heightMap.height); 9340 } 9341 get contentHeight() { 9342 return this.docHeight + this.paddingTop + this.paddingBottom; 9343 } 9344} 9345class Viewport { 9346 constructor(from, to) { 9347 this.from = from; 9348 this.to = to; 9349 } 9350} 9351function lineStructure(from, to, stateDeco) { 9352 let ranges = [], pos = from, total = 0; 9353 RangeSet.spans(stateDeco, from, to, { 9354 span() { }, 9355 point(from, to) { 9356 if (from > pos) { 9357 ranges.push({ from: pos, to: from }); 9358 total += from - pos; 9359 } 9360 pos = to; 9361 } 9362 }, 20); // We're only interested in collapsed ranges of a significant size 9363 if (pos < to) { 9364 ranges.push({ from: pos, to }); 9365 total += to - pos; 9366 } 9367 return { total, ranges }; 9368} 9369function findPosition({ total, ranges }, ratio) { 9370 if (ratio <= 0) 9371 return ranges[0].from; 9372 if (ratio >= 1) 9373 return ranges[ranges.length - 1].to; 9374 let dist = Math.floor(total * ratio); 9375 for (let i = 0;; i++) { 9376 let { from, to } = ranges[i], size = to - from; 9377 if (dist <= size) 9378 return from + dist; 9379 dist -= size; 9380 } 9381} 9382function findFraction(structure, pos) {
vendor: 4,179 bytes, lines 9383-9484
9383 let counted = 0; 9384 for (let { from, to } of structure.ranges) { 9385 if (pos <= to) { 9386 counted += pos - from; 9387 break; 9388 } 9389 counted += to - from; 9390 } 9391 return counted / structure.total; 9392} 9393function find(array, f) { 9394 for (let val of array) 9395 if (f(val)) 9396 return val; 9397 return undefined; 9398} 9399// Don't scale when the document height is within the range of what 9400// the DOM can handle. 9401const IdScaler = { 9402 toDOM(n) { return n; }, 9403 fromDOM(n) { return n; }, 9404 scale: 1 9405}; 9406// When the height is too big (> VP.MaxDOMHeight), scale down the 9407// regions outside the viewports so that the total height is 9408// VP.MaxDOMHeight. 9409class BigScaler { 9410 constructor(doc, heightMap, viewports) { 9411 let vpHeight = 0, base = 0, domBase = 0; 9412 this.viewports = viewports.map(({ from, to }) => { 9413 let top = heightMap.lineAt(from, QueryType.ByPos, doc, 0, 0).top; 9414 let bottom = heightMap.lineAt(to, QueryType.ByPos, doc, 0, 0).bottom; 9415 vpHeight += bottom - top; 9416 return { from, to, top, bottom, domTop: 0, domBottom: 0 }; 9417 }); 9418 this.scale = (7000000 /* VP.MaxDOMHeight */ - vpHeight) / (heightMap.height - vpHeight); 9419 for (let obj of this.viewports) { 9420 obj.domTop = domBase + (obj.top - base) * this.scale; 9421 domBase = obj.domBottom = obj.domTop + (obj.bottom - obj.top); 9422 base = obj.bottom; 9423 } 9424 } 9425 toDOM(n) { 9426 for (let i = 0, base = 0, domBase = 0;; i++) { 9427 let vp = i < this.viewports.length ? this.viewports[i] : null; 9428 if (!vp || n < vp.top) 9429 return domBase + (n - base) * this.scale; 9430 if (n <= vp.bottom) 9431 return vp.domTop + (n - vp.top); 9432 base = vp.bottom; 9433 domBase = vp.domBottom; 9434 } 9435 } 9436 fromDOM(n) { 9437 for (let i = 0, base = 0, domBase = 0;; i++) { 9438 let vp = i < this.viewports.length ? this.viewports[i] : null; 9439 if (!vp || n < vp.domTop) 9440 return base + (n - domBase) / this.scale; 9441 if (n <= vp.domBottom) 9442 return vp.top + (n - vp.domTop); 9443 base = vp.bottom; 9444 domBase = vp.domBottom; 9445 } 9446 } 9447} 9448function scaleBlock(block, scaler) { 9449 if (scaler.scale == 1) 9450 return block; 9451 let bTop = scaler.toDOM(block.top), bBottom = scaler.toDOM(block.bottom); 9452 return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block.type) ? block.type.map(b => scaleBlock(b, scaler)) : block.type); 9453} 9454 9455const theme = /*@__PURE__*/Facet.define({ combine: strs => strs.join(" ") }); 9456const darkTheme = /*@__PURE__*/Facet.define({ combine: values => values.indexOf(true) > -1 }); 9457const baseThemeID = /*@__PURE__*/StyleModule.newName(), baseLightID = /*@__PURE__*/StyleModule.newName(), baseDarkID = /*@__PURE__*/StyleModule.newName(); 9458const lightDarkIDs = { "&light": "." + baseLightID, "&dark": "." + baseDarkID }; 9459function buildTheme(main, spec, scopes) { 9460 return new StyleModule(spec, { 9461 finish(sel) { 9462 return /&/.test(sel) ? sel.replace(/&\w*/, m => { 9463 if (m == "&") 9464 return main; 9465 if (!scopes || !scopes[m]) 9466 throw new RangeError(`Unsupported selector: ${m}`); 9467 return scopes[m]; 9468 }) : main + " " + sel; 9469 } 9470 }); 9471} 9472const baseTheme$1$2 = /*@__PURE__*/buildTheme("." + baseThemeID, { 9473 "&.cm-editor": { 9474 position: "relative !important", 9475 boxSizing: "border-box", 9476 "&.cm-focused": { 9477 // Provide a simple default outline to make sure a focused 9478 // editor is visually distinct. Can't leave the default behavior 9479 // because that will apply to the content element, which is 9480 // inside the scrollable container and doesn't include the 9481 // gutters. We also can't use an 'auto' outline, since those 9482 // are, for some reason, drawn behind the element content, which 9483 // will cause things like the active line background to cover 9484 // the outline (#297).
9485 outline: "1px dotted #212121" 9486 }, 9487 display: "flex !important", 9488 flexDirection: "column" 9489 }, 9490 ".cm-scroller": { 9491 display: "flex !important", 9492 alignItems: "flex-start !important", 9493 fontFamily: "monospace", 9494 lineHeight: 1.4, 9495 height: "100%", 9496 overflowX: "auto", 9497 position: "relative", 9498 zIndex: 0 9499 }, 9500 ".cm-content": { 9501 margin: 0, 9502 flexGrow: 2, 9503 flexShrink: 0, 9504 minHeight: "100%", 9505 display: "block", 9506 whiteSpace: "pre", 9507 wordWrap: "normal", 9508 boxSizing: "border-box", 9509 padding: "4px 0", 9510 outline: "none", 9511 "&[contenteditable=true]": { 9512 WebkitUserModify: "read-write-plaintext-only", 9513 } 9514 }, 9515 ".cm-lineWrapping": { 9516 whiteSpace_fallback: "pre-wrap", 9517 whiteSpace: "break-spaces", 9518 wordBreak: "break-word", 9519 overflowWrap: "anywhere", 9520 flexShrink: 1 9521 }, 9522 "&light .cm-content": { caretColor: "black" }, 9523 "&dark .cm-content": { caretColor: "white" }, 9524 ".cm-line": { 9525 display: "block", 9526 padding: "0 2px 0 4px" 9527 }, 9528 ".cm-selectionLayer": { 9529 zIndex: -1, 9530 contain: "size style" 9531 }, 9532 ".cm-selectionBackground": { 9533 position: "absolute", 9534 }, 9535 "&light .cm-selectionBackground": { 9536 background: "#d9d9d9" 9537 }, 9538 "&dark .cm-selectionBackground": { 9539 background: "#222" 9540 }, 9541 "&light.cm-focused .cm-selectionBackground": { 9542 background: "#d7d4f0" 9543 }, 9544 "&dark.cm-focused .cm-selectionBackground": { 9545 background: "#233" 9546 }, 9547 ".cm-cursorLayer": { 9548 zIndex: 100, 9549 contain: "size style", 9550 pointerEvents: "none" 9551 }, 9552 "&.cm-focused .cm-cursorLayer": { 9553 animation: "steps(1) cm-blink 1.2s infinite" 9554 }, 9555 // Two animations defined so that we can switch between them to 9556 // restart the animation without forcing another style 9557 // recomputation. 9558 "@keyframes cm-blink": { "0%": {}, "50%": { opacity: 0 }, "100%": {} }, 9559 "@keyframes cm-blink2": { "0%": {}, "50%": { opacity: 0 }, "100%": {} }, 9560 ".cm-cursor, .cm-dropCursor": { 9561 position: "absolute", 9562 borderLeft: "1.2px solid black", 9563 marginLeft: "-0.6px", 9564 pointerEvents: "none", 9565 }, 9566 ".cm-cursor": { 9567 display: "none" 9568 }, 9569 "&dark .cm-cursor": { 9570 borderLeftColor: "#444" 9571 }, 9572 "&.cm-focused .cm-cursor": { 9573 display: "block" 9574 }, 9575 "&light .cm-activeLine": { backgroundColor: "#cceeff44" }, 9576 "&dark .cm-activeLine": { backgroundColor: "#99eeff33" }, 9577 "&light .cm-specialChar": { color: "red" }, 9578 "&dark .cm-specialChar": { color: "#f78" }, 9579 ".cm-gutters": { 9580 flexShrink: 0, 9581 display: "flex", 9582 height: "100%", 9583 boxSizing: "border-box", 9584 left: 0, 9585 zIndex: 200 9586 }, 9587 "&light .cm-gutters": { 9588 backgroundColor: "#f5f5f5", 9589 color: "#6c6c6c", 9590 borderRight: "1px solid #ddd" 9591 }, 9592 "&dark .cm-gutters": { 9593 backgroundColor: "#333338", 9594 color: "#ccc" 9595 }, 9596 ".cm-gutter": { 9597 display: "flex !important", 9598 flexDirection: "column", 9599 flexShrink: 0, 9600 boxSizing: "border-box", 9601 minHeight: "100%", 9602 overflow: "hidden" 9603 }, 9604 ".cm-gutterElement": { 9605 boxSizing: "border-box" 9606 }, 9607 ".cm-lineNumbers .cm-gutterElement": { 9608 padding: "0 3px 0 5px", 9609 minWidth: "20px", 9610 textAlign: "right", 9611 whiteSpace: "nowrap" 9612 }, 9613 "&light .cm-activeLineGutter": { 9614 backgroundColor: "#e2f2ff" 9615 }, 9616 "&dark .cm-activeLineGutter": { 9617 backgroundColor: "#222227" 9618 }, 9619 ".cm-panels": { 9620 boxSizing: "border-box", 9621 position: "sticky", 9622 left: 0, 9623 right: 0 9624 }, 9625 "&light .cm-panels": { 9626 backgroundColor: "#f5f5f5", 9627 color: "black" 9628 }, 9629 "&light .cm-panels-top": { 9630 borderBottom: "1px solid #ddd" 9631 }, 9632 "&light .cm-panels-bottom": { 9633 borderTop: "1px solid #ddd" 9634 }, 9635 "&dark .cm-panels": { 9636 backgroundColor: "#333338", 9637 color: "white" 9638 }, 9639 ".cm-tab": { 9640 display: "inline-block", 9641 overflow: "hidden", 9642 verticalAlign: "bottom" 9643 }, 9644 ".cm-widgetBuffer": { 9645 verticalAlign: "text-top", 9646 height: "1em", 9647 width: 0, 9648 display: "inline" 9649 }, 9650 ".cm-placeholder": { 9651 color: "#888", 9652 display: "inline-block", 9653 verticalAlign: "top", 9654 }, 9655 ".cm-button": { 9656 verticalAlign: "middle", 9657 color: "inherit", 9658 fontSize: "70%", 9659 padding: ".2em 1em", 9660 borderRadius: "1px" 9661 }, 9662 "&light .cm-button": { 9663 backgroundImage: "linear-gradient(#eff1f5, #d9d9df)", 9664 border: "1px solid #888", 9665 "&:active": { 9666 backgroundImage: "linear-gradient(#b4b4b4, #d0d3d6)" 9667 } 9668 }, 9669 "&dark .cm-button": { 9670 backgroundImage: "linear-gradient(#393939, #111)", 9671 border: "1px solid #888", 9672 "&:active": { 9673 backgroundImage: "linear-gradient(#111, #333)" 9674 } 9675 }, 9676 ".cm-textfield": { 9677 verticalAlign: "middle", 9678 color: "inherit", 9679 fontSize: "70%", 9680 border: "1px solid silver", 9681 padding: ".2em .5em" 9682 }, 9683 "&light .cm-textfield": { 9684 backgroundColor: "white" 9685 }, 9686 "&dark .cm-textfield": { 9687 border: "1px solid #555", 9688 backgroundColor: "inherit" 9689 } 9690}, lightDarkIDs); 9691 9692class DOMChange { 9693 constructor(view, start, end, typeOver) { 9694 this.typeOver = typeOver; 9695 this.bounds = null; 9696 this.text = ""; 9697 let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView; 9698 if (start > -1 && !view.state.readOnly && (this.bounds = view.docView.domBoundsAround(start, end, 0))) { 9699 let selPoints = iHead || iAnchor ? [] : selectionPoints(view); 9700 let reader = new DOMReader(selPoints, view.state); 9701 reader.readRange(this.bounds.startDOM, this.bounds.endDOM); 9702 this.text = reader.text; 9703 this.newSel = selectionFromPoints(selPoints, this.bounds.from); 9704 } 9705 else { 9706 let domSel = view.observer.selectionRange; 9707 let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset || 9708 !contains(view.contentDOM, domSel.focusNode) 9709 ? view.state.selection.main.head 9710 : view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset); 9711 let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset || 9712 !contains(view.contentDOM, domSel.anchorNode) 9713 ? view.state.selection.main.anchor 9714 : view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset); 9715 this.newSel = EditorSelection.single(anchor, head); 9716 } 9717 } 9718} 9719function applyDOMChange(view, domChange) {
9720 let change; 9721 let { newSel } = domChange, sel = view.state.selection.main; 9722 if (domChange.bounds) { 9723 let { from, to } = domChange.bounds; 9724 let preferredPos = sel.from, preferredSide = null; 9725 // Prefer anchoring to end when Backspace is pressed (or, on 9726 // Android, when something was deleted) 9727 if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 || 9728 browser.android && domChange.text.length < to - from) { 9729 preferredPos = sel.to; 9730 preferredSide = "end"; 9731 } 9732 let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), domChange.text, preferredPos - from, preferredSide); 9733 if (diff) { 9734 // Chrome inserts two newlines when pressing shift-enter at the 9735 // end of a line. DomChange drops one of those. 9736 if (browser.chrome && view.inputState.lastKeyCode == 13 && 9737 diff.toB == diff.from + 2 && domChange.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder) 9738 diff.toB--; 9739 change = { from: from + diff.from, to: from + diff.toA, 9740 insert: Text.of(domChange.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) }; 9741 } 9742 } 9743 else if (newSel && (!view.hasFocus || !view.state.facet(editable) || newSel.main.eq(sel))) { 9744 newSel = null; 9745 } 9746 if (!change && !newSel) 9747 return false; 9748 if (!change && domChange.typeOver && !sel.empty && newSel && newSel.main.empty) { 9749 // Heuristic to notice typing over a selected character 9750 change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) }; 9751 } 9752 else if (change && change.from >= sel.from && change.to <= sel.to && 9753 (change.from != sel.from || change.to != sel.to) && 9754 (sel.to - sel.from) - (change.to - change.from) <= 4) { 9755 // If the change is inside the selection and covers most of it, 9756 // assume it is a selection replace (with identical characters at 9757 // the start/end not included in the diff) 9758 change = { 9759 from: sel.from, to: sel.to, 9760 insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to)) 9761 }; 9762 } 9763 else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 && 9764 /^\. ?$/.test(change.insert.toString())) { 9765 // Detect insert-period-on-double-space Mac and Android behavior, 9766 // and transform it into a regular space insert. 9767 if (newSel && change.insert.length == 2) 9768 newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1); 9769 change = { from: sel.from, to: sel.to, insert: Text.of([" "]) }; 9770 } 9771 else if (browser.chrome && change && change.from == change.to && change.from == sel.head && 9772 change.insert.toString() == "\n " && view.lineWrapping) { 9773 // In Chrome, if you insert a space at the start of a wrapped 9774 // line, it will actually insert a newline and a space, causing a 9775 // bogus new line to be created in CodeMirror (#968) 9776 if (newSel) 9777 newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1); 9778 change = { from: sel.from, to: sel.to, insert: Text.of([" "]) }; 9779 } 9780 if (change) { 9781 let startState = view.state; 9782 if (browser.ios && view.inputState.flushIOSKey(view)) 9783 return true; 9784 // Android browsers don't fire reasonable key events for enter, 9785 // backspace, or delete. So this detects changes that look like 9786 // they're caused by those keys, and reinterprets them as key 9787 // events. (Some of these keys are also handled by beforeinput 9788 // events and the pendingAndroidKey mechanism, but that's not 9789 // reliable in all situations.) 9790 if (browser.android && 9791 ((change.from == sel.from && change.to == sel.to && 9792 change.insert.length == 1 && change.insert.lines == 2 && 9793 dispatchKey(view.contentDOM, "Enter", 13)) || 9794 (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 && 9795 dispatchKey(view.contentDOM, "Backspace", 8)) || 9796 (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 && 9797 dispatchKey(view.contentDOM, "Delete", 46)))) 9798 return true; 9799 let text = change.insert.toString(); 9800 if (view.state.facet(inputHandler$1).some(h => h(view, change.from, change.to, text))) 9801 return true; 9802 if (view.inputState.composing >= 0)
9803 view.inputState.composing++; 9804 let tr; 9805 if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 && 9806 (!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) && 9807 view.inputState.composing < 0) { 9808 let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : ""; 9809 let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : ""; 9810 tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after)); 9811 } 9812 else { 9813 let changes = startState.changes(change); 9814 let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength 9815 ? newSel.main : undefined; 9816 // Try to apply a composition change to all cursors 9817 if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 && 9818 change.to <= sel.to && change.to >= sel.to - 10) { 9819 let replaced = view.state.sliceDoc(change.from, change.to); 9820 let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head); 9821 let offset = sel.to - change.to, size = sel.to - sel.from; 9822 tr = startState.changeByRange(range => { 9823 if (range.from == sel.from && range.to == sel.to) 9824 return { changes, range: mainSel || range.map(changes) }; 9825 let to = range.to - offset, from = to - replaced.length; 9826 if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced || 9827 // Unfortunately, there's no way to make multiple 9828 // changes in the same node work without aborting 9829 // composition, so cursors in the composition range are 9830 // ignored. 9831 compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to) 9832 return { range }; 9833 let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to; 9834 return { 9835 changes: rangeChanges, 9836 range: !mainSel ? range.map(rangeChanges) : 9837 EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff)) 9838 }; 9839 }); 9840 } 9841 else { 9842 tr = { 9843 changes, 9844 selection: mainSel && startState.selection.replaceRange(mainSel) 9845 }; 9846 } 9847 } 9848 let userEvent = "input.type"; 9849 if (view.composing) { 9850 userEvent += ".compose"; 9851 if (view.inputState.compositionFirstChange) { 9852 userEvent += ".start"; 9853 view.inputState.compositionFirstChange = false; 9854 } 9855 } 9856 view.dispatch(tr, { scrollIntoView: true, userEvent }); 9857 return true; 9858 } 9859 else if (newSel && !newSel.main.eq(sel)) { 9860 let scrollIntoView = false, userEvent = "select"; 9861 if (view.inputState.lastSelectionTime > Date.now() - 50) { 9862 if (view.inputState.lastSelectionOrigin == "select") 9863 scrollIntoView = true; 9864 userEvent = view.inputState.lastSelectionOrigin; 9865 } 9866 view.dispatch({ selection: newSel, scrollIntoView, userEvent }); 9867 return true; 9868 } 9869 else { 9870 return false; 9871 } 9872} 9873function findDiff(a, b, preferredPos, preferredSide) { 9874 let minLen = Math.min(a.length, b.length); 9875 let from = 0; 9876 while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from)) 9877 from++; 9878 if (from == minLen && a.length == b.length) 9879 return null; 9880 let toA = a.length, toB = b.length; 9881 while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) { 9882 toA--; 9883 toB--; 9884 } 9885 if (preferredSide == "end") { 9886 let adjust = Math.max(0, from - Math.min(toA, toB)); 9887 preferredPos -= toA + adjust - from; 9888 } 9889 if (toA < from && a.length < b.length) { 9890 let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0; 9891 from -= move; 9892 toB = from + (toB - toA); 9893 toA = from; 9894 } 9895 else if (toB < from) { 9896 let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0; 9897 from -= move; 9898 toA = from + (toA - toB); 9899 toB = from; 9900 } 9901 return { from, toA, toB }; 9902} 9903function selectionPoints(view) { 9904 let result = []; 9905 if (view.root.activeElement != view.contentDOM) 9906 return result; 9907 let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange; 9908 if (anchorNode) { 9909 result.push(new DOMPoint(anchorNode, anchorOffset)); 9910 if (focusNode != anchorNode || focusOffset != anchorOffset) 9911 result.push(new DOMPoint(focusNode, focusOffset)); 9912 } 9913 return result; 9914} 9915function selectionFromPoints(points, base) { 9916 if (points.length == 0) 9917 return null; 9918 let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor; 9919 return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base, head + base) : null; 9920} 9921 9922const observeOptions = { 9923 childList: true, 9924 characterData: true, 9925 subtree: true, 9926 attributes: true, 9927 characterDataOldValue: true 9928}; 9929// IE11 has very broken mutation observers, so we also listen to 9930// DOMCharacterDataModified there 9931const useCharData = browser.ie && browser.ie_version <= 11; 9932class DOMObserver { 9933 constructor(view) { 9934 this.view = view; 9935 this.active = false;
vendor: 4,701 bytes, lines 9936-10040
9936 // The known selection. Kept in our own object, as opposed to just 9937 // directly accessing the selection because: 9938 // - Safari doesn't report the right selection in shadow DOM 9939 // - Reading from the selection forces a DOM layout 9940 // - This way, we can ignore selectionchange events if we have 9941 // already seen the 'new' selection 9942 this.selectionRange = new DOMSelectionState; 9943 // Set when a selection change is detected, cleared on flush 9944 this.selectionChanged = false; 9945 this.delayedFlush = -1; 9946 this.resizeTimeout = -1; 9947 this.queue = []; 9948 this.delayedAndroidKey = null; 9949 this.flushingAndroidKey = -1; 9950 this.lastChange = 0; 9951 this.scrollTargets = []; 9952 this.intersection = null; 9953 this.resize = null; 9954 this.intersecting = false; 9955 this.gapIntersection = null; 9956 this.gaps = []; 9957 // Timeout for scheduling check of the parents that need scroll handlers 9958 this.parentCheck = -1; 9959 this.dom = view.contentDOM; 9960 this.observer = new MutationObserver(mutations => { 9961 for (let mut of mutations) 9962 this.queue.push(mut); 9963 // IE11 will sometimes (on typing over a selection or 9964 // backspacing out a single character text node) call the 9965 // observer callback before actually updating the DOM. 9966 // 9967 // Unrelatedly, iOS Safari will, when ending a composition, 9968 // sometimes first clear it, deliver the mutations, and then 9969 // reinsert the finished text. CodeMirror's handling of the 9970 // deletion will prevent the reinsertion from happening, 9971 // breaking composition. 9972 if ((browser.ie && browser.ie_version <= 11 || browser.ios && view.composing) && 9973 mutations.some(m => m.type == "childList" && m.removedNodes.length || 9974 m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length)) 9975 this.flushSoon(); 9976 else 9977 this.flush(); 9978 }); 9979 if (useCharData) 9980 this.onCharData = (event) => { 9981 this.queue.push({ target: event.target, 9982 type: "characterData", 9983 oldValue: event.prevValue }); 9984 this.flushSoon(); 9985 }; 9986 this.onSelectionChange = this.onSelectionChange.bind(this); 9987 this.onResize = this.onResize.bind(this); 9988 this.onPrint = this.onPrint.bind(this); 9989 this.onScroll = this.onScroll.bind(this); 9990 if (typeof ResizeObserver == "function") { 9991 this.resize = new ResizeObserver(() => { 9992 var _a; 9993 if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75) 9994 this.onResize(); 9995 }); 9996 this.resize.observe(view.scrollDOM); 9997 } 9998 this.addWindowListeners(this.win = view.win); 9999 this.start(); 10000 if (typeof IntersectionObserver == "function") { 10001 this.intersection = new IntersectionObserver(entries => { 10002 if (this.parentCheck < 0) 10003 this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000); 10004 if (entries.length > 0 && (entries[entries.length - 1].intersectionRatio > 0) != this.intersecting) { 10005 this.intersecting = !this.intersecting; 10006 if (this.intersecting != this.view.inView) 10007 this.onScrollChanged(document.createEvent("Event")); 10008 } 10009 }, {}); 10010 this.intersection.observe(this.dom); 10011 this.gapIntersection = new IntersectionObserver(entries => { 10012 if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0) 10013 this.onScrollChanged(document.createEvent("Event")); 10014 }, {}); 10015 } 10016 this.listenForScroll(); 10017 this.readSelectionRange(); 10018 } 10019 onScrollChanged(e) { 10020 this.view.inputState.runScrollHandlers(this.view, e); 10021 if (this.intersecting) 10022 this.view.measure(); 10023 } 10024 onScroll(e) { 10025 if (this.intersecting) 10026 this.flush(false); 10027 this.onScrollChanged(e); 10028 } 10029 onResize() { 10030 if (this.resizeTimeout < 0) 10031 this.resizeTimeout = setTimeout(() => { 10032 this.resizeTimeout = -1; 10033 this.view.requestMeasure(); 10034 }, 50); 10035 } 10036 onPrint() { 10037 this.view.viewState.printing = true; 10038 this.view.measure(); 10039 setTimeout(() => { 10040 this.view.viewState.printing = false;
vendor: 4,719 bytes, lines 10041-10162
10041 this.view.requestMeasure(); 10042 }, 500); 10043 } 10044 updateGaps(gaps) { 10045 if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) { 10046 this.gapIntersection.disconnect(); 10047 for (let gap of gaps) 10048 this.gapIntersection.observe(gap); 10049 this.gaps = gaps; 10050 } 10051 } 10052 onSelectionChange(event) { 10053 let wasChanged = this.selectionChanged; 10054 if (!this.readSelectionRange() || this.delayedAndroidKey) 10055 return; 10056 let { view } = this, sel = this.selectionRange; 10057 if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(view.dom, sel)) 10058 return; 10059 let context = sel.anchorNode && view.docView.nearest(sel.anchorNode); 10060 if (context && context.ignoreEvent(event)) { 10061 if (!wasChanged) 10062 this.selectionChanged = false; 10063 return; 10064 } 10065 // Deletions on IE11 fire their events in the wrong order, giving 10066 // us a selection change event before the DOM changes are 10067 // reported. 10068 // Chrome Android has a similar issue when backspacing out a 10069 // selection (#645). 10070 if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty && 10071 // (Selection.isCollapsed isn't reliable on IE) 10072 sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset)) 10073 this.flushSoon(); 10074 else 10075 this.flush(false); 10076 } 10077 readSelectionRange() { 10078 let { view } = this; 10079 // The Selection object is broken in shadow roots in Safari. See 10080 // https://github.com/codemirror/dev/issues/414 10081 let range = browser.safari && view.root.nodeType == 11 && 10082 deepActiveElement(this.dom.ownerDocument) == this.dom && 10083 safariSelectionRangeHack(this.view) || getSelection(view.root); 10084 if (!range || this.selectionRange.eq(range)) 10085 return false; 10086 let local = hasSelection(this.dom, range); 10087 // Detect the situation where the browser has, on focus, moved the 10088 // selection to the start of the content element. Reset it to the 10089 // position from the editor state. 10090 if (local && !this.selectionChanged && 10091 view.inputState.lastFocusTime > Date.now() - 200 && 10092 view.inputState.lastTouchTime < Date.now() - 300 && 10093 atElementStart(this.dom, range)) { 10094 this.view.inputState.lastFocusTime = 0; 10095 view.docView.updateSelection(); 10096 return false; 10097 } 10098 this.selectionRange.setRange(range); 10099 if (local) 10100 this.selectionChanged = true; 10101 return true; 10102 } 10103 setSelectionRange(anchor, head) { 10104 this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset); 10105 this.selectionChanged = false; 10106 } 10107 clearSelectionRange() { 10108 this.selectionRange.set(null, 0, null, 0); 10109 } 10110 listenForScroll() { 10111 this.parentCheck = -1; 10112 let i = 0, changed = null; 10113 for (let dom = this.dom; dom;) { 10114 if (dom.nodeType == 1) { 10115 if (!changed && i < this.scrollTargets.length && this.scrollTargets[i] == dom) 10116 i++; 10117 else if (!changed) 10118 changed = this.scrollTargets.slice(0, i); 10119 if (changed) 10120 changed.push(dom); 10121 dom = dom.assignedSlot || dom.parentNode; 10122 } 10123 else if (dom.nodeType == 11) { // Shadow root 10124 dom = dom.host; 10125 } 10126 else { 10127 break; 10128 } 10129 } 10130 if (i < this.scrollTargets.length && !changed) 10131 changed = this.scrollTargets.slice(0, i); 10132 if (changed) { 10133 for (let dom of this.scrollTargets) 10134 dom.removeEventListener("scroll", this.onScroll); 10135 for (let dom of this.scrollTargets = changed) 10136 dom.addEventListener("scroll", this.onScroll); 10137 } 10138 } 10139 ignore(f) { 10140 if (!this.active) 10141 return f(); 10142 try { 10143 this.stop(); 10144 return f(); 10145 } 10146 finally { 10147 this.start(); 10148 this.clear(); 10149 } 10150 } 10151 start() { 10152 if (this.active) 10153 return; 10154 this.observer.observe(this.dom, observeOptions); 10155 if (useCharData) 10156 this.dom.addEventListener("DOMCharacterDataModified", this.onCharData); 10157 this.active = true; 10158 } 10159 stop() { 10160 if (!this.active) 10161 return; 10162 this.active = false;
vendor: 4,137 bytes, lines 10163-10262
10163 this.observer.disconnect(); 10164 if (useCharData) 10165 this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData); 10166 } 10167 // Throw away any pending changes 10168 clear() { 10169 this.processRecords(); 10170 this.queue.length = 0; 10171 this.selectionChanged = false; 10172 } 10173 // Chrome Android, especially in combination with GBoard, not only 10174 // doesn't reliably fire regular key events, but also often 10175 // surrounds the effect of enter or backspace with a bunch of 10176 // composition events that, when interrupted, cause text duplication 10177 // or other kinds of corruption. This hack makes the editor back off 10178 // from handling DOM changes for a moment when such a key is 10179 // detected (via beforeinput or keydown), and then tries to flush 10180 // them or, if that has no effect, dispatches the given key. 10181 delayAndroidKey(key, keyCode) { 10182 var _a; 10183 if (!this.delayedAndroidKey) { 10184 let flush = () => { 10185 let key = this.delayedAndroidKey; 10186 if (key) { 10187 this.clearDelayedAndroidKey(); 10188 if (!this.flush() && key.force) 10189 dispatchKey(this.dom, key.key, key.keyCode); 10190 } 10191 }; 10192 this.flushingAndroidKey = this.view.win.requestAnimationFrame(flush); 10193 } 10194 // Since backspace beforeinput is sometimes signalled spuriously, 10195 // Enter always takes precedence. 10196 if (!this.delayedAndroidKey || key == "Enter") 10197 this.delayedAndroidKey = { 10198 key, keyCode, 10199 // Only run the key handler when no changes are detected if 10200 // this isn't coming right after another change, in which case 10201 // it is probably part of a weird chain of updates, and should 10202 // be ignored if it returns the DOM to its previous state. 10203 force: this.lastChange < Date.now() - 50 || !!((_a = this.delayedAndroidKey) === null || _a === void 0 ? void 0 : _a.force) 10204 }; 10205 } 10206 clearDelayedAndroidKey() { 10207 this.win.cancelAnimationFrame(this.flushingAndroidKey); 10208 this.delayedAndroidKey = null; 10209 this.flushingAndroidKey = -1; 10210 } 10211 flushSoon() { 10212 if (this.delayedFlush < 0) 10213 this.delayedFlush = this.view.win.requestAnimationFrame(() => { this.delayedFlush = -1; this.flush(); }); 10214 } 10215 forceFlush() { 10216 if (this.delayedFlush >= 0) { 10217 this.view.win.cancelAnimationFrame(this.delayedFlush); 10218 this.delayedFlush = -1; 10219 } 10220 this.flush(); 10221 } 10222 processRecords() { 10223 let records = this.queue; 10224 for (let mut of this.observer.takeRecords()) 10225 records.push(mut); 10226 if (records.length) 10227 this.queue = []; 10228 let from = -1, to = -1, typeOver = false; 10229 for (let record of records) { 10230 let range = this.readMutation(record); 10231 if (!range) 10232 continue; 10233 if (range.typeOver) 10234 typeOver = true; 10235 if (from == -1) { 10236 ({ from, to } = range); 10237 } 10238 else { 10239 from = Math.min(range.from, from); 10240 to = Math.max(range.to, to); 10241 } 10242 } 10243 return { from, to, typeOver }; 10244 } 10245 readChange() { 10246 let { from, to, typeOver } = this.processRecords(); 10247 let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange); 10248 if (from < 0 && !newSel) 10249 return null; 10250 if (from > -1) 10251 this.lastChange = Date.now(); 10252 this.view.inputState.lastFocusTime = 0; 10253 this.selectionChanged = false; 10254 return new DOMChange(this.view, from, to, typeOver); 10255 } 10256 // Apply pending changes, if any 10257 flush(readSelection = true) { 10258 // Completely hold off flushing when pending keys are setâthe code 10259 // managing those will make sure processRecords is called and the 10260 // view is resynchronized after 10261 if (this.delayedFlush >= 0 || this.delayedAndroidKey) 10262 return false;
vendor: 4,103 bytes, lines 10263-10358
10263 if (readSelection) 10264 this.readSelectionRange(); 10265 let domChange = this.readChange(); 10266 if (!domChange) 10267 return false; 10268 let startState = this.view.state; 10269 let handled = applyDOMChange(this.view, domChange); 10270 // The view wasn't updated 10271 if (this.view.state == startState) 10272 this.view.update([]); 10273 return handled; 10274 } 10275 readMutation(rec) { 10276 let cView = this.view.docView.nearest(rec.target); 10277 if (!cView || cView.ignoreMutation(rec)) 10278 return null; 10279 cView.markDirty(rec.type == "attributes"); 10280 if (rec.type == "attributes") 10281 cView.dirty |= 4 /* Dirty.Attrs */; 10282 if (rec.type == "childList") { 10283 let childBefore = findChild(cView, rec.previousSibling || rec.target.previousSibling, -1); 10284 let childAfter = findChild(cView, rec.nextSibling || rec.target.nextSibling, 1); 10285 return { from: childBefore ? cView.posAfter(childBefore) : cView.posAtStart, 10286 to: childAfter ? cView.posBefore(childAfter) : cView.posAtEnd, typeOver: false }; 10287 } 10288 else if (rec.type == "characterData") { 10289 return { from: cView.posAtStart, to: cView.posAtEnd, typeOver: rec.target.nodeValue == rec.oldValue }; 10290 } 10291 else { 10292 return null; 10293 } 10294 } 10295 setWindow(win) { 10296 if (win != this.win) { 10297 this.removeWindowListeners(this.win); 10298 this.win = win; 10299 this.addWindowListeners(this.win); 10300 } 10301 } 10302 addWindowListeners(win) { 10303 win.addEventListener("resize", this.onResize); 10304 win.addEventListener("beforeprint", this.onPrint); 10305 win.addEventListener("scroll", this.onScroll); 10306 win.document.addEventListener("selectionchange", this.onSelectionChange); 10307 } 10308 removeWindowListeners(win) { 10309 win.removeEventListener("scroll", this.onScroll); 10310 win.removeEventListener("resize", this.onResize); 10311 win.removeEventListener("beforeprint", this.onPrint); 10312 win.document.removeEventListener("selectionchange", this.onSelectionChange); 10313 } 10314 destroy() { 10315 var _a, _b, _c; 10316 this.stop(); 10317 (_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect(); 10318 (_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect(); 10319 (_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect(); 10320 for (let dom of this.scrollTargets) 10321 dom.removeEventListener("scroll", this.onScroll); 10322 this.removeWindowListeners(this.win); 10323 clearTimeout(this.parentCheck); 10324 clearTimeout(this.resizeTimeout); 10325 this.win.cancelAnimationFrame(this.delayedFlush); 10326 this.win.cancelAnimationFrame(this.flushingAndroidKey); 10327 } 10328} 10329function findChild(cView, dom, dir) { 10330 while (dom) { 10331 let curView = ContentView.get(dom); 10332 if (curView && curView.parent == cView) 10333 return curView; 10334 let parent = dom.parentNode; 10335 dom = parent != cView.dom ? parent : dir > 0 ? dom.nextSibling : dom.previousSibling; 10336 } 10337 return null; 10338} 10339// Used to work around a Safari Selection/shadow DOM bug (#414) 10340function safariSelectionRangeHack(view) { 10341 let found = null; 10342 // Because Safari (at least in 2018-2021) doesn't provide regular 10343 // access to the selection inside a shadowroot, we have to perform a 10344 // ridiculous hack to get at itâusing `execCommand` to trigger a 10345 // `beforeInput` event so that we can read the target range from the 10346 // event. 10347 function read(event) { 10348 event.preventDefault(); 10349 event.stopImmediatePropagation(); 10350 found = event.getTargetRanges()[0]; 10351 } 10352 view.contentDOM.addEventListener("beforeinput", read, true); 10353 view.dom.ownerDocument.execCommand("indent"); 10354 view.contentDOM.removeEventListener("beforeinput", read, true); 10355 if (!found) 10356 return null; 10357 let anchorNode = found.startContainer, anchorOffset = found.startOffset; 10358 let focusNode = found.endContainer, focusOffset = found.endOffset;
10359 let curAnchor = view.docView.domAtPos(view.state.selection.main.anchor); 10360 // Since such a range doesn't distinguish between anchor and head, 10361 // use a heuristic that flips it around if its end matches the 10362 // current anchor. 10363 if (isEquivalentPosition(curAnchor.node, curAnchor.offset, focusNode, focusOffset)) 10364 [anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset]; 10365 return { anchorNode, anchorOffset, focusNode, focusOffset }; 10366} 10367 10368// The editor's update state machine looks something like this: 10369// 10370// Idle â Updating â Idle (unchecked) â Measuring â Idle 10371// â â 10372// Updating (measure) 10373// 10374// The difference between 'Idle' and 'Idle (unchecked)' lies in 10375// whether a layout check has been scheduled. A regular update through 10376// the `update` method updates the DOM in a write-only fashion, and 10377// relies on a check (scheduled with `requestAnimationFrame`) to make 10378// sure everything is where it should be and the viewport covers the 10379// visible code. That check continues to measure and then optionally 10380// update until it reaches a coherent state. 10381/** 10382An editor view represents the editor's user interface. It holds 10383the editable DOM surface, and possibly other elements such as the 10384line number gutter. It handles events and dispatches state 10385transactions for editing actions. 10386*/ 10387class EditorView { 10388 /** 10389 Construct a new view. You'll want to either provide a `parent` 10390 option, or put `view.dom` into your document after creating a 10391 view, so that the user can see the editor. 10392 */ 10393 constructor(config = {}) { 10394 this.plugins = []; 10395 this.pluginMap = new Map; 10396 this.editorAttrs = {}; 10397 this.contentAttrs = {}; 10398 this.bidiCache = []; 10399 this.destroyed = false; 10400 /** 10401 @internal 10402 */ 10403 this.updateState = 2 /* UpdateState.Updating */; 10404 /** 10405 @internal 10406 */ 10407 this.measureScheduled = -1; 10408 /** 10409 @internal 10410 */ 10411 this.measureRequests = []; 10412 this.contentDOM = document.createElement("div"); 10413 this.scrollDOM = document.createElement("div"); 10414 this.scrollDOM.tabIndex = -1; 10415 this.scrollDOM.className = "cm-scroller"; 10416 this.scrollDOM.appendChild(this.contentDOM); 10417 this.announceDOM = document.createElement("div"); 10418 this.announceDOM.style.cssText = "position: absolute; top: -10000px"; 10419 this.announceDOM.setAttribute("aria-live", "polite"); 10420 this.dom = document.createElement("div"); 10421 this.dom.appendChild(this.announceDOM); 10422 this.dom.appendChild(this.scrollDOM); 10423 this._dispatch = config.dispatch || ((tr) => this.update([tr])); 10424 this.dispatch = this.dispatch.bind(this); 10425 this._root = (config.root || getRoot(config.parent) || document); 10426 this.viewState = new ViewState(config.state || EditorState.create(config)); 10427 this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec)); 10428 for (let plugin of this.plugins) 10429 plugin.update(this); 10430 this.observer = new DOMObserver(this); 10431 this.inputState = new InputState(this); 10432 this.inputState.ensureHandlers(this, this.plugins); 10433 this.docView = new DocView(this); 10434 this.mountStyles(); 10435 this.updateAttrs(); 10436 this.updateState = 0 /* UpdateState.Idle */; 10437 this.requestMeasure(); 10438 if (config.parent) 10439 config.parent.appendChild(this.dom); 10440 } 10441 /** 10442 The current editor state. 10443 */ 10444 get state() { return this.viewState.state; } 10445 /** 10446 To be able to display large documents without consuming too much 10447 memory or overloading the browser, CodeMirror only draws the 10448 code that is visible (plus a margin around it) to the DOM. This 10449 property tells you the extent of the current drawn viewport, in 10450 document positions. 10451 */ 10452 get viewport() { return this.viewState.viewport; } 10453 /** 10454 When there are, for example, large collapsed ranges in the 10455 viewport, its size can be a lot bigger than the actual visible 10456 content. Thus, if you are doing something like styling the 10457 content in the viewport, it is preferable to only do so for 10458 these ranges, which are the subset of the viewport that is 10459 actually drawn. 10460 */ 10461 get visibleRanges() { return this.viewState.visibleRanges; } 10462 /** 10463 Returns false when the editor is entirely scrolled out of view 10464 or otherwise hidden. 10465 */ 10466 get inView() { return this.viewState.inView; } 10467 /** 10468 Indicates whether the user is currently composing text via 10469 [IME](https://en.wikipedia.org/wiki/Input_method), and at least 10470 one change has been made in the current composition. 10471 */ 10472 get composing() { return this.inputState.composing > 0; } 10473 /** 10474 Indicates whether the user is currently in composing state. Note 10475 that on some platforms, like Android, this will be the case a 10476 lot, since just putting the cursor on a word starts a 10477 composition there. 10478 */ 10479 get compositionStarted() { return this.inputState.composing >= 0; } 10480 /** 10481 The document or shadow root that the view lives in. 10482 */ 10483 get root() { return this._root; } 10484 /** 10485 @internal 10486 */ 10487 get win() { return this.dom.ownerDocument.defaultView || window; } 10488 dispatch(...input) { 10489 this._dispatch(input.length == 1 && input[0] instanceof Transaction ? input[0] 10490 : this.state.update(...input)); 10491 } 10492 /** 10493 Update the view for the given array of transactions. This will 10494 update the visible document and selection to match the state 10495 produced by the transactions, and notify view plugins of the 10496 change. You should usually call 10497 [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead, which uses this 10498 as a primitive. 10499 */ 10500 update(transactions) { 10501 if (this.updateState != 0 /* UpdateState.Idle */) 10502 throw new Error("Calls to EditorView.update are not allowed while an update is in progress"); 10503 let redrawn = false, attrsChanged = false, update; 10504 let state = this.state; 10505 for (let tr of transactions) { 10506 if (tr.startState != state) 10507 throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state."); 10508 state = tr.state; 10509 } 10510 if (this.destroyed) { 10511 this.viewState.state = state; 10512 return; 10513 } 10514 // If there was a pending DOM change, eagerly read it and try to 10515 // apply it after the given transactions. 10516 let pendingKey = this.observer.delayedAndroidKey, domChange = null; 10517 if (pendingKey) { 10518 this.observer.clearDelayedAndroidKey(); 10519 domChange = this.observer.readChange(); 10520 // Only try to apply DOM changes if the transactions didn't 10521 // change the doc or selection. 10522 if (domChange && !this.state.doc.eq(state.doc) || !this.state.selection.eq(state.selection)) 10523 domChange = null; 10524 } 10525 else { 10526 this.observer.clear(); 10527 } 10528 // When the phrases change, redraw the editor
10529 if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases)) 10530 return this.setState(state); 10531 update = ViewUpdate.create(this, state, transactions); 10532 let scrollTarget = this.viewState.scrollTarget; 10533 try { 10534 this.updateState = 2 /* UpdateState.Updating */; 10535 for (let tr of transactions) { 10536 if (scrollTarget) 10537 scrollTarget = scrollTarget.map(tr.changes); 10538 if (tr.scrollIntoView) { 10539 let { main } = tr.state.selection; 10540 scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1)); 10541 } 10542 for (let e of tr.effects) 10543 if (e.is(scrollIntoView$1)) 10544 scrollTarget = e.value; 10545 } 10546 this.viewState.update(update, scrollTarget); 10547 this.bidiCache = CachedOrder.update(this.bidiCache, update.changes); 10548 if (!update.empty) { 10549 this.updatePlugins(update); 10550 this.inputState.update(update); 10551 } 10552 redrawn = this.docView.update(update); 10553 if (this.state.facet(styleModule) != this.styleModules) 10554 this.mountStyles(); 10555 attrsChanged = this.updateAttrs(); 10556 this.showAnnouncements(transactions); 10557 this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer"))); 10558 } 10559 finally { 10560 this.updateState = 0 /* UpdateState.Idle */; 10561 } 10562 if (update.startState.facet(theme) != update.state.facet(theme)) 10563 this.viewState.mustMeasureContent = true; 10564 if (redrawn || attrsChanged || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent) 10565 this.requestMeasure(); 10566 if (!update.empty) 10567 for (let listener of this.state.facet(updateListener)) 10568 listener(update); 10569 if (domChange) { 10570 if (!applyDOMChange(this, domChange) && pendingKey.force) 10571 dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode); 10572 } 10573 } 10574 /** 10575 Reset the view to the given state. (This will cause the entire 10576 document to be redrawn and all view plugins to be reinitialized, 10577 so you should probably only use it when the new state isn't 10578 derived from the old state. Otherwise, use 10579 [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead.) 10580 */ 10581 setState(newState) { 10582 if (this.updateState != 0 /* UpdateState.Idle */) 10583 throw new Error("Calls to EditorView.setState are not allowed while an update is in progress"); 10584 if (this.destroyed) { 10585 this.viewState.state = newState; 10586 return; 10587 } 10588 this.updateState = 2 /* UpdateState.Updating */; 10589 let hadFocus = this.hasFocus; 10590 try { 10591 for (let plugin of this.plugins) 10592 plugin.destroy(this); 10593 this.viewState = new ViewState(newState); 10594 this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec)); 10595 this.pluginMap.clear(); 10596 for (let plugin of this.plugins) 10597 plugin.update(this); 10598 this.docView = new DocView(this); 10599 this.inputState.ensureHandlers(this, this.plugins); 10600 this.mountStyles(); 10601 this.updateAttrs(); 10602 this.bidiCache = []; 10603 } 10604 finally { 10605 this.updateState = 0 /* UpdateState.Idle */; 10606 } 10607 if (hadFocus) 10608 this.focus(); 10609 this.requestMeasure(); 10610 } 10611 updatePlugins(update) { 10612 let prevSpecs = update.startState.facet(viewPlugin), specs = update.state.facet(viewPlugin); 10613 if (prevSpecs != specs) { 10614 let newPlugins = []; 10615 for (let spec of specs) { 10616 let found = prevSpecs.indexOf(spec); 10617 if (found < 0) { 10618 newPlugins.push(new PluginInstance(spec)); 10619 } 10620 else { 10621 let plugin = this.plugins[found]; 10622 plugin.mustUpdate = update; 10623 newPlugins.push(plugin); 10624 } 10625 } 10626 for (let plugin of this.plugins) 10627 if (plugin.mustUpdate != update) 10628 plugin.destroy(this); 10629 this.plugins = newPlugins; 10630 this.pluginMap.clear(); 10631 this.inputState.ensureHandlers(this, this.plugins); 10632 } 10633 else { 10634 for (let p of this.plugins) 10635 p.mustUpdate = update; 10636 } 10637 for (let i = 0; i < this.plugins.length; i++) 10638 this.plugins[i].update(this); 10639 } 10640 /** 10641 @internal 10642 */ 10643 measure(flush = true) { 10644 if (this.destroyed) 10645 return; 10646 if (this.measureScheduled > -1) 10647 cancelAnimationFrame(this.measureScheduled); 10648 this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame 10649 if (flush) 10650 this.observer.forceFlush(); 10651 let updated = null; 10652 let { scrollHeight, scrollTop, clientHeight } = this.scrollDOM; 10653 let refHeight = scrollTop > scrollHeight - clientHeight - 4 ? scrollHeight : scrollTop; 10654 try { 10655 for (let i = 0;; i++) { 10656 this.updateState = 1 /* UpdateState.Measuring */; 10657 let oldViewport = this.viewport; 10658 let refBlock = this.viewState.lineBlockAtHeight(refHeight); 10659 let changed = this.viewState.measure(this); 10660 if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null) 10661 break; 10662 if (i > 5) { 10663 console.warn(this.measureRequests.length 10664 ? "Measure loop restarted more than 5 times" 10665 : "Viewport failed to stabilize"); 10666 break; 10667 } 10668 let measuring = []; 10669 // Only run measure requests in this cycle when the viewport didn't change 10670 if (!(changed & 4 /* UpdateFlag.Viewport */)) 10671 [this.measureRequests, measuring] = [measuring, this.measureRequests]; 10672 let measured = measuring.map(m => { 10673 try { 10674 return m.read(this); 10675 } 10676 catch (e) { 10677 logException(this.state, e); 10678 return BadMeasure; 10679 } 10680 }); 10681 let update = ViewUpdate.create(this, this.state, []), redrawn = false, scrolled = false;
10682 update.flags |= changed; 10683 if (!updated) 10684 updated = update; 10685 else 10686 updated.flags |= changed; 10687 this.updateState = 2 /* UpdateState.Updating */; 10688 if (!update.empty) { 10689 this.updatePlugins(update); 10690 this.inputState.update(update); 10691 this.updateAttrs(); 10692 redrawn = this.docView.update(update); 10693 } 10694 for (let i = 0; i < measuring.length; i++) 10695 if (measured[i] != BadMeasure) { 10696 try { 10697 let m = measuring[i]; 10698 if (m.write) 10699 m.write(measured[i], this); 10700 } 10701 catch (e) { 10702 logException(this.state, e); 10703 } 10704 } 10705 if (this.viewState.editorHeight) { 10706 if (this.viewState.scrollTarget) { 10707 this.docView.scrollIntoView(this.viewState.scrollTarget); 10708 this.viewState.scrollTarget = null; 10709 scrolled = true; 10710 } 10711 else { 10712 let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top; 10713 if (diff > 1 || diff < -1) { 10714 this.scrollDOM.scrollTop += diff; 10715 scrolled = true; 10716 } 10717 } 10718 } 10719 if (redrawn) 10720 this.docView.updateSelection(true); 10721 if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && 10722 !scrolled && this.measureRequests.length == 0) 10723 break; 10724 } 10725 } 10726 finally { 10727 this.updateState = 0 /* UpdateState.Idle */; 10728 this.measureScheduled = -1; 10729 } 10730 if (updated && !updated.empty) 10731 for (let listener of this.state.facet(updateListener)) 10732 listener(updated); 10733 } 10734 /** 10735 Get the CSS classes for the currently active editor themes. 10736 */ 10737 get themeClasses() { 10738 return baseThemeID + " " + 10739 (this.state.facet(darkTheme) ? baseDarkID : baseLightID) + " " + 10740 this.state.facet(theme); 10741 } 10742 updateAttrs() { 10743 let editorAttrs = attrsFromFacet(this, editorAttributes, { 10744 class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses 10745 }); 10746 let contentAttrs = { 10747 spellcheck: "false", 10748 autocorrect: "off", 10749 autocapitalize: "off", 10750 translate: "no", 10751 contenteditable: !this.state.facet(editable) ? "false" : "true", 10752 class: "cm-content", 10753 style: `${browser.tabSize}: ${this.state.tabSize}`, 10754 role: "textbox", 10755 "aria-multiline": "true" 10756 }; 10757 if (this.state.readOnly) 10758 contentAttrs["aria-readonly"] = "true"; 10759 attrsFromFacet(this, contentAttributes, contentAttrs); 10760 let changed = this.observer.ignore(() => { 10761 let changedContent = updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs); 10762 let changedEditor = updateAttrs(this.dom, this.editorAttrs, editorAttrs); 10763 return changedContent || changedEditor; 10764 }); 10765 this.editorAttrs = editorAttrs; 10766 this.contentAttrs = contentAttrs; 10767 return changed; 10768 } 10769 showAnnouncements(trs) { 10770 let first = true; 10771 for (let tr of trs) 10772 for (let effect of tr.effects) 10773 if (effect.is(EditorView.announce)) { 10774 if (first) 10775 this.announceDOM.textContent = ""; 10776 first = false; 10777 let div = this.announceDOM.appendChild(document.createElement("div")); 10778 div.textContent = effect.value; 10779 } 10780 } 10781 mountStyles() { 10782 this.styleModules = this.state.facet(styleModule); 10783 StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1$2).reverse()); 10784 } 10785 readMeasured() { 10786 if (this.updateState == 2 /* UpdateState.Updating */) 10787 throw new Error("Reading the editor layout isn't allowed during an update"); 10788 if (this.updateState == 0 /* UpdateState.Idle */ && this.measureScheduled > -1) 10789 this.measure(false); 10790 } 10791 /**
10792 Schedule a layout measurement, optionally providing callbacks to 10793 do custom DOM measuring followed by a DOM write phase. Using 10794 this is preferable reading DOM layout directly from, for 10795 example, an event handler, because it'll make sure measuring and 10796 drawing done by other components is synchronized, avoiding 10797 unnecessary DOM layout computations. 10798 */ 10799 requestMeasure(request) { 10800 if (this.measureScheduled < 0) 10801 this.measureScheduled = this.win.requestAnimationFrame(() => this.measure()); 10802 if (request) { 10803 if (request.key != null) 10804 for (let i = 0; i < this.measureRequests.length; i++) { 10805 if (this.measureRequests[i].key === request.key) { 10806 this.measureRequests[i] = request; 10807 return; 10808 } 10809 } 10810 this.measureRequests.push(request); 10811 } 10812 } 10813 /** 10814 Get the value of a specific plugin, if present. Note that 10815 plugins that crash can be dropped from a view, so even when you 10816 know you registered a given plugin, it is recommended to check 10817 the return value of this method. 10818 */ 10819 plugin(plugin) { 10820 let known = this.pluginMap.get(plugin); 10821 if (known === undefined || known && known.spec != plugin) 10822 this.pluginMap.set(plugin, known = this.plugins.find(p => p.spec == plugin) || null); 10823 return known && known.update(this).value; 10824 } 10825 /** 10826 The top position of the document, in screen coordinates. This 10827 may be negative when the editor is scrolled down. Points 10828 directly to the top of the first line, not above the padding. 10829 */ 10830 get documentTop() { 10831 return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop; 10832 } 10833 /** 10834 Reports the padding above and below the document. 10835 */ 10836 get documentPadding() { 10837 return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom }; 10838 } 10839 /** 10840 Find the text line or block widget at the given vertical 10841 position (which is interpreted as relative to the [top of the 10842 document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)). 10843 */ 10844 elementAtHeight(height) { 10845 this.readMeasured(); 10846 return this.viewState.elementAtHeight(height); 10847 } 10848 /** 10849 Find the line block (see 10850 [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given 10851 height, again interpreted relative to the [top of the 10852 document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop). 10853 */ 10854 lineBlockAtHeight(height) { 10855 this.readMeasured(); 10856 return this.viewState.lineBlockAtHeight(height); 10857 } 10858 /** 10859 Get the extent and vertical position of all [line 10860 blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions 10861 are relative to the [top of the 10862 document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop); 10863 */ 10864 get viewportLineBlocks() { 10865 return this.viewState.viewportLines; 10866 } 10867 /** 10868 Find the line block around the given document position. A line 10869 block is a range delimited on both sides by either a 10870 non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^replace) line breaks, or the 10871 start/end of the document. It will usually just hold a line of 10872 text, but may be broken into multiple textblocks by block 10873 widgets. 10874 */ 10875 lineBlockAt(pos) { 10876 return this.viewState.lineBlockAt(pos); 10877 } 10878 /** 10879 The editor's total content height. 10880 */ 10881 get contentHeight() { 10882 return this.viewState.contentHeight; 10883 } 10884 /** 10885 Move a cursor position by [grapheme 10886 cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak). `forward` determines whether 10887 the motion is away from the line start, or towards it. In 10888 bidirectional text, the line is traversed in visual order, using 10889 the editor's [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). 10890 When the start position was the last one on the line, the 10891 returned position will be across the line break. If there is no 10892 further line, the original position is returned. 10893 10894 By default, this method moves over a single cluster. The 10895 optional `by` argument can be used to move across more. It will 10896 be called with the first cluster as argument, and should return 10897 a predicate that determines, for each subsequent cluster, 10898 whether it should also be moved over. 10899 */ 10900 moveByChar(start, forward, by) { 10901 return skipAtoms(this, start, moveByChar(this, start, forward, by)); 10902 } 10903 /** 10904 Move a cursor position across the next group of either 10905 [letters](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) or non-letter 10906 non-whitespace characters. 10907 */ 10908 moveByGroup(start, forward) { 10909 return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial))); 10910 } 10911 /** 10912 Move to the next line boundary in the given direction. If 10913 `includeWrap` is true, line wrapping is on, and there is a 10914 further wrap point on the current line, the wrap point will be 10915 returned. Otherwise this function will return the start or end 10916 of the line. 10917 */ 10918 moveToLineBoundary(start, forward, includeWrap = true) { 10919 return moveToLineBoundary(this, start, forward, includeWrap); 10920 } 10921 /** 10922 Move a cursor position vertically. When `distance` isn't given, 10923 it defaults to moving to the next line (including wrapped 10924 lines). Otherwise, `distance` should provide a positive distance 10925 in pixels. 10926 10927 When `start` has a 10928 [`goalColumn`](https://codemirror.net/6/docs/ref/#state.SelectionRange.goalColumn), the vertical 10929 motion will use that as a target horizontal position. Otherwise, 10930 the cursor's own horizontal position is used. The returned 10931 cursor will have its goal column set to whichever column was 10932 used. 10933 */ 10934 moveVertically(start, forward, distance) { 10935 return skipAtoms(this, start, moveVertically(this, start, forward, distance)); 10936 } 10937 /** 10938 Find the DOM parent node and offset (child offset if `node` is 10939 an element, character offset when it is a text node) at the 10940 given document position. 10941 10942 Note that for positions that aren't currently in 10943 `visibleRanges`, the resulting DOM position isn't necessarily 10944 meaningful (it may just point before or after a placeholder 10945 element). 10946 */ 10947 domAtPos(pos) { 10948 return this.docView.domAtPos(pos); 10949 } 10950 /** 10951 Find the document position at the given DOM node. Can be useful 10952 for associating positions with DOM events. Will raise an error 10953 when `node` isn't part of the editor content. 10954 */ 10955 posAtDOM(node, offset = 0) { 10956 return this.docView.posFromDOM(node, offset); 10957 } 10958 posAtCoords(coords, precise = true) { 10959 this.readMeasured(); 10960 return posAtCoords(this, coords, precise); 10961 } 10962 /** 10963 Get the screen coordinates at the given document position. 10964 `side` determines whether the coordinates are based on the 10965 element before (-1) or after (1) the position (if no element is 10966 available on the given side, the method will transparently use 10967 another strategy to get reasonable coordinates). 10968 */ 10969 coordsAtPos(pos, side = 1) { 10970 this.readMeasured(); 10971 let rect = this.docView.coordsAt(pos, side); 10972 if (!rect || rect.left == rect.right) 10973 return rect; 10974 let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line); 10975 let span = order[BidiSpan.find(order, pos - line.from, -1, side)]; 10976 return flattenRect(rect, (span.dir == Direction.LTR) == (side > 0)); 10977 } 10978 /** 10979 The default width of a character in the editor. May not 10980 accurately reflect the width of all characters (given variable 10981 width fonts or styling of invididual ranges). 10982 */ 10983 get defaultCharacterWidth() { return this.viewState.heightOracle.charWidth; } 10984 /** 10985 The default height of a line in the editor. May not be accurate 10986 for all lines. 10987 */ 10988 get defaultLineHeight() { return this.viewState.heightOracle.lineHeight; } 10989 /** 10990 The text direction 10991 ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction) 10992 CSS property) of the editor's content element. 10993 */ 10994 get textDirection() { return this.viewState.defaultTextDirection; } 10995 /** 10996 Find the text direction of the block at the given position, as 10997 assigned by CSS. If 10998 [`perLineTextDirection`](https://codemirror.net/6/docs/ref/#view.EditorView^perLineTextDirection) 10999 isn't enabled, or the given position is outside of the viewport, 11000 this will always return the same as 11001 [`textDirection`](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). Note that 11002 this may trigger a DOM layout. 11003 */ 11004 textDirectionAt(pos) { 11005 let perLine = this.state.facet(perLineTextDirection); 11006 if (!perLine || pos < this.viewport.from || pos > this.viewport.to) 11007 return this.textDirection; 11008 this.readMeasured(); 11009 return this.docView.textDirectionAt(pos); 11010 } 11011 /** 11012 Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping) 11013 (as determined by the 11014 [`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space) 11015 CSS property of its content element). 11016 */ 11017 get lineWrapping() { return this.viewState.heightOracle.lineWrapping; } 11018 /** 11019 Returns the bidirectional text structure of the given line 11020 (which should be in the current document) as an array of span 11021 objects. The order of these spans matches the [text 11022 direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection)âif that is 11023 left-to-right, the leftmost spans come first, otherwise the 11024 rightmost spans come first. 11025 */ 11026 bidiSpans(line) { 11027 if (line.length > MaxBidiLine) 11028 return trivialOrder(line.length); 11029 let dir = this.textDirectionAt(line.from); 11030 for (let entry of this.bidiCache) 11031 if (entry.from == line.from && entry.dir == dir) 11032 return entry.order;
vendor: 6,791 bytes, lines 11033-11191
11033 let order = computeOrder(line.text, dir); 11034 this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order)); 11035 return order; 11036 } 11037 /** 11038 Check whether the editor has focus. 11039 */ 11040 get hasFocus() { 11041 var _a; 11042 // Safari return false for hasFocus when the context menu is open 11043 // or closing, which leads us to ignore selection changes from the 11044 // context menu because it looks like the editor isn't focused. 11045 // This kludges around that. 11046 return (this.dom.ownerDocument.hasFocus() || browser.safari && ((_a = this.inputState) === null || _a === void 0 ? void 0 : _a.lastContextMenu) > Date.now() - 3e4) && 11047 this.root.activeElement == this.contentDOM; 11048 } 11049 /** 11050 Put focus on the editor. 11051 */ 11052 focus() { 11053 this.observer.ignore(() => { 11054 focusPreventScroll(this.contentDOM); 11055 this.docView.updateSelection(); 11056 }); 11057 } 11058 /** 11059 Update the [root](https://codemirror.net/6/docs/ref/##view.EditorViewConfig.root) in which the editor lives. This is only 11060 necessary when moving the editor's existing DOM to a new window or shadow root. 11061 */ 11062 setRoot(root) { 11063 if (this._root != root) { 11064 this._root = root; 11065 this.observer.setWindow((root.nodeType == 9 ? root : root.ownerDocument).defaultView || window); 11066 this.mountStyles(); 11067 } 11068 } 11069 /** 11070 Clean up this editor view, removing its element from the 11071 document, unregistering event handlers, and notifying 11072 plugins. The view instance can no longer be used after 11073 calling this. 11074 */ 11075 destroy() { 11076 for (let plugin of this.plugins) 11077 plugin.destroy(this); 11078 this.plugins = []; 11079 this.inputState.destroy(); 11080 this.dom.remove(); 11081 this.observer.destroy(); 11082 if (this.measureScheduled > -1) 11083 cancelAnimationFrame(this.measureScheduled); 11084 this.destroyed = true; 11085 } 11086 /** 11087 Returns an effect that can be 11088 [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to 11089 cause it to scroll the given position or range into view. 11090 */ 11091 static scrollIntoView(pos, options = {}) { 11092 return scrollIntoView$1.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin)); 11093 } 11094 /** 11095 Returns an extension that can be used to add DOM event handlers. 11096 The value should be an object mapping event names to handler 11097 functions. For any given event, such functions are ordered by 11098 extension precedence, and the first handler to return true will 11099 be assumed to have handled that event, and no other handlers or 11100 built-in behavior will be activated for it. These are registered 11101 on the [content element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except 11102 for `scroll` handlers, which will be called any time the 11103 editor's [scroll element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of 11104 its parent nodes is scrolled. 11105 */ 11106 static domEventHandlers(handlers) { 11107 return ViewPlugin.define(() => ({}), { eventHandlers: handlers }); 11108 } 11109 /** 11110 Create a theme extension. The first argument can be a 11111 [`style-mod`](https://github.com/marijnh/style-mod#documentation) 11112 style spec providing the styles for the theme. These will be 11113 prefixed with a generated class for the style. 11114 11115 Because the selectors will be prefixed with a scope class, rule 11116 that directly match the editor's [wrapper 11117 element](https://codemirror.net/6/docs/ref/#view.EditorView.dom)âto which the scope class will be 11118 addedâneed to be explicitly differentiated by adding an `&` to 11119 the selector for that elementâfor example 11120 `&.cm-focused`. 11121 11122 When `dark` is set to true, the theme will be marked as dark, 11123 which will cause the `&dark` rules from [base 11124 themes](https://codemirror.net/6/docs/ref/#view.EditorView^baseTheme) to be used (as opposed to 11125 `&light` when a light theme is active). 11126 */ 11127 static theme(spec, options) { 11128 let prefix = StyleModule.newName(); 11129 let result = [theme.of(prefix), styleModule.of(buildTheme(`.${prefix}`, spec))]; 11130 if (options && options.dark) 11131 result.push(darkTheme.of(true)); 11132 return result; 11133 } 11134 /** 11135 Create an extension that adds styles to the base theme. Like 11136 with [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme), use `&` to indicate the 11137 place of the editor wrapper element when directly targeting 11138 that. You can also use `&dark` or `&light` instead to only 11139 target editors with a dark or light theme. 11140 */ 11141 static baseTheme(spec) { 11142 return Prec.lowest(styleModule.of(buildTheme("." + baseThemeID, spec, lightDarkIDs))); 11143 } 11144 /** 11145 Retrieve an editor view instance from the view's DOM 11146 representation. 11147 */ 11148 static findFromDOM(dom) { 11149 var _a; 11150 let content = dom.querySelector(".cm-content"); 11151 let cView = content && ContentView.get(content) || ContentView.get(dom); 11152 return ((_a = cView === null || cView === void 0 ? void 0 : cView.rootView) === null || _a === void 0 ? void 0 : _a.view) || null; 11153 } 11154} 11155/** 11156Facet to add a [style 11157module](https://github.com/marijnh/style-mod#documentation) to 11158an editor view. The view will ensure that the module is 11159mounted in its [document 11160root](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.root). 11161*/ 11162EditorView.styleModule = styleModule; 11163/** 11164An input handler can override the way changes to the editable 11165DOM content are handled. Handlers are passed the document 11166positions between which the change was found, and the new 11167content. When one returns true, no further input handlers are 11168called and the default behavior is prevented. 11169*/ 11170EditorView.inputHandler = inputHandler$1; 11171/** 11172By default, the editor assumes all its content has the same 11173[text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true` 11174value to make it read the text direction of every (rendered) 11175line separately. 11176*/ 11177EditorView.perLineTextDirection = perLineTextDirection; 11178/** 11179Allows you to provide a function that should be called when the 11180library catches an exception from an extension (mostly from view 11181plugins, but may be used by other extensions to route exceptions 11182from user-code-provided callbacks). This is mostly useful for 11183debugging and logging. See [`logException`](https://codemirror.net/6/docs/ref/#view.logException). 11184*/ 11185EditorView.exceptionSink = exceptionSink; 11186/** 11187A facet that can be used to register a function to be called 11188every time the view updates. 11189*/ 11190EditorView.updateListener = updateListener; 11191/**
11192Facet that controls whether the editor content DOM is editable. 11193When its highest-precedence value is `false`, the element will 11194not have its `contenteditable` attribute set. (Note that this 11195doesn't affect API calls that change the editor content, even 11196when those are bound to keys or buttons. See the 11197[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.) 11198*/ 11199EditorView.editable = editable; 11200/** 11201Allows you to influence the way mouse selection happens. The 11202functions in this facet will be called for a `mousedown` event 11203on the editor, and can return an object that overrides the way a 11204selection is computed from that mouse click or drag. 11205*/ 11206EditorView.mouseSelectionStyle = mouseSelectionStyle; 11207/** 11208Facet used to configure whether a given selection drag event 11209should move or copy the selection. The given predicate will be 11210called with the `mousedown` event, and can return `true` when 11211the drag should move the content. 11212*/ 11213EditorView.dragMovesSelection = dragMovesSelection$1; 11214/** 11215Facet used to configure whether a given selecting click adds a 11216new range to the existing selection or replaces it entirely. The 11217default behavior is to check `event.metaKey` on macOS, and 11218`event.ctrlKey` elsewhere. 11219*/ 11220EditorView.clickAddsSelectionRange = clickAddsSelectionRange; 11221/** 11222A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration) 11223are shown in the view. Decorations can be provided in two 11224waysâdirectly, or via a function that takes an editor view. 11225 11226Only decoration sets provided directly are allowed to influence 11227the editor's vertical layout structure. The ones provided as 11228functions are called _after_ the new viewport has been computed, 11229and thus **must not** introduce block widgets or replacing 11230decorations that cover line breaks. 11231 11232If you want decorated ranges to behave like atomic units for 11233cursor motion and deletion purposes, also provide the range set 11234containing the decorations to 11235[`EditorView.atomicRanges`](https://codemirror.net/6/docs/ref/#view.EditorView^atomicRanges). 11236*/ 11237EditorView.decorations = decorations; 11238/** 11239Used to provide ranges that should be treated as atoms as far as 11240cursor motion is concerned. This causes methods like 11241[`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and 11242[`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the 11243commands built on top of them) to skip across such regions when 11244a selection endpoint would enter them. This does _not_ prevent 11245direct programmatic [selection 11246updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such 11247regions. 11248*/ 11249EditorView.atomicRanges = atomicRanges; 11250/** 11251Facet that allows extensions to provide additional scroll 11252margins (space around the sides of the scrolling element that 11253should be considered invisible). This can be useful when the 11254plugin introduces elements that cover part of that element (for 11255example a horizontally fixed gutter). 11256*/ 11257EditorView.scrollMargins = scrollMargins; 11258/** 11259This facet records whether a dark theme is active. The extension 11260returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically 11261includes an instance of this when the `dark` option is set to 11262true. 11263*/ 11264EditorView.darkTheme = darkTheme; 11265/** 11266Facet that provides additional DOM attributes for the editor's 11267editable DOM element. 11268*/ 11269EditorView.contentAttributes = contentAttributes; 11270/** 11271Facet that provides DOM attributes for the editor's outer 11272element. 11273*/ 11274EditorView.editorAttributes = editorAttributes; 11275/** 11276An extension that enables line wrapping in the editor (by 11277setting CSS `white-space` to `pre-wrap` in the content). 11278*/ 11279EditorView.lineWrapping = /*@__PURE__*/EditorView.contentAttributes.of({ "class": "cm-lineWrapping" }); 11280/** 11281State effect used to include screen reader announcements in a 11282transaction. These will be added to the DOM in a visually hidden 11283element with `aria-live="polite"` set, and should be used to 11284describe effects that are visually obvious but may not be 11285noticed by screen reader users (such as moving to the next 11286search match). 11287*/
vendor: 6,198 bytes, lines 11288-11451
11288EditorView.announce = /*@__PURE__*/StateEffect.define(); 11289// Maximum line length for which we compute accurate bidi info 11290const MaxBidiLine = 4096; 11291const BadMeasure = {}; 11292class CachedOrder { 11293 constructor(from, to, dir, order) { 11294 this.from = from; 11295 this.to = to; 11296 this.dir = dir; 11297 this.order = order; 11298 } 11299 static update(cache, changes) { 11300 if (changes.empty) 11301 return cache; 11302 let result = [], lastDir = cache.length ? cache[cache.length - 1].dir : Direction.LTR; 11303 for (let i = Math.max(0, cache.length - 10); i < cache.length; i++) { 11304 let entry = cache[i]; 11305 if (entry.dir == lastDir && !changes.touchesRange(entry.from, entry.to)) 11306 result.push(new CachedOrder(changes.mapPos(entry.from, 1), changes.mapPos(entry.to, -1), entry.dir, entry.order)); 11307 } 11308 return result; 11309 } 11310} 11311function attrsFromFacet(view, facet, base) { 11312 for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) { 11313 let source = sources[i], value = typeof source == "function" ? source(view) : source; 11314 if (value) 11315 combineAttrs(value, base); 11316 } 11317 return base; 11318} 11319 11320const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key"; 11321function normalizeKeyName(name, platform) { 11322 const parts = name.split(/-(?!$)/); 11323 let result = parts[parts.length - 1]; 11324 if (result == "Space") 11325 result = " "; 11326 let alt, ctrl, shift, meta; 11327 for (let i = 0; i < parts.length - 1; ++i) { 11328 const mod = parts[i]; 11329 if (/^(cmd|meta|m)$/i.test(mod)) 11330 meta = true; 11331 else if (/^a(lt)?$/i.test(mod)) 11332 alt = true; 11333 else if (/^(c|ctrl|control)$/i.test(mod)) 11334 ctrl = true; 11335 else if (/^s(hift)?$/i.test(mod)) 11336 shift = true; 11337 else if (/^mod$/i.test(mod)) { 11338 if (platform == "mac") 11339 meta = true; 11340 else 11341 ctrl = true; 11342 } 11343 else 11344 throw new Error("Unrecognized modifier name: " + mod); 11345 } 11346 if (alt) 11347 result = "Alt-" + result; 11348 if (ctrl) 11349 result = "Ctrl-" + result; 11350 if (meta) 11351 result = "Meta-" + result; 11352 if (shift) 11353 result = "Shift-" + result; 11354 return result; 11355} 11356function modifiers(name, event, shift) { 11357 if (event.altKey) 11358 name = "Alt-" + name; 11359 if (event.ctrlKey) 11360 name = "Ctrl-" + name; 11361 if (event.metaKey) 11362 name = "Meta-" + name; 11363 if (shift !== false && event.shiftKey) 11364 name = "Shift-" + name; 11365 return name; 11366} 11367const handleKeyEvents = /*@__PURE__*/Prec.default(/*@__PURE__*/EditorView.domEventHandlers({ 11368 keydown(event, view) { 11369 return runHandlers(getKeymap(view.state), event, view, "editor"); 11370 } 11371})); 11372/** 11373Facet used for registering keymaps. 11374 11375You can add multiple keymaps to an editor. Their priorities 11376determine their precedence (the ones specified early or with high 11377priority get checked first). When a handler has returned `true` 11378for a given key, no further handlers are called. 11379*/ 11380const keymap = /*@__PURE__*/Facet.define({ enables: handleKeyEvents }); 11381const Keymaps = /*@__PURE__*/new WeakMap(); 11382// This is hidden behind an indirection, rather than directly computed 11383// by the facet, to keep internal types out of the facet's type. 11384function getKeymap(state) { 11385 let bindings = state.facet(keymap); 11386 let map = Keymaps.get(bindings); 11387 if (!map) 11388 Keymaps.set(bindings, map = buildKeymap(bindings.reduce((a, b) => a.concat(b), []))); 11389 return map; 11390} 11391let storedPrefix = null; 11392const PrefixTimeout = 4000; 11393function buildKeymap(bindings, platform = currentPlatform) { 11394 let bound = Object.create(null); 11395 let isPrefix = Object.create(null); 11396 let checkPrefix = (name, is) => { 11397 let current = isPrefix[name]; 11398 if (current == null) 11399 isPrefix[name] = is; 11400 else if (current != is) 11401 throw new Error("Key binding " + name + " is used both as a regular binding and as a multi-stroke prefix"); 11402 }; 11403 let add = (scope, key, command, preventDefault) => { 11404 var _a, _b; 11405 let scopeObj = bound[scope] || (bound[scope] = Object.create(null)); 11406 let parts = key.split(/ (?!$)/).map(k => normalizeKeyName(k, platform)); 11407 for (let i = 1; i < parts.length; i++) { 11408 let prefix = parts.slice(0, i).join(" "); 11409 checkPrefix(prefix, true); 11410 if (!scopeObj[prefix]) 11411 scopeObj[prefix] = { 11412 preventDefault: true, 11413 run: [(view) => { 11414 let ourObj = storedPrefix = { view, prefix, scope }; 11415 setTimeout(() => { if (storedPrefix == ourObj) 11416 storedPrefix = null; }, PrefixTimeout); 11417 return true; 11418 }] 11419 }; 11420 } 11421 let full = parts.join(" "); 11422 checkPrefix(full, false); 11423 let binding = scopeObj[full] || (scopeObj[full] = { preventDefault: false, run: ((_b = (_a = scopeObj._any) === null || _a === void 0 ? void 0 : _a.run) === null || _b === void 0 ? void 0 : _b.slice()) || [] }); 11424 if (command) 11425 binding.run.push(command); 11426 if (preventDefault) 11427 binding.preventDefault = true; 11428 }; 11429 for (let b of bindings) { 11430 let scopes = b.scope ? b.scope.split(" ") : ["editor"]; 11431 if (b.any) 11432 for (let scope of scopes) { 11433 let scopeObj = bound[scope] || (bound[scope] = Object.create(null)); 11434 if (!scopeObj._any) 11435 scopeObj._any = { preventDefault: false, run: [] }; 11436 for (let key in scopeObj) 11437 scopeObj[key].run.push(b.any); 11438 } 11439 let name = b[platform] || b.key; 11440 if (!name) 11441 continue; 11442 for (let scope of scopes) { 11443 add(scope, name, b.run, b.preventDefault); 11444 if (b.shift) 11445 add(scope, "Shift-" + name, b.shift, b.preventDefault); 11446 } 11447 } 11448 return bound; 11449} 11450function runHandlers(map, event, view, scope) { 11451 let name = keyName(event);
11452 let charCode = codePointAt(name, 0), isChar = codePointSize(charCode) == name.length && name != " "; 11453 let prefix = "", fallthrough = false; 11454 if (storedPrefix && storedPrefix.view == view && storedPrefix.scope == scope) { 11455 prefix = storedPrefix.prefix + " "; 11456 if (fallthrough = modifierCodes.indexOf(event.keyCode) < 0) 11457 storedPrefix = null; 11458 } 11459 let ran = new Set; 11460 let runFor = (binding) => { 11461 if (binding) { 11462 for (let cmd of binding.run) 11463 if (!ran.has(cmd)) { 11464 ran.add(cmd); 11465 if (cmd(view, event)) 11466 return true; 11467 } 11468 if (binding.preventDefault) 11469 fallthrough = true; 11470 } 11471 return false; 11472 }; 11473 let scopeObj = map[scope], baseName, shiftName; 11474 if (scopeObj) { 11475 if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)])) 11476 return true; 11477 if (isChar && (event.shiftKey || event.altKey || event.metaKey || charCode > 127) && 11478 (baseName = base[event.keyCode]) && baseName != name) { 11479 if (runFor(scopeObj[prefix + modifiers(baseName, event, true)])) 11480 return true; 11481 else if (event.shiftKey && (shiftName = shift[event.keyCode]) != name && shiftName != baseName && 11482 runFor(scopeObj[prefix + modifiers(shiftName, event, false)])) 11483 return true; 11484 } 11485 else if (isChar && event.shiftKey) { 11486 if (runFor(scopeObj[prefix + modifiers(name, event, true)])) 11487 return true; 11488 } 11489 if (runFor(scopeObj._any)) 11490 return true; 11491 } 11492 return fallthrough; 11493} 11494 11495const CanHidePrimary = !browser.ios; // FIXME test IE 11496const selectionConfig = /*@__PURE__*/Facet.define({ 11497 combine(configs) { 11498 return combineConfig(configs, { 11499 cursorBlinkRate: 1200, 11500 drawRangeCursor: true 11501 }, { 11502 cursorBlinkRate: (a, b) => Math.min(a, b), 11503 drawRangeCursor: (a, b) => a || b 11504 }); 11505 } 11506}); 11507/** 11508Returns an extension that hides the browser's native selection and 11509cursor, replacing the selection with a background behind the text 11510(with the `cm-selectionBackground` class), and the 11511cursors with elements overlaid over the code (using 11512`cm-cursor-primary` and `cm-cursor-secondary`). 11513 11514This allows the editor to display secondary selection ranges, and 11515tends to produce a type of selection more in line with that users 11516expect in a text editor (the native selection styling will often 11517leave gaps between lines and won't fill the horizontal space after 11518a line when the selection continues past it). 11519 11520It does have a performance cost, in that it requires an extra DOM 11521layout cycle for many updates (the selection is drawn based on DOM 11522layout information that's only available after laying out the 11523content). 11524*/ 11525function drawSelection(config = {}) { 11526 return [ 11527 selectionConfig.of(config), 11528 drawSelectionPlugin, 11529 hideNativeSelection, 11530 nativeSelectionHidden.of(true) 11531 ]; 11532} 11533class Piece { 11534 constructor(left, top, width, height, className) { 11535 this.left = left; 11536 this.top = top; 11537 this.width = width; 11538 this.height = height; 11539 this.className = className; 11540 } 11541 draw() { 11542 let elt = document.createElement("div"); 11543 elt.className = this.className; 11544 this.adjust(elt); 11545 return elt; 11546 } 11547 adjust(elt) { 11548 elt.style.left = this.left + "px"; 11549 elt.style.top = this.top + "px"; 11550 if (this.width >= 0) 11551 elt.style.width = this.width + "px"; 11552 elt.style.height = this.height + "px"; 11553 } 11554 eq(p) { 11555 return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height && 11556 this.className == p.className; 11557 } 11558} 11559const drawSelectionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class { 11560 constructor(view) { 11561 this.view = view; 11562 this.rangePieces = []; 11563 this.cursors = []; 11564 this.measureReq = { read: this.readPos.bind(this), write: this.drawSel.bind(this) }; 11565 this.selectionLayer = view.scrollDOM.appendChild(document.createElement("div")); 11566 this.selectionLayer.className = "cm-selectionLayer"; 11567 this.selectionLayer.setAttribute("aria-hidden", "true"); 11568 this.cursorLayer = view.scrollDOM.appendChild(document.createElement("div")); 11569 this.cursorLayer.className = "cm-cursorLayer"; 11570 this.cursorLayer.setAttribute("aria-hidden", "true"); 11571 view.requestMeasure(this.measureReq); 11572 this.setBlinkRate(); 11573 } 11574 setBlinkRate() { 11575 this.cursorLayer.style.animationDuration = this.view.state.facet(selectionConfig).cursorBlinkRate + "ms"; 11576 } 11577 update(update) { 11578 let confChanged = update.startState.facet(selectionConfig) != update.state.facet(selectionConfig); 11579 if (confChanged || update.selectionSet || update.geometryChanged || update.viewportChanged) 11580 this.view.requestMeasure(this.measureReq); 11581 if (update.transactions.some(tr => tr.scrollIntoView)) 11582 this.cursorLayer.style.animationName = this.cursorLayer.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink"; 11583 if (confChanged) 11584 this.setBlinkRate(); 11585 } 11586 readPos() { 11587 let { state } = this.view, conf = state.facet(selectionConfig); 11588 let rangePieces = state.selection.ranges.map(r => r.empty ? [] : measureRange(this.view, r)).reduce((a, b) =>
11588 a.concat(b)); 11589 let cursors = []; 11590 for (let r of state.selection.ranges) { 11591 let prim = r == state.selection.main; 11592 if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) { 11593 let piece = measureCursor(this.view, r, prim); 11594 if (piece) 11595 cursors.push(piece); 11596 } 11597 } 11598 return { rangePieces, cursors }; 11599 } 11600 drawSel({ rangePieces, cursors }) { 11601 if (rangePieces.length != this.rangePieces.length || rangePieces.some((p, i) => !p.eq(this.rangePieces[i]))) { 11602 this.selectionLayer.textContent = ""; 11603 for (let p of rangePieces) 11604 this.selectionLayer.appendChild(p.draw()); 11605 this.rangePieces = rangePieces; 11606 } 11607 if (cursors.length != this.cursors.length || cursors.some((c, i) => !c.eq(this.cursors[i]))) { 11608 let oldCursors = this.cursorLayer.children; 11609 if (oldCursors.length !== cursors.length) { 11610 this.cursorLayer.textContent = ""; 11611 for (const c of cursors) 11612 this.cursorLayer.appendChild(c.draw()); 11613 } 11614 else { 11615 cursors.forEach((c, idx) => c.adjust(oldCursors[idx])); 11616 } 11617 this.cursors = cursors; 11618 } 11619 } 11620 destroy() { 11621 this.selectionLayer.remove(); 11622 this.cursorLayer.remove(); 11623 } 11624}); 11625const themeSpec = { 11626 ".cm-line": { 11627 "& ::selection": { backgroundColor: "transparent !important" }, 11628 "&::selection": { backgroundColor: "transparent !important" } 11629 } 11630}; 11631if (CanHidePrimary) 11632 themeSpec[".cm-line"].caretColor = "transparent !important";
11633const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec)); 11634function getBase(view) { 11635 let rect = view.scrollDOM.getBoundingClientRect(); 11636 let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth; 11637 return { left: left - view.scrollDOM.scrollLeft, top: rect.top - view.scrollDOM.scrollTop }; 11638} 11639function wrappedLine(view, pos, inside) { 11640 let range = EditorSelection.cursor(pos); 11641 return { from: Math.max(inside.from, view.moveToLineBoundary(range, false, true).from), 11642 to: Math.min(inside.to, view.moveToLineBoundary(range, true, true).from), 11643 type: BlockType.Text }; 11644} 11645function blockAt(view, pos) { 11646 let line = view.lineBlockAt(pos); 11647 if (Array.isArray(line.type)) 11648 for (let l of line.type) { 11649 if (l.to > pos || l.to == pos && (l.to == line.to || l.type == BlockType.Text)) 11650 return l; 11651 } 11652 return line; 11653} 11654function measureRange(view, range) { 11655 if (range.to <= view.viewport.from || range.from >= view.viewport.to) 11656 return []; 11657 let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to); 11658 let ltr = view.textDirection == Direction.LTR; 11659 let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view); 11660 let lineStyle = window.getComputedStyle(content.firstChild); 11661 let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent)); 11662 let rightSide = contentRect.right - parseInt(lineStyle.paddingRight); 11663 let startBlock = blockAt(view, from), endBlock = blockAt(view, to); 11664 let visualStart = startBlock.type == BlockType.Text ? startBlock : null; 11665 let visualEnd = endBlock.type == BlockType.Text ? endBlock : null; 11666 if (view.lineWrapping) { 11667 if (visualStart) 11668 visualStart = wrappedLine(view, from, visualStart); 11669 if (visualEnd) 11670 visualEnd = wrappedLine(view, to, visualEnd); 11671 } 11672 if (visualStart && visualEnd && visualStart.from == visualEnd.from) { 11673 return pieces(drawForLine(range.from, range.to, visualStart)); 11674 } 11675 else { 11676 let top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false); 11677 let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true); 11678 let between = []; 11679 if ((visualStart || startBlock).to < (visualEnd || endBlock).from - 1) 11680 between.push(piece(leftSide, top.bottom, rightSide, bottom.top)); 11681 else if (top.bottom < bottom.top && view.elementAtHeight((top.bottom + bottom.top) / 2).type == BlockType.Text) 11682 top.bottom = bottom.top = (top.bottom + bottom.top) / 2; 11683 return pieces(top).concat(between).concat(pieces(bottom)); 11684 } 11685 function piece(left, top, right, bottom) { 11686 return new Piece(left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */, "cm-selectionBackground"); 11687 } 11688 function pieces({ top, bottom, horizontal }) { 11689 let pieces = []; 11690 for (let i = 0; i < horizontal.length; i += 2) 11691 pieces.push(piece(horizontal[i], top, horizontal[i + 1], bottom)); 11692 return pieces; 11693 } 11694 // Gets passed from/to in line-local positions 11695 function drawForLine(from, to, line) { 11696 let top = 1e9, bottom = -1e9, horizontal = []; 11697 function addSpan(from, fromOpen, to, toOpen, dir) { 11698 // Passing 2/-2 is a kludge to force the view to return 11699 // coordinates on the proper side of block widgets, since 11700 // normalizing the side there, though appropriate for most 11701 // coordsAtPos queries, would break selection drawing. 11702 let fromCoords = view.coordsAtPos(from, (from == line.to ? -2 : 2)); 11703 let toCoords = view.coordsAtPos(to, (to == line.from ? 2 : -2)); 11704 top = Math.min(fromCoords.top, toCoords.top, top); 11705 bottom = Math.max(fromCoords.bottom, toCoords.bottom, bottom); 11706 if (dir == Direction.LTR) 11707 horizontal.push(ltr && fromOpen ? leftSide : fromCoords.left, ltr && toOpen ? rightSide : toCoords.right); 11708 else 11709 horizontal.push(!ltr && toOpen ? leftSide : toCoords.left, !ltr && fromOpen ? rightSide : fromCoords.right); 11710 } 11711 let start = from !== null && from !== void 0 ? from : line.from, end = to !== null && to !== void 0 ? to : line.to; 11712 // Split the range by visible range and document line 11713 for (let r of view.visibleRanges) 11714 if (r.to > start && r.from < end) { 11715 for (let pos = Math.max(r.from, start), endPos = Math.min(r.to, end);;) { 11716 let docLine = view.state.doc.lineAt(pos); 11717 for (let span of view.bidiSpans(docLine)) { 11718 let spanFrom = span.from + docLine.from, spanTo
vendor: 10,389 bytes, lines 11718-11966
11718= span.to + docLine.from; 11719 if (spanFrom >= endPos) 11720 break; 11721 if (spanTo > pos) 11722 addSpan(Math.max(spanFrom, pos), from == null && spanFrom <= start, Math.min(spanTo, endPos), to == null && spanTo >= end, span.dir); 11723 } 11724 pos = docLine.to + 1; 11725 if (pos >= endPos) 11726 break; 11727 } 11728 } 11729 if (horizontal.length == 0) 11730 addSpan(start, from == null, end, to == null, view.textDirection); 11731 return { top, bottom, horizontal }; 11732 } 11733 function drawForWidget(block, top) { 11734 let y = contentRect.top + (top ? block.top : block.bottom); 11735 return { top: y, bottom: y, horizontal: [] }; 11736 } 11737} 11738function measureCursor(view, cursor, primary) { 11739 let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1); 11740 if (!pos) 11741 return null; 11742 let base = getBase(view); 11743 return new Piece(pos.left - base.left, pos.top - base.top, -1, pos.bottom - pos.top, primary ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary"); 11744} 11745 11746function iterMatches(doc, re, from, to, f) { 11747 re.lastIndex = 0; 11748 for (let cursor = doc.iterRange(from, to), pos = from, m; !cursor.next().done; pos += cursor.value.length) { 11749 if (!cursor.lineBreak) 11750 while (m = re.exec(cursor.value)) 11751 f(pos + m.index, m); 11752 } 11753} 11754function matchRanges(view, maxLength) { 11755 let visible = view.visibleRanges; 11756 if (visible.length == 1 && visible[0].from == view.viewport.from && 11757 visible[0].to == view.viewport.to) 11758 return visible; 11759 let result = []; 11760 for (let { from, to } of visible) { 11761 from = Math.max(view.state.doc.lineAt(from).from, from - maxLength); 11762 to = Math.min(view.state.doc.lineAt(to).to, to + maxLength); 11763 if (result.length && result[result.length - 1].to >= from) 11764 result[result.length - 1].to = to; 11765 else 11766 result.push({ from, to }); 11767 } 11768 return result; 11769} 11770/** 11771Helper class used to make it easier to maintain decorations on 11772visible code that matches a given regular expression. To be used 11773in a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin). Instances of this object 11774represent a matching configuration. 11775*/ 11776class MatchDecorator { 11777 /** 11778 Create a decorator. 11779 */ 11780 constructor(config) { 11781 const { regexp, decoration, decorate, boundary, maxLength = 1000 } = config; 11782 if (!regexp.global) 11783 throw new RangeError("The regular expression given to MatchDecorator should have its 'g' flag set"); 11784 this.regexp = regexp; 11785 if (decorate) { 11786 this.addMatch = (match, view, from, add) => decorate(add, from, from + match[0].length, match, view); 11787 } 11788 else if (typeof decoration == "function") { 11789 this.addMatch = (match, view, from, add) => { 11790 let deco = decoration(match, view, from); 11791 if (deco) 11792 add(from, from + match[0].length, deco); 11793 }; 11794 } 11795 else if (decoration) { 11796 this.addMatch = (match, _view, from, add) => add(from, from + match[0].length, decoration); 11797 } 11798 else { 11799 throw new RangeError("Either 'decorate' or 'decoration' should be provided to MatchDecorator"); 11800 } 11801 this.boundary = boundary; 11802 this.maxLength = maxLength; 11803 } 11804 /** 11805 Compute the full set of decorations for matches in the given 11806 view's viewport. You'll want to call this when initializing your 11807 plugin. 11808 */ 11809 createDeco(view) { 11810 let build = new RangeSetBuilder(), add = build.add.bind(build); 11811 for (let { from, to } of matchRanges(view, this.maxLength)) 11812 iterMatches(view.state.doc, this.regexp, from, to, (from, m) => this.addMatch(m, view, from, add)); 11813 return build.finish(); 11814 } 11815 /** 11816 Update a set of decorations for a view update. `deco` _must_ be 11817 the set of decorations produced by _this_ `MatchDecorator` for 11818 the view state before the update. 11819 */ 11820 updateDeco(update, deco) { 11821 let changeFrom = 1e9, changeTo = -1; 11822 if (update.docChanged) 11823 update.changes.iterChanges((_f, _t, from, to) => { 11824 if (to > update.view.viewport.from && from < update.view.viewport.to) { 11825 changeFrom = Math.min(from, changeFrom); 11826 changeTo = Math.max(to, changeTo); 11827 } 11828 }); 11829 if (update.viewportChanged || changeTo - changeFrom > 1000) 11830 return this.createDeco(update.view); 11831 if (changeTo > -1) 11832 return this.updateRange(update.view, deco.map(update.changes), changeFrom, changeTo); 11833 return deco; 11834 } 11835 updateRange(view, deco, updateFrom, updateTo) { 11836 for (let r of view.visibleRanges) { 11837 let from = Math.max(r.from, updateFrom), to = Math.min(r.to, updateTo); 11838 if (to > from) { 11839 let fromLine = view.state.doc.lineAt(from), toLine = fromLine.to < to ? view.state.doc.lineAt(to) : fromLine; 11840 let start = Math.max(r.from, fromLine.from), end = Math.min(r.to, toLine.to); 11841 if (this.boundary) { 11842 for (; from > fromLine.from; from--) 11843 if (this.boundary.test(fromLine.text[from - 1 - fromLine.from])) { 11844 start = from; 11845 break; 11846 } 11847 for (; to < toLine.to; to++) 11848 if (this.boundary.test(toLine.text[to - toLine.from])) { 11849 end = to; 11850 break; 11851 } 11852 } 11853 let ranges = [], m; 11854 let add = (from, to, deco) => ranges.push(deco.range(from, to)); 11855 if (fromLine == toLine) { 11856 this.regexp.lastIndex = start - fromLine.from; 11857 while ((m = this.regexp.exec(fromLine.text)) && m.index < end - fromLine.from) 11858 this.addMatch(m, view, m.index + fromLine.from, add); 11859 } 11860 else { 11861 iterMatches(view.state.doc, this.regexp, start, end, (from, m) => this.addMatch(m, view, from, add)); 11862 } 11863 deco = deco.update({ filterFrom: start, filterTo: end, filter: (from, to) => from < start || to > end, add: ranges }); 11864 } 11865 } 11866 return deco; 11867 } 11868} 11869 11870const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g"; 11871const Specials = /*@__PURE__*/new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport); 11872const Names = { 11873 0: "null", 11874 7: "bell", 11875 8: "backspace", 11876 10: "newline", 11877 11: "vertical tab", 11878 13: "carriage return", 11879 27: "escape", 11880 8203: "zero width space", 11881 8204: "zero width non-joiner", 11882 8205: "zero width joiner", 11883 8206: "left-to-right mark", 11884 8207: "right-to-left mark", 11885 8232: "line separator", 11886 8237: "left-to-right override", 11887 8238: "right-to-left override", 11888 8294: "left-to-right isolate", 11889 8295: "right-to-left isolate", 11890 8297: "pop directional isolate", 11891 8233: "paragraph separator", 11892 65279: "zero width no-break space", 11893 65532: "object replacement" 11894}; 11895let _supportsTabSize = null; 11896function supportsTabSize() { 11897 var _a; 11898 if (_supportsTabSize == null && typeof document != "undefined" && document.body) { 11899 let styles = document.body.style; 11900 _supportsTabSize = ((_a = styles.tabSize) !== null && _a !== void 0 ? _a : styles.MozTabSize) != null; 11901 } 11902 return _supportsTabSize || false; 11903} 11904const specialCharConfig = /*@__PURE__*/Facet.define({ 11905 combine(configs) { 11906 let config = combineConfig(configs, { 11907 render: null, 11908 specialChars: Specials, 11909 addSpecialChars: null 11910 }); 11911 if (config.replaceTabs = !supportsTabSize()) 11912 config.specialChars = new RegExp("\t|" + config.specialChars.source, UnicodeRegexpSupport); 11913 if (config.addSpecialChars) 11914 config.specialChars = new RegExp(config.specialChars.source + "|" + config.addSpecialChars.source, UnicodeRegexpSupport); 11915 return config; 11916 } 11917}); 11918/** 11919Returns an extension that installs highlighting of special 11920characters. 11921*/ 11922function highlightSpecialChars( 11923/** 11924Configuration options. 11925*/ 11926config = {}) { 11927 return [specialCharConfig.of(config), specialCharPlugin()]; 11928} 11929let _plugin = null; 11930function specialCharPlugin() { 11931 return _plugin || (_plugin = ViewPlugin.fromClass(class { 11932 constructor(view) { 11933 this.view = view; 11934 this.decorations = Decoration.none; 11935 this.decorationCache = Object.create(null); 11936 this.decorator = this.makeDecorator(view.state.facet(specialCharConfig)); 11937 this.decorations = this.decorator.createDeco(view); 11938 } 11939 makeDecorator(conf) { 11940 return new MatchDecorator({ 11941 regexp: conf.specialChars, 11942 decoration: (m, view, pos) => { 11943 let { doc } = view.state; 11944 let code = codePointAt(m[0], 0); 11945 if (code == 9) { 11946 let line = doc.lineAt(pos); 11947 let size = view.state.tabSize, col = countColumn(line.text, size, pos - line.from); 11948 return Decoration.replace({ widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth) }); 11949 } 11950 return this.decorationCache[code] || 11951 (this.decorationCache[code] = Decoration.replace({ widget: new SpecialCharWidget(conf, code) })); 11952 }, 11953 boundary: conf.replaceTabs ? undefined : /[^]/ 11954 }); 11955 } 11956 update(update) { 11957 let conf = update.state.facet(specialCharConfig); 11958 if (update.startState.facet(specialCharConfig) != conf) { 11959 this.decorator = this.makeDecorator(conf); 11960 this.decorations = this.decorator.createDeco(update.view); 11961 } 11962 else { 11963 this.decorations = this.decorator.updateDeco(update, this.decorations); 11964 } 11965 } 11966 }, {
11967 decorations: v => v.decorations 11968 })); 11969} 11970const DefaultPlaceholder = "\u2022"; 11971// Assigns placeholder characters from the Control Pictures block to 11972// ASCII control characters 11973function placeholder$1(code) { 11974 if (code >= 32) 11975 return DefaultPlaceholder; 11976 if (code == 10) 11977 return "\u2424"; 11978 return String.fromCharCode(9216 + code); 11979} 11980class SpecialCharWidget extends WidgetType { 11981 constructor(options, code) { 11982 super(); 11983 this.options = options; 11984 this.code = code; 11985 } 11986 eq(other) { return other.code == this.code; } 11987 toDOM(view) { 11988 let ph = placeholder$1(this.code); 11989 let desc = view.state.phrase("Control character") + " " + (Names[this.code] || "0x" + this.code.toString(16)); 11990 let custom = this.options.render && this.options.render(this.code, desc, ph); 11991 if (custom) 11992 return custom; 11993 let span = document.createElement("span"); 11994 span.textContent = ph; 11995 span.title = desc; 11996 span.setAttribute("aria-label", desc); 11997 span.className = "cm-specialChar"; 11998 return span; 11999 } 12000 ignoreEvent() { return false; } 12001} 12002class TabWidget extends WidgetType { 12003 constructor(width) { 12004 super(); 12005 this.width = width; 12006 } 12007 eq(other) { return other.width == this.width; } 12008 toDOM() { 12009 let span = document.createElement("span"); 12010 span.textContent = "\t"; 12011 span.className = "cm-tab"; 12012 span.style.width = this.width + "px"; 12013 return span; 12014 } 12015 ignoreEvent() { return false; } 12016} 12017 12018class Placeholder extends WidgetType { 12019 constructor(content) { 12020 super(); 12021 this.content = content; 12022 } 12023 toDOM() { 12024 let wrap = document.createElement("span"); 12025 wrap.className = "cm-placeholder"; 12026 wrap.style.pointerEvents = "none"; 12027 wrap.appendChild(typeof this.content == "string" ? document.createTextNode(this.content) : this.content); 12028 if (typeof this.content == "string") 12029 wrap.setAttribute("aria-label", "placeholder " + this.content); 12030 else 12031 wrap.setAttribute("aria-hidden", "true"); 12032 return wrap; 12033 } 12034 ignoreEvent() { return false; } 12035} 12036/** 12037Extension that enables a placeholderâa piece of example content 12038to show when the editor is empty. 12039*/ 12040function placeholder(content) { 12041 return ViewPlugin.fromClass(class { 12042 constructor(view) { 12043 this.view = view; 12044 this.placeholder = Decoration.set([Decoration.widget({ widget: new Placeholder(content), side: 1 }).range(0)]); 12045 } 12046 get decorations() { return this.view.state.doc.length ? Decoration.none : this.placeholder; } 12047 }, { decorations: v => v.decorations }); 12048} 12049 12050// Don't compute precise column positions for line offsets above this 12051// (since it could get expensive). Assume offset==column for them. 12052const MaxOff = 2000; 12053function rectangleFor(state, a, b) { 12054 let startLine = Math.min(a.line, b.line), endLine = Math.max(a.line, b.line); 12055 let ranges = []; 12056 if (a.off > MaxOff || b.off > MaxOff || a.col < 0 || b.col < 0) { 12057 let startOff = Math.min(a.off, b.off), endOff = Math.max(a.off, b.off); 12058 for (let i = startLine; i <= endLine; i++) { 12059 let line = state.doc.line(i); 12060 if (line.length <= endOff) 12061 ranges.push(EditorSelection.range(line.from + startOff, line.to + endOff)); 12062 } 12063 } 12064 else { 12065 let startCol = Math.min(a.col, b.col), endCol = Math.max(a.col, b.col); 12066 for (let i = startLine; i <= endLine; i++) { 12067 let line = state.doc.line(i); 12068 let start = findColumn(line.text, startCol, state.tabSize, true); 12069 if (start < 0) { 12070 ranges.push(EditorSelection.cursor(line.to)); 12071 } 12072 else { 12073 let end = findColumn(line.text, endCol, state.tabSize); 12074 ranges.push(EditorSelection.range(line.from + start, line.from + end)); 12075 } 12076 } 12077 } 12078 return ranges; 12079} 12080function absoluteColumn(view, x) { 12081 let ref = view.coordsAtPos(view.viewport.from); 12082 return ref ? Math.round(Math.abs((ref.left - x) / view.defaultCharacterWidth)) : -1; 12083} 12084function getPos(view, event) { 12085 let offset = view.posAtCoords({ x: event.clientX, y: event.clientY }, false); 12086 let line = view.state.doc.lineAt(offset), off = offset - line.from;
vendor: 6,128 bytes, lines 12087-12248
12087 let col = off > MaxOff ? -1 12088 : off == line.length ? absoluteColumn(view, event.clientX) 12089 : countColumn(line.text, view.state.tabSize, offset - line.from); 12090 return { line: line.number, col, off }; 12091} 12092function rectangleSelectionStyle(view, event) { 12093 let start = getPos(view, event), startSel = view.state.selection; 12094 if (!start) 12095 return null; 12096 return { 12097 update(update) { 12098 if (update.docChanged) { 12099 let newStart = update.changes.mapPos(update.startState.doc.line(start.line).from); 12100 let newLine = update.state.doc.lineAt(newStart); 12101 start = { line: newLine.number, col: start.col, off: Math.min(start.off, newLine.length) }; 12102 startSel = startSel.map(update.changes); 12103 } 12104 }, 12105 get(event, _extend, multiple) { 12106 let cur = getPos(view, event); 12107 if (!cur) 12108 return startSel; 12109 let ranges = rectangleFor(view.state, start, cur); 12110 if (!ranges.length) 12111 return startSel; 12112 if (multiple) 12113 return EditorSelection.create(ranges.concat(startSel.ranges)); 12114 else 12115 return EditorSelection.create(ranges); 12116 } 12117 }; 12118} 12119/** 12120Create an extension that enables rectangular selections. By 12121default, it will react to left mouse drag with the Alt key held 12122down. When such a selection occurs, the text within the rectangle 12123that was dragged over will be selected, as one selection 12124[range](https://codemirror.net/6/docs/ref/#state.SelectionRange) per line. 12125*/ 12126function rectangularSelection(options) { 12127 let filter = (options === null || options === void 0 ? void 0 : options.eventFilter) || (e => e.altKey && e.button == 0); 12128 return EditorView.mouseSelectionStyle.of((view, event) => filter(event) ? rectangleSelectionStyle(view, event) : null); 12129} 12130const keys = { 12131 Alt: [18, e => e.altKey], 12132 Control: [17, e => e.ctrlKey], 12133 Shift: [16, e => e.shiftKey], 12134 Meta: [91, e => e.metaKey] 12135}; 12136const showCrosshair = { style: "cursor: crosshair" }; 12137/** 12138Returns an extension that turns the pointer cursor into a 12139crosshair when a given modifier key, defaulting to Alt, is held 12140down. Can serve as a visual hint that rectangular selection is 12141going to happen when paired with 12142[`rectangularSelection`](https://codemirror.net/6/docs/ref/#view.rectangularSelection). 12143*/ 12144function crosshairCursor(options = {}) { 12145 let [code, getter] = keys[options.key || "Alt"]; 12146 let plugin = ViewPlugin.fromClass(class { 12147 constructor(view) { 12148 this.view = view; 12149 this.isDown = false; 12150 } 12151 set(isDown) { 12152 if (this.isDown != isDown) { 12153 this.isDown = isDown; 12154 this.view.update([]); 12155 } 12156 } 12157 }, { 12158 eventHandlers: { 12159 keydown(e) { 12160 this.set(e.keyCode == code || getter(e)); 12161 }, 12162 keyup(e) { 12163 if (e.keyCode == code || !getter(e)) 12164 this.set(false); 12165 }, 12166 mousemove(e) { 12167 this.set(getter(e)); 12168 } 12169 } 12170 }); 12171 return [ 12172 plugin, 12173 EditorView.contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.isDown) ? showCrosshair : null; }) 12174 ]; 12175} 12176 12177const Outside = "-10000px"; 12178class TooltipViewManager { 12179 constructor(view, facet, createTooltipView) { 12180 this.facet = facet; 12181 this.createTooltipView = createTooltipView; 12182 this.input = view.state.facet(facet); 12183 this.tooltips = this.input.filter(t => t); 12184 this.tooltipViews = this.tooltips.map(createTooltipView); 12185 } 12186 update(update) { 12187 var _a; 12188 let input = update.state.facet(this.facet); 12189 let tooltips = input.filter(x => x); 12190 if (input === this.input) { 12191 for (let t of this.tooltipViews) 12192 if (t.update) 12193 t.update(update); 12194 return false; 12195 } 12196 let tooltipViews = []; 12197 for (let i = 0; i < tooltips.length; i++) { 12198 let tip = tooltips[i], known = -1; 12199 if (!tip) 12200 continue; 12201 for (let i = 0; i < this.tooltips.length; i++) { 12202 let other = this.tooltips[i]; 12203 if (other && other.create == tip.create) 12204 known = i; 12205 } 12206 if (known < 0) { 12207 tooltipViews[i] = this.createTooltipView(tip); 12208 } 12209 else { 12210 let tooltipView = tooltipViews[i] = this.tooltipViews[known]; 12211 if (tooltipView.update) 12212 tooltipView.update(update); 12213 } 12214 } 12215 for (let t of this.tooltipViews) 12216 if (tooltipViews.indexOf(t) < 0) { 12217 t.dom.remove(); 12218 (_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t); 12219 } 12220 this.input = input; 12221 this.tooltips = tooltips; 12222 this.tooltipViews = tooltipViews; 12223 return true; 12224 } 12225} 12226function windowSpace(view) { 12227 let { win } = view; 12228 return { top: 0, left: 0, bottom: win.innerHeight, right: win.innerWidth }; 12229} 12230const tooltipConfig = /*@__PURE__*/Facet.define({ 12231 combine: values => { 12232 var _a, _b, _c; 12233 return ({ 12234 position: browser.ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed", 12235 parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null, 12236 tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace, 12237 }); 12238 } 12239}); 12240const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class { 12241 constructor(view) { 12242 this.view = view; 12243 this.inView = true; 12244 this.lastTransaction = 0; 12245 this.measureTimeout = -1; 12246 let config = view.state.facet(tooltipConfig); 12247 this.position = config.position; 12248 this.parent = config.parent;
12249 this.classes = view.themeClasses; 12250 this.createContainer(); 12251 this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this }; 12252 this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t)); 12253 this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => { 12254 if (Date.now() > this.lastTransaction - 50 && 12255 entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1) 12256 this.measureSoon(); 12257 }, { threshold: [1] }) : null; 12258 this.observeIntersection(); 12259 view.win.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this)); 12260 this.maybeMeasure(); 12261 } 12262 createContainer() { 12263 if (this.parent) { 12264 this.container = document.createElement("div"); 12265 this.container.style.position = "relative"; 12266 this.container.className = this.view.themeClasses; 12267 this.parent.appendChild(this.container); 12268 } 12269 else { 12270 this.container = this.view.dom; 12271 } 12272 } 12273 observeIntersection() { 12274 if (this.intersectionObserver) { 12275 this.intersectionObserver.disconnect(); 12276 for (let tooltip of this.manager.tooltipViews) 12277 this.intersectionObserver.observe(tooltip.dom); 12278 } 12279 } 12280 measureSoon() { 12281 if (this.measureTimeout < 0) 12282 this.measureTimeout = setTimeout(() => { 12283 this.measureTimeout = -1; 12284 this.maybeMeasure(); 12285 }, 50); 12286 } 12287 update(update) { 12288 if (update.transactions.length) 12289 this.lastTransaction = Date.now(); 12290 let updated = this.manager.update(update); 12291 if (updated) 12292 this.observeIntersection(); 12293 let shouldMeasure = updated || update.geometryChanged; 12294 let newConfig = update.state.facet(tooltipConfig); 12295 if (newConfig.position != this.position) { 12296 this.position = newConfig.position; 12297 for (let t of this.manager.tooltipViews) 12298 t.dom.style.position = this.position; 12299 shouldMeasure = true; 12300 } 12301 if (newConfig.parent != this.parent) { 12302 if (this.parent) 12303 this.container.remove(); 12304 this.parent = newConfig.parent; 12305 this.createContainer(); 12306 for (let t of this.manager.tooltipViews) 12307 this.container.appendChild(t.dom); 12308 shouldMeasure = true; 12309 } 12310 else if (this.parent && this.view.themeClasses != this.classes) { 12311 this.classes = this.container.className = this.view.themeClasses; 12312 } 12313 if (shouldMeasure) 12314 this.maybeMeasure(); 12315 } 12316 createTooltip(tooltip) { 12317 let tooltipView = tooltip.create(this.view); 12318 tooltipView.dom.classList.add("cm-tooltip"); 12319 if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) { 12320 let arrow = document.createElement("div"); 12321 arrow.className = "cm-tooltip-arrow"; 12322 tooltipView.dom.appendChild(arrow); 12323 } 12324 tooltipView.dom.style.position = this.position; 12325 tooltipView.dom.style.top = Outside; 12326 this.container.appendChild(tooltipView.dom); 12327 if (tooltipView.mount) 12328 tooltipView.mount(this.view); 12329 return tooltipView; 12330 } 12331 destroy() { 12332 var _a, _b; 12333 this.view.win.removeEventListener("resize", this.measureSoon); 12334 for (let tooltipView of this.manager.tooltipViews) { 12335 tooltipView.dom.remove(); 12336 (_a = tooltipView.destroy) === null || _a === void 0 ? void 0 : _a.call(tooltipView); 12337 } 12338 (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect(); 12339 clearTimeout(this.measureTimeout); 12340 } 12341 readMeasure() { 12342 let editor = this.view.dom.getBoundingClientRect(); 12343 return { 12344 editor, 12345 parent: this.parent ? this.container.getBoundingClientRect() : editor, 12346 pos: this.manager.tooltips.map((t, i) => { 12347 let tv = this.manager.tooltipViews[i]; 12348 return tv.getCoords ? tv.getCoords(t.pos) : this.view.coordsAtPos(t.pos); 12349 }), 12350 size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()), 12351 space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view), 12352 }; 12353 } 12354 writeMeasure(measured) { 12355 let { editor, space } = measured; 12356 let others = []; 12357 for (let i = 0; i < this.manager.tooltips.length; i++) { 12358 let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView; 12359 let pos = measured.pos[i], size = measured.size[i]; 12360 // Hide tooltips that are outside of the editor. 12361 if (!pos || pos.bottom <= Math.max(editor.top, space.top) || 12362 pos.top >= Math.min(editor.bottom, space.bottom) || 12363 pos.right < Math.max(editor.left, space.left) - .1 || 12364 pos.left > Math.min(editor.right, space.right) + .1) { 12365 dom.style.top = Outside; 12366 continue; 12367 } 12368 let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null; 12369 let arrowHeight = arrow ? 7 /* Arrow.Size */ : 0; 12370 let width = size.right - size.left, height = size.bottom - size.top; 12371 let offset = tView.offset || noOffset, ltr = this.view.textDirection == Direction.LTR; 12372 let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width) 12373 : ltr ? Math.min(pos.left - (arrow ? 14 /* Arrow.Offset */ : 0) + offset.x, space.right - width) 12374 : Math.max(space.left, pos.left - width + (arrow ? 14 /* Arrow.Offset */ : 0) - offset.x); 12375 let above = !!tooltip.above; 12376 if (!tooltip.strictSide && (above 12377 ? pos.top - (size.bottom - size.top) - offset.y < space.top 12378 : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) && 12379 above == (space.bottom - pos.bottom > pos.top - space.top)) 12380 above = !above; 12381 let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y; 12382 let right = left + width; 12383 if (tView.overlap !== true) 12384 for (let r of others) 12385 if (r.left < right && r.right > left && r.top < top + height && r.bottom > top) 12386 top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2; 12387 if (this.position == "absolute") { 12388 dom.style.top = (top - measured.parent.top) + "px"; 12389 dom.style.left = (left - measured.parent.left) + "px"; 12390 } 12391 else { 12392 dom.style.top = top + "px"; 12393 dom.style.left = left + "px"; 12394 } 12395 if (arrow) 12396 arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Arrow.Offset */ - 7 /* Arrow.Size */)}px`; 12397 if (tView.overlap !== true) 12398 others.push({ left, top, right, bottom: top + height }); 12399 dom.classList.toggle("cm-tooltip-above", above); 12400 dom.classList.toggle("cm-tooltip-below", !above); 12401 if (tView.positioned) 12402 tView.positioned(); 12403 } 12404 } 12405 maybeMeasure() { 12406 if (this.manager.tooltips.length) { 12407 if (this.view.inView) 12408 this.view.requestMeasure(this.measureReq); 12409 if (this.inView != this.view.inView) { 12410 this.inView = this.view.inView; 12411 if (!this.inView) 12412 for (let tv of this.manager.tooltipViews) 12413 tv.dom.style.top = Outside; 12414 } 12415 } 12416 } 12417}, { 12418 eventHandlers: { 12419 scroll() { this.maybeMeasure(); } 12420 } 12421}); 12422const baseTheme$2 = /*@__PURE__*/EditorView.baseTheme({ 12423 ".cm-tooltip": { 12424 zIndex: 100 12425 }, 12426 "&light .cm-tooltip": { 12427 border: "1px solid #bbb", 12428 backgroundColor: "#f5f5f5" 12429 }, 12430 "&light .cm-tooltip-section:not(:first-child)": { 12431 borderTop: "1px solid #bbb", 12432 }, 12433 "&dark .cm-tooltip": { 12434 backgroundColor: "#333338", 12435 color: "white" 12436 }, 12437 ".cm-tooltip-arrow": { 12438 height: `${7 /* Arrow.Size */}px`, 12439 width: `${7 /* Arrow.Size */ * 2}px`, 12440 position: "absolute", 12441 zIndex: -1, 12442 overflow: "hidden", 12443 "&:before, &:after": { 12444 content: "''", 12445 position: "absolute", 12446 width: 0, 12447 height: 0, 12448 borderLeft: `${7 /* Arrow.Size */}px solid transparent`, 12449 borderRight: `${7 /* Arrow.Size */}px solid transparent`, 12450 }, 12451 ".cm-tooltip-above &": { 12452 bottom: `-${7 /* Arrow.Size */}px`, 12453 "&:before": { 12454 borderTop: `${7 /* Arrow.Size */}px solid #bbb`, 12455 }, 12456 "&:after": { 12457 borderTop: `${7 /* Arrow.Size */}px solid #f5f5f5`,
12458 bottom: "1px" 12459 } 12460 }, 12461 ".cm-tooltip-below &": { 12462 top: `-${7 /* Arrow.Size */}px`, 12463 "&:before": { 12464 borderBottom: `${7 /* Arrow.Size */}px solid #bbb`, 12465 }, 12466 "&:after": { 12467 borderBottom: `${7 /* Arrow.Size */}px solid #f5f5f5`, 12468 top: "1px" 12469 } 12470 }, 12471 }, 12472 "&dark .cm-tooltip .cm-tooltip-arrow": { 12473 "&:before": { 12474 borderTopColor: "#333338", 12475 borderBottomColor: "#333338" 12476 }, 12477 "&:after": { 12478 borderTopColor: "transparent", 12479 borderBottomColor: "transparent" 12480 } 12481 } 12482}); 12483const noOffset = { x: 0, y: 0 }; 12484/** 12485Facet to which an extension can add a value to show a tooltip. 12486*/ 12487const showTooltip = /*@__PURE__*/Facet.define({ 12488 enables: [tooltipPlugin, baseTheme$2] 12489}); 12490const showHoverTooltip = /*@__PURE__*/Facet.define(); 12491class HoverTooltipHost { 12492 constructor(view) { 12493 this.view = view; 12494 this.mounted = false; 12495 this.dom = document.createElement("div"); 12496 this.dom.classList.add("cm-tooltip-hover"); 12497 this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t)); 12498 } 12499 // Needs to be static so that host tooltip instances always match 12500 static create(view) { 12501 return new HoverTooltipHost(view); 12502 } 12503 createHostedView(tooltip) { 12504 let hostedView = tooltip.create(this.view); 12505 hostedView.dom.classList.add("cm-tooltip-section"); 12506 this.dom.appendChild(hostedView.dom); 12507 if (this.mounted && hostedView.mount) 12508 hostedView.mount(this.view); 12509 return hostedView; 12510 } 12511 mount(view) { 12512 for (let hostedView of this.manager.tooltipViews) { 12513 if (hostedView.mount) 12514 hostedView.mount(view); 12515 } 12516 this.mounted = true; 12517 } 12518 positioned() { 12519 for (let hostedView of this.manager.tooltipViews) { 12520 if (hostedView.positioned) 12521 hostedView.positioned(); 12522 } 12523 } 12524 update(update) { 12525 this.manager.update(update); 12526 } 12527} 12528const showHoverTooltipHost = /*@__PURE__*/showTooltip.compute([showHoverTooltip], state => { 12529 let tooltips = state.facet(showHoverTooltip).filter(t => t); 12530 if (tooltips.length === 0) 12531 return null; 12532 return { 12533 pos: Math.min(...tooltips.map(t => t.pos)), 12534 end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)), 12535 create: HoverTooltipHost.create, 12536 above: tooltips[0].above, 12537 arrow: tooltips.some(t => t.arrow), 12538 }; 12539}); 12540class HoverPlugin { 12541 constructor(view, source, field, setHover, hoverTime) { 12542 this.view = view; 12543 this.source = source; 12544 this.field = field; 12545 this.setHover = setHover; 12546 this.hoverTime = hoverTime; 12547 this.hoverTimeout = -1; 12548 this.restartTimeout = -1; 12549 this.pending = null; 12550 this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 }; 12551 this.checkHover = this.checkHover.bind(this); 12552 view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this)); 12553 view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this)); 12554 } 12555 update() { 12556 if (this.pending) { 12557 this.pending = null; 12558 clearTimeout(this.restartTimeout); 12559 this.restartTimeout = setTimeout(() => this.startHover(), 20); 12560 } 12561 } 12562 get active() { 12563 return this.view.state.field(this.field); 12564 } 12565 checkHover() { 12566 this.hoverTimeout = -1; 12567 if (this.active) 12568 return; 12569 let hovered = Date.now() - this.lastMove.time; 12570 if (hovered < this.hoverTime) 12571 this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered); 12572 else 12573 this.startHover(); 12574 } 12575 startHover() { 12576 clearTimeout(this.restartTimeout); 12577 let { lastMove } = this; 12578 let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null; 12579 if (pos == null) 12580 return; 12581 let posCoords = this.view.coordsAtPos(pos); 12582 if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom || 12583 lastMove.x < posCoords.left - this.view.defaultCharacterWidth || 12584 lastMove.x > posCoords.right + this.view.defaultCharacterWidth) 12585 return; 12586 let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos); 12587 let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1; 12588 let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl)); 12589 if (open === null || open === void 0 ? void 0 : open.then) { 12590 let pending = this.pending = { pos }; 12591 open.then(result => { 12592 if (this.pending == pending) { 12593 this.pending = null; 12594 if (result) 12595 this.view.dispatch({ effects: this.setHover.of(result) }); 12596 } 12597 }, e =>
12597 logException(this.view.state, e, "hover tooltip")); 12598 } 12599 else if (open) { 12600 this.view.dispatch({ effects: this.setHover.of(open) }); 12601 } 12602 } 12603 mousemove(event) { 12604 var _a; 12605 this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() }; 12606 if (this.hoverTimeout < 0) 12607 this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime); 12608 let tooltip = this.active; 12609 if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) { 12610 let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos; 12611 if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos 12612 : !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* Hover.MaxDist */))) { 12613 this.view.dispatch({ effects: this.setHover.of(null) }); 12614 this.pending = null; 12615 } 12616 } 12617 } 12618 mouseleave() { 12619 clearTimeout(this.hoverTimeout); 12620 this.hoverTimeout = -1; 12621 if (this.active) 12622 this.view.dispatch({ effects: this.setHover.of(null) }); 12623 } 12624 destroy() { 12625 clearTimeout(this.hoverTimeout); 12626 this.view.dom.removeEventListener("mouseleave", this.mouseleave); 12627 this.view.dom.removeEventListener("mousemove", this.mousemove); 12628 } 12629} 12630function isInTooltip(elt) { 12631 for (let cur = elt; cur; cur = cur.parentNode) 12632 if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip")) 12633 return true; 12634 return false; 12635} 12636function isOverRange(view, from, to, x, y, margin) { 12637 let range = document.createRange(); 12638 let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to); 12639 range.setEnd(toDOM.node, toDOM.offset); 12640 range.setStart(fromDOM.node, fromDOM.offset); 12641 let rects = range.getClientRects(); 12642 range.detach(); 12643 for (let i = 0; i < rects.length; i++) { 12644 let rect = rects[i]; 12645 let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right); 12646 if (dist <= margin) 12647 return true; 12648 } 12649 return false; 12650} 12651/** 12652Set up a hover tooltip, which shows up when the pointer hovers 12653over ranges of text. The callback is called when the mouse hovers 12654over the document text. It should, if there is a tooltip 12655associated with position `pos`, return the tooltip description 12656(either directly or in a promise). The `side` argument indicates 12657on which side of the position the pointer isâit will be -1 if the 12658pointer is before the position, 1 if after the position. 12659 12660Note that all hover tooltips are hosted within a single tooltip 12661container element. This allows multiple tooltips over the same 12662range to be "merged" together without overlapping. 12663*/ 12664function hoverTooltip(source, options = {}) { 12665 let setHover = StateEffect.define(); 12666 let hoverState = StateField.define({ 12667 create() { return null; }, 12668 update(value, tr) { 12669 if (value && (options.hideOnChange && (tr.docChanged || tr.selection) || 12670 options.hideOn && options.hideOn(tr, value))) 12671 return null; 12672 if (value && tr.docChanged) { 12673 let newPos = tr.changes.mapPos(value.pos, -1, MapMode.TrackDel); 12674 if (newPos == null) 12675 return null; 12676 let copy = Object.assign(Object.create(null), value); 12677 copy.pos = newPos; 12678 if (value.end != null) 12679 copy.end = tr.changes.mapPos(value.end); 12680 value = copy; 12681 } 12682 for (let effect of tr.effects) { 12683 if (effect.is(setHover)) 12684 value = effect.value; 12685 if (effect.is(closeHoverTooltipEffect)) 12686 value = null; 12687 } 12688 return value; 12689 }, 12690 provide: f => showHoverTooltip.from(f) 12691 }); 12692 return [ 12693 hoverState, 12694 ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, options.hoverTime || 300 /* Hover.Time */)), 12695 showHoverTooltipHost 12696 ]; 12697} 12698/** 12699Get the active tooltip view for a given tooltip, if available. 12700*/ 12701function getTooltip(view, tooltip) { 12702 let plugin = view.plugin(tooltipPlugin); 12703 if (!plugin) 12704 return null; 12705 let found = plugin.manager.tooltips.indexOf(tooltip); 12706 return found < 0 ? null : plugin.manager.tooltipViews[found]; 12707}
vendor: 5,260 bytes, lines 12708-12854
12708const closeHoverTooltipEffect = /*@__PURE__*/StateEffect.define(); 12709 12710const panelConfig = /*@__PURE__*/Facet.define({ 12711 combine(configs) { 12712 let topContainer, bottomContainer; 12713 for (let c of configs) { 12714 topContainer = topContainer || c.topContainer; 12715 bottomContainer = bottomContainer || c.bottomContainer; 12716 } 12717 return { topContainer, bottomContainer }; 12718 } 12719}); 12720/** 12721Get the active panel created by the given constructor, if any. 12722This can be useful when you need access to your panels' DOM 12723structure. 12724*/ 12725function getPanel(view, panel) { 12726 let plugin = view.plugin(panelPlugin); 12727 let index = plugin ? plugin.specs.indexOf(panel) : -1; 12728 return index > -1 ? plugin.panels[index] : null; 12729} 12730const panelPlugin = /*@__PURE__*/ViewPlugin.fromClass(class { 12731 constructor(view) { 12732 this.input = view.state.facet(showPanel); 12733 this.specs = this.input.filter(s => s); 12734 this.panels = this.specs.map(spec => spec(view)); 12735 let conf = view.state.facet(panelConfig); 12736 this.top = new PanelGroup(view, true, conf.topContainer); 12737 this.bottom = new PanelGroup(view, false, conf.bottomContainer); 12738 this.top.sync(this.panels.filter(p => p.top)); 12739 this.bottom.sync(this.panels.filter(p => !p.top)); 12740 for (let p of this.panels) { 12741 p.dom.classList.add("cm-panel"); 12742 if (p.mount) 12743 p.mount(); 12744 } 12745 } 12746 update(update) { 12747 let conf = update.state.facet(panelConfig); 12748 if (this.top.container != conf.topContainer) { 12749 this.top.sync([]); 12750 this.top = new PanelGroup(update.view, true, conf.topContainer); 12751 } 12752 if (this.bottom.container != conf.bottomContainer) { 12753 this.bottom.sync([]); 12754 this.bottom = new PanelGroup(update.view, false, conf.bottomContainer); 12755 } 12756 this.top.syncClasses(); 12757 this.bottom.syncClasses(); 12758 let input = update.state.facet(showPanel); 12759 if (input != this.input) { 12760 let specs = input.filter(x => x); 12761 let panels = [], top = [], bottom = [], mount = []; 12762 for (let spec of specs) { 12763 let known = this.specs.indexOf(spec), panel; 12764 if (known < 0) { 12765 panel = spec(update.view); 12766 mount.push(panel); 12767 } 12768 else { 12769 panel = this.panels[known]; 12770 if (panel.update) 12771 panel.update(update); 12772 } 12773 panels.push(panel); 12774 (panel.top ? top : bottom).push(panel); 12775 } 12776 this.specs = specs; 12777 this.panels = panels; 12778 this.top.sync(top); 12779 this.bottom.sync(bottom); 12780 for (let p of mount) { 12781 p.dom.classList.add("cm-panel"); 12782 if (p.mount) 12783 p.mount(); 12784 } 12785 } 12786 else { 12787 for (let p of this.panels) 12788 if (p.update) 12789 p.update(update); 12790 } 12791 } 12792 destroy() { 12793 this.top.sync([]); 12794 this.bottom.sync([]); 12795 } 12796}, { 12797 provide: plugin => EditorView.scrollMargins.of(view => { 12798 let value = view.plugin(plugin); 12799 return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() }; 12800 }) 12801}); 12802class PanelGroup { 12803 constructor(view, top, container) { 12804 this.view = view; 12805 this.top = top; 12806 this.container = container; 12807 this.dom = undefined; 12808 this.classes = ""; 12809 this.panels = []; 12810 this.syncClasses(); 12811 } 12812 sync(panels) { 12813 for (let p of this.panels) 12814 if (p.destroy && panels.indexOf(p) < 0) 12815 p.destroy(); 12816 this.panels = panels; 12817 this.syncDOM(); 12818 } 12819 syncDOM() { 12820 if (this.panels.length == 0) { 12821 if (this.dom) { 12822 this.dom.remove(); 12823 this.dom = undefined; 12824 } 12825 return; 12826 } 12827 if (!this.dom) { 12828 this.dom = document.createElement("div"); 12829 this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom"; 12830 this.dom.style[this.top ? "top" : "bottom"] = "0"; 12831 let parent = this.container || this.view.dom; 12832 parent.insertBefore(this.dom, this.top ? parent.firstChild : null); 12833 } 12834 let curDOM = this.dom.firstChild; 12835 for (let panel of this.panels) { 12836 if (panel.dom.parentNode == this.dom) { 12837 while (curDOM != panel.dom) 12838 curDOM = rm(curDOM); 12839 curDOM = curDOM.nextSibling; 12840 } 12841 else { 12842 this.dom.insertBefore(panel.dom, curDOM); 12843 } 12844 } 12845 while (curDOM) 12846 curDOM = rm(curDOM); 12847 } 12848 scrollMargin() { 12849 return !this.dom || this.container ? 0 12850 : Math.max(0, this.top ? 12851 this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) : 12852 Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top); 12853 } 12854 syncClasses() {
12855 if (!this.container || this.classes == this.view.themeClasses) 12856 return; 12857 for (let cls of this.classes.split(" ")) 12858 if (cls) 12859 this.container.classList.remove(cls); 12860 for (let cls of (this.classes = this.view.themeClasses).split(" ")) 12861 if (cls) 12862 this.container.classList.add(cls); 12863 } 12864} 12865function rm(node) { 12866 let next = node.nextSibling; 12867 node.remove(); 12868 return next; 12869} 12870/** 12871Opening a panel is done by providing a constructor function for 12872the panel through this facet. (The panel is closed again when its 12873constructor is no longer provided.) Values of `null` are ignored. 12874*/ 12875const showPanel = /*@__PURE__*/Facet.define({ 12876 enables: panelPlugin 12877}); 12878 12879/** 12880A gutter marker represents a bit of information attached to a line 12881in a specific gutter. Your own custom markers have to extend this 12882class. 12883*/ 12884class GutterMarker extends RangeValue { 12885 /** 12886 @internal 12887 */ 12888 compare(other) { 12889 return this == other || this.constructor == other.constructor && this.eq(other); 12890 } 12891 /** 12892 Compare this marker to another marker of the same type. 12893 */ 12894 eq(other) { return false; } 12895 /** 12896 Called if the marker has a `toDOM` method and its representation 12897 was removed from a gutter. 12898 */ 12899 destroy(dom) { } 12900} 12901GutterMarker.prototype.elementClass = ""; 12902GutterMarker.prototype.toDOM = undefined; 12903GutterMarker.prototype.mapMode = MapMode.TrackBefore; 12904GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1; 12905GutterMarker.prototype.point = true; 12906/** 12907Facet used to add a class to all gutter elements for a given line. 12908Markers given to this facet should _only_ define an 12909[`elementclass`](https://codemirror.net/6/docs/ref/#view.GutterMarker.elementClass), not a 12910[`toDOM`](https://codemirror.net/6/docs/ref/#view.GutterMarker.toDOM) (or the marker will appear 12911in all gutters for the line). 12912*/ 12913const gutterLineClass = /*@__PURE__*/Facet.define(); 12914const defaults$1 = { 12915 class: "", 12916 renderEmptyElements: false, 12917 elementStyle: "", 12918 markers: () => RangeSet.empty, 12919 lineMarker: () => null, 12920 lineMarkerChange: null, 12921 initialSpacer: null, 12922 updateSpacer: null, 12923 domEventHandlers: {} 12924}; 12925const activeGutters = /*@__PURE__*/Facet.define(); 12926/** 12927Define an editor gutter. The order in which the gutters appear is 12928determined by their extension priority. 12929*/ 12930function gutter(config) { 12931 return [gutters(), activeGutters.of(Object.assign(Object.assign({}, defaults$1), config))]; 12932} 12933const unfixGutters = /*@__PURE__*/Facet.define({ 12934 combine: values => values.some(x => x) 12935}); 12936/** 12937The gutter-drawing plugin is automatically enabled when you add a 12938gutter, but you can use this function to explicitly configure it. 12939 12940Unless `fixed` is explicitly set to `false`, the gutters are 12941fixed, meaning they don't scroll along with the content 12942horizontally (except on Internet Explorer, which doesn't support 12943CSS [`position: 12944sticky`](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky)). 12945*/ 12946function gutters(config) { 12947 let result = [ 12948 gutterView, 12949 ]; 12950 if (config && config.fixed === false) 12951 result.push(unfixGutters.of(true)); 12952 return result; 12953} 12954const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class { 12955 constructor(view) { 12956 this.view = view; 12957 this.prevViewport = view.viewport; 12958 this.dom = document.createElement("div"); 12959 this.dom.className = "cm-gutters"; 12960 this.dom.setAttribute("aria-hidden", "true"); 12961 this.dom.style.minHeight = this.view.contentHeight + "px"; 12962 this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf)); 12963 for (let gutter of this.gutters) 12964 this.dom.appendChild(gutter.dom); 12965 this.fixed = !view.state.facet(unfixGutters); 12966 if (this.fixed) { 12967 // FIXME IE11 fallback, which doesn't support position: sticky, 12968 // by using position: relative + event handlers that realign the 12969 // gutter (or just force fixed=false on IE11?) 12970 this.dom.style.position = "sticky"; 12971 } 12972 this.syncGutters(false); 12973 view.scrollDOM.insertBefore(this.dom, view.contentDOM); 12974 } 12975 update(update) { 12976 if (this.updateGutters(update)) { 12977 // Detach during sync when the viewport changed significantly 12978 // (such as during scrolling), since for large updates that is 12979 // faster. 12980 let vpA = this.prevViewport, vpB = update.view.viewport; 12981 let vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from); 12982 this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8); 12983 } 12984 if (update.geometryChanged) 12985 this.dom.style.minHeight = this.view.contentHeight + "px"; 12986 if (this.view.state.facet(unfixGutters) != !this.fixed) { 12987 this.fixed = !this.fixed; 12988 this.dom.style.position = this.fixed ? "sticky" : ""; 12989 } 12990 this.prevViewport = update.view.viewport; 12991 } 12992 syncGutters(detach) { 12993 let after = this.dom.nextSibling; 12994 if (detach) 12995 this.dom.remove(); 12996 let lineClasses = RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from); 12997 let classSet = []; 12998 let contexts = this.gutters.map(gutter => new UpdateContext(gutter, this.view.viewport, -this.view.documentPadding.top)); 12999 for (let line of this.view.viewportLineBlocks) { 13000 let text; 13001 if (Array.isArray(line.type)) { 13002 for (let b of line.type) 13003 if (b.type == BlockType.Text) { 13004 text = b; 13005 break; 13006 } 13007 } 13008 else { 13009 text = line.type == BlockType.Text ? line : undefined; 13010 } 13011 if (!text) 13012 continue; 13013 if (classSet.length) 13014 classSet = []; 13015 advanceCursor(lineClasses, classSet, line.from); 13016 for (let cx of contexts) 13017 cx.line(this.view, text, classSet); 13018 } 13019 for (let cx of contexts) 13020 cx.finish(); 13021 if (detach) 13022 this.view.scrollDOM.insertBefore(this.dom, after); 13023 } 13024 updateGutters(update) { 13025 let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters); 13026 let change = update.docChanged || update.heightChanged || update.viewportChanged || 13027 !RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to); 13028 if (prev == cur) { 13029 for (let gutter of this.gutters) 13030 if (gutter.update(update)) 13031 change = true; 13032 } 13033 else { 13034 change = true; 13035 let gutters = []; 13036 for (let conf of cur) { 13037 let known = prev.indexOf(conf); 13038 if (known < 0) { 13039 gutters.push(new SingleGutterView(this.view, conf)); 13040 } 13041 else {
13042 this.gutters[known].update(update); 13043 gutters.push(this.gutters[known]); 13044 } 13045 } 13046 for (let g of this.gutters) { 13047 g.dom.remove(); 13048 if (gutters.indexOf(g) < 0) 13049 g.destroy(); 13050 } 13051 for (let g of gutters) 13052 this.dom.appendChild(g.dom); 13053 this.gutters = gutters; 13054 } 13055 return change; 13056 } 13057 destroy() { 13058 for (let view of this.gutters) 13059 view.destroy(); 13060 this.dom.remove(); 13061 } 13062}, { 13063 provide: plugin => EditorView.scrollMargins.of(view => { 13064 let value = view.plugin(plugin); 13065 if (!value || value.gutters.length == 0 || !value.fixed) 13066 return null; 13067 return view.textDirection == Direction.LTR ? { left: value.dom.offsetWidth } : { right: value.dom.offsetWidth }; 13068 }) 13069}); 13070function asArray(val) { return (Array.isArray(val) ? val : [val]); } 13071function advanceCursor(cursor, collect, pos) { 13072 while (cursor.value && cursor.from <= pos) { 13073 if (cursor.from == pos) 13074 collect.push(cursor.value); 13075 cursor.next(); 13076 } 13077} 13078class UpdateContext { 13079 constructor(gutter, viewport, height) { 13080 this.gutter = gutter; 13081 this.height = height; 13082 this.localMarkers = []; 13083 this.i = 0; 13084 this.cursor = RangeSet.iter(gutter.markers, viewport.from); 13085 } 13086 line(view, line, extraMarkers) { 13087 if (this.localMarkers.length) 13088 this.localMarkers = []; 13089 advanceCursor(this.cursor, this.localMarkers, line.from); 13090 let localMarkers = extraMarkers.length ? this.localMarkers.concat(extraMarkers) : this.localMarkers; 13091 let forLine = this.gutter.config.lineMarker(view, line, localMarkers); 13092 if (forLine) 13093 localMarkers.unshift(forLine); 13094 let gutter = this.gutter; 13095 if (localMarkers.length == 0 && !gutter.config.renderEmptyElements) 13096 return; 13097 let above = line.top - this.height; 13098 if (this.i == gutter.elements.length) { 13099 let newElt = new GutterElement(view, line.height, above, localMarkers); 13100 gutter.elements.push(newElt); 13101 gutter.dom.appendChild(newElt.dom); 13102 } 13103 else { 13104 gutter.elements[this.i].update(view, line.height, above, localMarkers); 13105 } 13106 this.height = line.bottom; 13107 this.i++; 13108 } 13109 finish() { 13110 let gutter = this.gutter; 13111 while (gutter.elements.length > this.i) { 13112 let last = gutter.elements.pop(); 13113 gutter.dom.removeChild(last.dom); 13114 last.destroy(); 13115 } 13116 } 13117} 13118class SingleGutterView { 13119 constructor(view, config) { 13120 this.view = view; 13121 this.config = config; 13122 this.elements = []; 13123 this.spacer = null; 13124 this.dom = document.createElement("div"); 13125 this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : ""); 13126 for (let prop in config.domEventHandlers) { 13127 this.dom.addEventListener(prop, (event) => { 13128 let line = view.lineBlockAtHeight(event.clientY - view.documentTop); 13129 if (config.domEventHandlers[prop](view, line, event)) 13130 event.preventDefault(); 13131 }); 13132 } 13133 this.markers = asArray(config.markers(view)); 13134 if (config.initialSpacer) { 13135 this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]); 13136 this.dom.appendChild(this.spacer.dom); 13137 this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none"; 13138 } 13139 } 13140 update(update) { 13141 let prevMarkers = this.markers; 13142 this.markers = asArray(this.config.markers(update.view)); 13143 if (this.spacer && this.config.updateSpacer) { 13144 let updated = this.config.updateSpacer(this.spacer.markers[0], update); 13145 if (updated != this.spacer.markers[0]) 13146 this.spacer.update(update.view, 0, 0, [updated]); 13147 } 13148 let vp = update.view.viewport; 13149 return !RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) || 13150 (this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false); 13151 } 13152 destroy() { 13153 for (let elt of this.elements) 13154 elt.destroy(); 13155 } 13156} 13157class GutterElement { 13158 constructor(view, height, above, markers) { 13159 this.height = -1; 13160 this.above = 0; 13161 this.markers = []; 13162 this.dom = document.createElement("div"); 13163 this.dom.className = "cm-gutterElement"; 13164 this.update(view, height, above, markers); 13165 } 13166 update(view, height, above, markers) { 13167 if (this.height != height) 13168 this.dom.style.height = (this.height = height) + "px"; 13169 if (this.above != above) 13170 this.dom.style.marginTop = (this.above = above) ? above + "px" : ""; 13171 if (!sameMarkers(this.markers, markers)) 13172 this.setMarkers(view, markers); 13173 } 13174 setMarkers(view, markers) { 13175 let cls = "cm-gutterElement", domPos = this.dom.firstChild; 13176 for (let iNew = 0, iOld = 0;;) { 13177 let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
13178 if (marker) { 13179 let c = marker.elementClass; 13180 if (c) 13181 cls += " " + c; 13182 for (let i = iOld; i < this.markers.length; i++) 13183 if (this.markers[i].compare(marker)) { 13184 skipTo = i; 13185 matched = true; 13186 break; 13187 } 13188 } 13189 else { 13190 skipTo = this.markers.length; 13191 } 13192 while (iOld < skipTo) { 13193 let next = this.markers[iOld++]; 13194 if (next.toDOM) { 13195 next.destroy(domPos); 13196 let after = domPos.nextSibling; 13197 domPos.remove(); 13198 domPos = after; 13199 } 13200 } 13201 if (!marker) 13202 break; 13203 if (marker.toDOM) { 13204 if (matched) 13205 domPos = domPos.nextSibling; 13206 else 13207 this.dom.insertBefore(marker.toDOM(view), domPos); 13208 } 13209 if (matched) 13210 iOld++; 13211 } 13212 this.dom.className = cls; 13213 this.markers = markers; 13214 } 13215 destroy() { 13216 this.setMarkers(null, []); // First argument not used unless creating markers 13217 } 13218} 13219function sameMarkers(a, b) { 13220 if (a.length != b.length) 13221 return false; 13222 for (let i = 0; i < a.length; i++) 13223 if (!a[i].compare(b[i])) 13224 return false; 13225 return true; 13226} 13227/** 13228Facet used to provide markers to the line number gutter. 13229*/ 13230const lineNumberMarkers = /*@__PURE__*/Facet.define(); 13231const lineNumberConfig = /*@__PURE__*/Facet.define({ 13232 combine(values) { 13233 return combineConfig(values, { formatNumber: String, domEventHandlers: {} }, { 13234 domEventHandlers(a, b) { 13235 let result = Object.assign({}, a); 13236 for (let event in b) { 13237 let exists = result[event], add = b[event]; 13238 result[event] = exists ? (view, line, event) => exists(view, line, event) || add(view, line, event) : add; 13239 } 13240 return result; 13241 } 13242 }); 13243 } 13244}); 13245class NumberMarker extends GutterMarker { 13246 constructor(number) { 13247 super(); 13248 this.number = number; 13249 } 13250 eq(other) { return this.number == other.number; } 13251 toDOM() { return document.createTextNode(this.number); } 13252} 13253function formatNumber(view, number) { 13254 return view.state.facet(lineNumberConfig).formatNumber(number, view.state); 13255} 13256const lineNumberGutter = /*@__PURE__*/activeGutters.compute([lineNumberConfig], state => ({ 13257 class: "cm-lineNumbers", 13258 renderEmptyElements: false, 13259 markers(view) { return view.state.facet(lineNumberMarkers); }, 13260 lineMarker(view, line, others) { 13261 if (others.some(m => m.toDOM)) 13262 return null; 13263 return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number)); 13264 }, 13265 lineMarkerChange: update => update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig), 13266 initialSpacer(view) { 13267 return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines))); 13268 }, 13269 updateSpacer(spacer, update) { 13270 let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines)); 13271 return max == spacer.number ? spacer : new NumberMarker(max); 13272 }, 13273 domEventHandlers: state.facet(lineNumberConfig).domEventHandlers 13274})); 13275/** 13276Create a line number gutter extension. 13277*/ 13278function lineNumbers(config = {}) { 13279 return [ 13280 lineNumberConfig.of(config), 13281 gutters(), 13282 lineNumberGutter 13283 ]; 13284} 13285function maxLineNumber(lines) { 13286 let last = 9; 13287 while (last < lines) 13288 last = last * 10 + 9; 13289 return last; 13290} 13291 13292// FIXME profile adding a per-Tree TreeNode cache, validating it by 13293// parent pointer 13294/// The default maximum length of a `TreeBuffer` node. 13295const DefaultBufferLength = 1024; 13296let nextPropID = 0; 13297class Range { 13298 constructor(from, to) { 13299 this.from = from; 13300 this.to = to; 13301 } 13302} 13303/// Each [node type](#common.NodeType) or [individual tree](#common.Tree) 13304/// can have metadata associated with it in props. Instances of this 13305/// class represent prop names. 13306class NodeProp { 13307 /// Create a new node prop type. 13308 constructor(config = {}) { 13309 this.id = nextPropID++; 13310 this.perNode = !!config.perNode; 13311 this.deserialize = config.deserialize || (() => { 13312 throw new Error("This node type doesn't define a deserialize function"); 13313 }); 13314 } 13315 /// This is meant to be used with 13316 /// [`NodeSet.extend`](#common.NodeSet.extend) or 13317 /// [`LRParser.configure`](#lr.ParserConfig.props) to compute 13318 /// prop values for each node type in the set. Takes a [match 13319 /// object](#common.NodeType^match) or function that returns undefined 13320 /// if the node type doesn't get this prop, and the prop's value if 13321 /// it does. 13322 add(match) { 13323 if (this.perNode) 13324 throw new RangeError("Can't add per-node props to node types"); 13325 if (typeof match != "function") 13326 match = NodeType.match(match); 13327 return (type) => { 13328 let result = match(type); 13329 return result === undefined ? null : [this, result]; 13330 }; 13331 } 13332} 13333/// Prop that is used to describe matching delimiters. For opening 13334/// delimiters, this holds an array of node names (written as a 13335/// space-separated string when declaring this prop in a grammar) 13336/// for the node types of closing delimiters that match it. 13337NodeProp.closedBy = new NodeProp({ deserialize: str => str.split(" ") }); 13338/// The inverse of [`closedBy`](#common.NodeProp^closedBy). This is 13339/// attached to closing delimiters, holding an array of node names 13340/// of types of matching opening delimiters. 13341NodeProp.openedBy = new NodeProp({ deserialize: str => str.split(" ") }); 13342/// Used to assign node types to groups (for example, all node 13343/// types that represent an expression could be tagged with an 13344/// `"Expression"` group). 13345NodeProp.group = new NodeProp({ deserialize: str => str.split(" ") }); 13346/// The hash of the [context](#lr.ContextTracker.constructor) 13347/// that the node was parsed in, if any. Used to limit reuse of 13348/// contextual nodes. 13349NodeProp.contextHash = new NodeProp({ perNode: true }); 13350/// The distance beyond the end of the node that the tokenizer 13351/// looked ahead for any of the tokens inside the node. (The LR 13352/// parser only stores this when it is larger than 25, for
vendor: 11,005 bytes, lines 13353-13609
13353/// efficiency reasons.) 13354NodeProp.lookAhead = new NodeProp({ perNode: true }); 13355/// This per-node prop is used to replace a given node, or part of a 13356/// node, with another tree. This is useful to include trees from 13357/// different languages in mixed-language parsers. 13358NodeProp.mounted = new NodeProp({ perNode: true }); 13359/// A mounted tree, which can be [stored](#common.NodeProp^mounted) on 13360/// a tree node to indicate that parts of its content are 13361/// represented by another tree. 13362class MountedTree { 13363 constructor( 13364 /// The inner tree. 13365 tree, 13366 /// If this is null, this tree replaces the entire node (it will 13367 /// be included in the regular iteration instead of its host 13368 /// node). If not, only the given ranges are considered to be 13369 /// covered by this tree. This is used for trees that are mixed in 13370 /// a way that isn't strictly hierarchical. Such mounted trees are 13371 /// only entered by [`resolveInner`](#common.Tree.resolveInner) 13372 /// and [`enter`](#common.SyntaxNode.enter). 13373 overlay, 13374 /// The parser used to create this subtree. 13375 parser) { 13376 this.tree = tree; 13377 this.overlay = overlay; 13378 this.parser = parser; 13379 } 13380} 13381const noProps = Object.create(null); 13382/// Each node in a syntax tree has a node type associated with it. 13383class NodeType { 13384 /// @internal 13385 constructor( 13386 /// The name of the node type. Not necessarily unique, but if the 13387 /// grammar was written properly, different node types with the 13388 /// same name within a node set should play the same semantic 13389 /// role. 13390 name, 13391 /// @internal 13392 props, 13393 /// The id of this node in its set. Corresponds to the term ids 13394 /// used in the parser. 13395 id, 13396 /// @internal 13397 flags = 0) { 13398 this.name = name; 13399 this.props = props; 13400 this.id = id; 13401 this.flags = flags; 13402 } 13403 /// Define a node type. 13404 static define(spec) { 13405 let props = spec.props && spec.props.length ? Object.create(null) : noProps; 13406 let flags = (spec.top ? 1 /* NodeFlag.Top */ : 0) | (spec.skipped ? 2 /* NodeFlag.Skipped */ : 0) | 13407 (spec.error ? 4 /* NodeFlag.Error */ : 0) | (spec.name == null ? 8 /* NodeFlag.Anonymous */ : 0); 13408 let type = new NodeType(spec.name || "", props, spec.id, flags); 13409 if (spec.props) 13410 for (let src of spec.props) { 13411 if (!Array.isArray(src)) 13412 src = src(type); 13413 if (src) { 13414 if (src[0].perNode) 13415 throw new RangeError("Can't store a per-node prop on a node type"); 13416 props[src[0].id] = src[1]; 13417 } 13418 } 13419 return type; 13420 } 13421 /// Retrieves a node prop for this type. Will return `undefined` if 13422 /// the prop isn't present on this node. 13423 prop(prop) { return this.props[prop.id]; } 13424 /// True when this is the top node of a grammar. 13425 get isTop() { return (this.flags & 1 /* NodeFlag.Top */) > 0; } 13426 /// True when this node is produced by a skip rule. 13427 get isSkipped() { return (this.flags & 2 /* NodeFlag.Skipped */) > 0; } 13428 /// Indicates whether this is an error node. 13429 get isError() { return (this.flags & 4 /* NodeFlag.Error */) > 0; } 13430 /// When true, this node type doesn't correspond to a user-declared 13431 /// named node, for example because it is used to cache repetition. 13432 get isAnonymous() { return (this.flags & 8 /* NodeFlag.Anonymous */) > 0; } 13433 /// Returns true when this node's name or one of its 13434 /// [groups](#common.NodeProp^group) matches the given string. 13435 is(name) { 13436 if (typeof name == 'string') { 13437 if (this.name == name) 13438 return true; 13439 let group = this.prop(NodeProp.group); 13440 return group ? group.indexOf(name) > -1 : false; 13441 } 13442 return this.id == name; 13443 } 13444 /// Create a function from node types to arbitrary values by 13445 /// specifying an object whose property names are node or 13446 /// [group](#common.NodeProp^group) names. Often useful with 13447 /// [`NodeProp.add`](#common.NodeProp.add). You can put multiple 13448 /// names, separated by spaces, in a single property name to map 13449 /// multiple node names to a single value. 13450 static match(map) { 13451 let direct = Object.create(null); 13452 for (let prop in map) 13453 for (let name of prop.split(" ")) 13454 direct[name] = map[prop]; 13455 return (node) => { 13456 for (let groups = node.prop(NodeProp.group), i = -1; i < (groups ? groups.length : 0); i++) { 13457 let found = direct[i < 0 ? node.name : groups[i]]; 13458 if (found) 13459 return found; 13460 } 13461 }; 13462 } 13463} 13464/// An empty dummy node type to use when no actual type is available. 13465NodeType.none = new NodeType("", Object.create(null), 0, 8 /* NodeFlag.Anonymous */); 13466/// A node set holds a collection of node types. It is used to 13467/// compactly represent trees by storing their type ids, rather than a 13468/// full pointer to the type object, in a numeric array. Each parser 13469/// [has](#lr.LRParser.nodeSet) a node set, and [tree 13470/// buffers](#common.TreeBuffer) can only store collections of nodes 13471/// from the same set. A set can have a maximum of 2**16 (65536) node 13472/// types in it, so that the ids fit into 16-bit typed array slots. 13473class NodeSet { 13474 /// Create a set with the given types. The `id` property of each 13475 /// type should correspond to its position within the array. 13476 constructor( 13477 /// The node types in this set, by id. 13478 types) { 13479 this.types = types; 13480 for (let i = 0; i < types.length; i++) 13481 if (types[i].id != i) 13482 throw new RangeError("Node type ids should correspond to array positions when creating a node set"); 13483 } 13484 /// Create a copy of this set with some node properties added. The 13485 /// arguments to this method can be created with 13486 /// [`NodeProp.add`](#common.NodeProp.add). 13487 extend(...props) { 13488 let newTypes = []; 13489 for (let type of this.types) { 13490 let newProps = null; 13491 for (let source of props) { 13492 let add = source(type); 13493 if (add) { 13494 if (!newProps) 13495 newProps = Object.assign({}, type.props); 13496 newProps[add[0].id] = add[1]; 13497 } 13498 } 13499 newTypes.push(newProps ? new NodeType(type.name, newProps, type.id, type.flags) : type); 13500 } 13501 return new NodeSet(newTypes); 13502 } 13503} 13504const CachedNode = new WeakMap(), CachedInnerNode = new WeakMap(); 13505/// Options that control iteration. Can be combined with the `|` 13506/// operator to enable multiple ones. 13507var IterMode; 13508(function (IterMode) { 13509 /// When enabled, iteration will only visit [`Tree`](#common.Tree) 13510 /// objects, not nodes packed into 13511 /// [`TreeBuffer`](#common.TreeBuffer)s. 13512 IterMode[IterMode["ExcludeBuffers"] = 1] = "ExcludeBuffers"; 13513 /// Enable this to make iteration include anonymous nodes (such as 13514 /// the nodes that wrap repeated grammar constructs into a balanced 13515 /// tree). 13516 IterMode[IterMode["IncludeAnonymous"] = 2] = "IncludeAnonymous"; 13517 /// By default, regular [mounted](#common.NodeProp^mounted) nodes 13518 /// replace their base node in iteration. Enable this to ignore them 13519 /// instead. 13520 IterMode[IterMode["IgnoreMounts"] = 4] = "IgnoreMounts"; 13521 /// This option only applies in 13522 /// [`enter`](#common.SyntaxNode.enter)-style methods. It tells the 13523 /// library to not enter mounted overlays if one covers the given 13524 /// position. 13525 IterMode[IterMode["IgnoreOverlays"] = 8] = "IgnoreOverlays"; 13526})(IterMode || (IterMode = {})); 13527/// A piece of syntax tree. There are two ways to approach these 13528/// trees: the way they are actually stored in memory, and the 13529/// convenient way. 13530/// 13531/// Syntax trees are stored as a tree of `Tree` and `TreeBuffer` 13532/// objects. By packing detail information into `TreeBuffer` leaf 13533/// nodes, the representation is made a lot more memory-efficient. 13534/// 13535/// However, when you want to actually work with tree nodes, this 13536/// representation is very awkward, so most client code will want to 13537/// use the [`TreeCursor`](#common.TreeCursor) or 13538/// [`SyntaxNode`](#common.SyntaxNode) interface instead, which provides 13539/// a view on some part of this data structure, and can be used to 13540/// move around to adjacent nodes. 13541class Tree { 13542 /// Construct a new tree. See also [`Tree.build`](#common.Tree^build). 13543 constructor( 13544 /// The type of the top node. 13545 type, 13546 /// This node's child nodes. 13547 children, 13548 /// The positions (offsets relative to the start of this tree) of 13549 /// the children. 13550 positions, 13551 /// The total length of this tree 13552 length, 13553 /// Per-node [node props](#common.NodeProp) to associate with this node. 13554 props) { 13555 this.type = type; 13556 this.children = children; 13557 this.positions = positions; 13558 this.length = length; 13559 /// @internal 13560 this.props = null; 13561 if (props && props.length) { 13562 this.props = Object.create(null); 13563 for (let [prop, value] of props) 13564 this.props[typeof prop == "number" ? prop : prop.id] = value; 13565 } 13566 } 13567 /// @internal 13568 toString() { 13569 let mounted = this.prop(NodeProp.mounted); 13570 if (mounted && !mounted.overlay) 13571 return mounted.tree.toString(); 13572 let children = ""; 13573 for (let ch of this.children) { 13574 let str = ch.toString(); 13575 if (str) { 13576 if (children) 13577 children += ","; 13578 children += str; 13579 } 13580 } 13581 return !this.type.name ? children : 13582 (/\W/.test(this.type.name) && !this.type.isError ? JSON.stringify(this.type.name) : this.type.name) + 13583 (children.length ? "(" + children + ")" : ""); 13584 } 13585 /// Get a [tree cursor](#common.TreeCursor) positioned at the top of 13586 /// the tree. Mode can be used to [control](#common.IterMode) which 13587 /// nodes the cursor visits. 13588 cursor(mode = 0) { 13589 return new TreeCursor(this.topNode, mode); 13590 } 13591 /// Get a [tree cursor](#common.TreeCursor) pointing into this tree 13592 /// at the given position and side (see 13593 /// [`moveTo`](#common.TreeCursor.moveTo). 13594 cursorAt(pos, side = 0, mode = 0) { 13595 let scope = CachedNode.get(this) || this.topNode; 13596 let cursor = new TreeCursor(scope); 13597 cursor.moveTo(pos, side); 13598 CachedNode.set(this, cursor._tree); 13599 return cursor; 13600 } 13601 /// Get a [syntax node](#common.SyntaxNode) object for the top of the 13602 /// tree. 13603 get topNode() { 13604 return new TreeNode(this, 0, 0, null); 13605 } 13606 /// Get the [syntax node](#common.SyntaxNode) at the given position. 13607 /// If `side` is -1, this will move into nodes that end at the 13608 /// position. If 1, it'll move into nodes that start at the 13609 /// position. With 0, it'll only enter nodes that cover the position
13610 /// from both sides. 13611 /// 13612 /// Note that this will not enter 13613 /// [overlays](#common.MountedTree.overlay), and you often want 13614 /// [`resolveInner`](#common.Tree.resolveInner) instead. 13615 resolve(pos, side = 0) { 13616 let node = resolveNode(CachedNode.get(this) || this.topNode, pos, side, false); 13617 CachedNode.set(this, node); 13618 return node; 13619 } 13620 /// Like [`resolve`](#common.Tree.resolve), but will enter 13621 /// [overlaid](#common.MountedTree.overlay) nodes, producing a syntax node 13622 /// pointing into the innermost overlaid tree at the given position 13623 /// (with parent links going through all parent structure, including 13624 /// the host trees). 13625 resolveInner(pos, side = 0) { 13626 let node = resolveNode(CachedInnerNode.get(this) || this.topNode, pos, side, true); 13627 CachedInnerNode.set(this, node); 13628 return node; 13629 } 13630 /// Iterate over the tree and its children, calling `enter` for any 13631 /// node that touches the `from`/`to` region (if given) before 13632 /// running over such a node's children, and `leave` (if given) when 13633 /// leaving the node. When `enter` returns `false`, that node will 13634 /// not have its children iterated over (or `leave` called). 13635 iterate(spec) { 13636 let { enter, leave, from = 0, to = this.length } = spec; 13637 for (let c = this.cursor((spec.mode || 0) | IterMode.IncludeAnonymous);;) { 13638 let entered = false; 13639 if (c.from <= to && c.to >= from && (c.type.isAnonymous || enter(c) !== false)) { 13640 if (c.firstChild()) 13641 continue; 13642 entered = true; 13643 } 13644 for (;;) { 13645 if (entered && leave && !c.type.isAnonymous) 13646 leave(c); 13647 if (c.nextSibling()) 13648 break; 13649 if (!c.parent()) 13650 return; 13651 entered = true; 13652 } 13653 } 13654 } 13655 /// Get the value of the given [node prop](#common.NodeProp) for this 13656 /// node. Works with both per-node and per-type props. 13657 prop(prop) { 13658 return !prop.perNode ? this.type.prop(prop) : this.props ? this.props[prop.id] : undefined; 13659 } 13660 /// Returns the node's [per-node props](#common.NodeProp.perNode) in a 13661 /// format that can be passed to the [`Tree`](#common.Tree) 13662 /// constructor. 13663 get propValues() { 13664 let result = []; 13665 if (this.props) 13666 for (let id in this.props) 13667 result.push([+id, this.props[id]]); 13668 return result; 13669 } 13670 /// Balance the direct children of this tree, producing a copy of 13671 /// which may have children grouped into subtrees with type 13672 /// [`NodeType.none`](#common.NodeType^none). 13673 balance(config = {}) { 13674 return this.children.length <= 8 /* Balance.BranchFactor */ ? this : 13675 balanceRange(NodeType.none, this.children, this.positions, 0, this.children.length, 0, this.length, (children, positions, length) => new Tree(this.type, children, positions, length, this.propValues), config.makeTree || ((children, positions, length) => new Tree(NodeType.none, children, positions, length))); 13676 } 13677 /// Build a tree from a postfix-ordered buffer of node information, 13678 /// or a cursor over such a buffer. 13679 static build(data) { return buildTree(data); } 13680} 13681/// The empty tree 13682Tree.empty = new Tree(NodeType.none, [], [], 0); 13683class FlatBufferCursor { 13684 constructor(buffer, index) { 13685 this.buffer = buffer; 13686 this.index = index; 13687 } 13688 get id() { return this.buffer[this.index - 4]; } 13689 get start() { return this.buffer[this.index - 3]; } 13690 get end() { return this.buffer[this.index - 2]; } 13691 get size() { return this.buffer[this.index - 1]; } 13692 get pos() { return this.index; } 13693 next() { this.index -= 4; } 13694 fork() { return new FlatBufferCursor(this.buffer, this.index); } 13695} 13696/// Tree buffers contain (type, start, end, endIndex) quads for each 13697/// node. In such a buffer, nodes are stored in prefix order (parents 13698/// before children, with the endIndex of the parent indicating which 13699/// children belong to it). 13700class TreeBuffer { 13701 /// Create a tree buffer. 13702 constructor( 13703 /// The buffer's content. 13704 buffer, 13705 /// The total length of the group of nodes in the buffer. 13706 length, 13707 /// The node set used in this buffer. 13708 set) { 13709 this.buffer = buffer; 13710 this.length = length; 13711 this.set = set; 13712 } 13713 /// @internal
vendor: 8,256 bytes, lines 13714-13916
13714 get type() { return NodeType.none; } 13715 /// @internal 13716 toString() { 13717 let result = []; 13718 for (let index = 0; index < this.buffer.length;) { 13719 result.push(this.childString(index)); 13720 index = this.buffer[index + 3]; 13721 } 13722 return result.join(","); 13723 } 13724 /// @internal 13725 childString(index) { 13726 let id = this.buffer[index], endIndex = this.buffer[index + 3]; 13727 let type = this.set.types[id], result = type.name; 13728 if (/\W/.test(result) && !type.isError) 13729 result = JSON.stringify(result); 13730 index += 4; 13731 if (endIndex == index) 13732 return result; 13733 let children = []; 13734 while (index < endIndex) { 13735 children.push(this.childString(index)); 13736 index = this.buffer[index + 3]; 13737 } 13738 return result + "(" + children.join(",") + ")"; 13739 } 13740 /// @internal 13741 findChild(startIndex, endIndex, dir, pos, side) { 13742 let { buffer } = this, pick = -1; 13743 for (let i = startIndex; i != endIndex; i = buffer[i + 3]) { 13744 if (checkSide(side, pos, buffer[i + 1], buffer[i + 2])) { 13745 pick = i; 13746 if (dir > 0) 13747 break; 13748 } 13749 } 13750 return pick; 13751 } 13752 /// @internal 13753 slice(startI, endI, from) { 13754 let b = this.buffer; 13755 let copy = new Uint16Array(endI - startI), len = 0; 13756 for (let i = startI, j = 0; i < endI;) { 13757 copy[j++] = b[i++]; 13758 copy[j++] = b[i++] - from; 13759 let to = copy[j++] = b[i++] - from; 13760 copy[j++] = b[i++] - startI; 13761 len = Math.max(len, to); 13762 } 13763 return new TreeBuffer(copy, len, this.set); 13764 } 13765} 13766function checkSide(side, pos, from, to) { 13767 switch (side) { 13768 case -2 /* Side.Before */: return from < pos; 13769 case -1 /* Side.AtOrBefore */: return to >= pos && from < pos; 13770 case 0 /* Side.Around */: return from < pos && to > pos; 13771 case 1 /* Side.AtOrAfter */: return from <= pos && to > pos; 13772 case 2 /* Side.After */: return to > pos; 13773 case 4 /* Side.DontCare */: return true; 13774 } 13775} 13776function enterUnfinishedNodesBefore(node, pos) { 13777 let scan = node.childBefore(pos); 13778 while (scan) { 13779 let last = scan.lastChild; 13780 if (!last || last.to != scan.to) 13781 break; 13782 if (last.type.isError && last.from == last.to) { 13783 node = scan; 13784 scan = last.prevSibling; 13785 } 13786 else { 13787 scan = last; 13788 } 13789 } 13790 return node; 13791} 13792function resolveNode(node, pos, side, overlays) { 13793 var _a; 13794 // Move up to a node that actually holds the position, if possible 13795 while (node.from == node.to || 13796 (side < 1 ? node.from >= pos : node.from > pos) || 13797 (side > -1 ? node.to <= pos : node.to < pos)) { 13798 let parent = !overlays && node instanceof TreeNode && node.index < 0 ? null : node.parent; 13799 if (!parent) 13800 return node; 13801 node = parent; 13802 } 13803 let mode = overlays ? 0 : IterMode.IgnoreOverlays; 13804 // Must go up out of overlays when those do not overlap with pos 13805 if (overlays) 13806 for (let scan = node, parent = scan.parent; parent; scan = parent, parent = scan.parent) { 13807 if (scan instanceof TreeNode && scan.index < 0 && ((_a = parent.enter(pos, side, mode)) === null || _a === void 0 ? void 0 : _a.from) != scan.from) 13808 node = parent; 13809 } 13810 for (;;) { 13811 let inner = node.enter(pos, side, mode); 13812 if (!inner) 13813 return node; 13814 node = inner; 13815 } 13816} 13817class TreeNode { 13818 constructor(_tree, from, 13819 // Index in parent node, set to -1 if the node is not a direct child of _parent.node (overlay) 13820 index, _parent) { 13821 this._tree = _tree; 13822 this.from = from; 13823 this.index = index; 13824 this._parent = _parent; 13825 } 13826 get type() { return this._tree.type; } 13827 get name() { return this._tree.type.name; } 13828 get to() { return this.from + this._tree.length; } 13829 nextChild(i, dir, pos, side, mode = 0) { 13830 for (let parent = this;;) { 13831 for (let { children, positions } = parent._tree, e = dir > 0 ? children.length : -1; i != e; i += dir) { 13832 let next = children[i], start = positions[i] + parent.from; 13833 if (!checkSide(side, pos, start, start + next.length)) 13834 continue; 13835 if (next instanceof TreeBuffer) { 13836 if (mode & IterMode.ExcludeBuffers) 13837 continue; 13838 let index = next.findChild(0, next.buffer.length, dir, pos - start, side); 13839 if (index > -1) 13840 return new BufferNode(new BufferContext(parent, next, i, start), null, index); 13841 } 13842 else if ((mode & IterMode.IncludeAnonymous) || (!next.type.isAnonymous || hasChild(next))) { 13843 let mounted; 13844 if (!(mode & IterMode.IgnoreMounts) && 13845 next.props && (mounted = next.prop(NodeProp.mounted)) && !mounted.overlay) 13846 return new TreeNode(mounted.tree, start, i, parent); 13847 let inner = new TreeNode(next, start, i, parent); 13848 return (mode & IterMode.IncludeAnonymous) || !inner.type.isAnonymous ? inner 13849 : inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side); 13850 } 13851 } 13852 if ((mode & IterMode.IncludeAnonymous) || !parent.type.isAnonymous) 13853 return null; 13854 if (parent.index >= 0) 13855 i = parent.index + dir; 13856 else 13857 i = dir < 0 ? -1 : parent._parent._tree.children.length; 13858 parent = parent._parent; 13859 if (!parent) 13860 return null; 13861 } 13862 } 13863 get firstChild() { return this.nextChild(0, 1, 0, 4 /* Side.DontCare */); } 13864 get lastChild() { return this.nextChild(this._tree.children.length - 1, -1, 0, 4 /* Side.DontCare */); } 13865 childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* Side.After */); } 13866 childBefore(pos) { return this.nextChild(this._tree.children.length - 1, -1, pos, -2 /* Side.Before */); } 13867 enter(pos, side, mode = 0) { 13868 let mounted; 13869 if (!(mode & IterMode.IgnoreOverlays) && (mounted = this._tree.prop(NodeProp.mounted)) && mounted.overlay) { 13870 let rPos = pos - this.from; 13871 for (let { from, to } of mounted.overlay) { 13872 if ((side > 0 ? from <= rPos : from < rPos) && 13873 (side < 0 ? to >= rPos : to > rPos)) 13874 return new TreeNode(mounted.tree, mounted.overlay[0].from + this.from, -1, this); 13875 } 13876 } 13877 return this.nextChild(0, 1, pos, side, mode); 13878 } 13879 nextSignificantParent() { 13880 let val = this; 13881 while (val.type.isAnonymous && val._parent) 13882 val = val._parent; 13883 return val; 13884 } 13885 get parent() { 13886 return this._parent ? this._parent.nextSignificantParent() : null; 13887 } 13888 get nextSibling() { 13889 return this._parent && this.index >= 0 ? this._parent.nextChild(this.index + 1, 1, 0, 4 /* Side.DontCare */) : null; 13890 } 13891 get prevSibling() { 13892 return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* Side.DontCare */) : null; 13893 } 13894 cursor(mode = 0) { return new TreeCursor(this, mode); } 13895 get tree() { return this._tree; } 13896 toTree() { return this._tree; } 13897 resolve(pos, side = 0) { 13898 return resolveNode(this, pos, side, false); 13899 } 13900 resolveInner(pos, side = 0) { 13901 return resolveNode(this, pos, side, true); 13902 } 13903 enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); } 13904 getChild(type, before = null, after = null) { 13905 let r = getChildren(this, type, before, after); 13906 return r.length ? r[0] : null; 13907 } 13908 getChildren(type, before = null, after = null) { 13909 return getChildren(this, type, before, after); 13910 } 13911 /// @internal 13912 toString() { return this._tree.toString(); } 13913 get node() { return this; } 13914 matchContext(context) { return matchNodeContext(this, context); } 13915} 13916function getChildren(node, type, before, after) {
vendor: 5,479 bytes, lines 13917-14061
13917 let cur = node.cursor(), result = []; 13918 if (!cur.firstChild()) 13919 return result; 13920 if (before != null) 13921 while (!cur.type.is(before)) 13922 if (!cur.nextSibling()) 13923 return result; 13924 for (;;) { 13925 if (after != null && cur.type.is(after)) 13926 return result; 13927 if (cur.type.is(type)) 13928 result.push(cur.node); 13929 if (!cur.nextSibling()) 13930 return after == null ? result : []; 13931 } 13932} 13933function matchNodeContext(node, context, i = context.length - 1) { 13934 for (let p = node.parent; i >= 0; p = p.parent) { 13935 if (!p) 13936 return false; 13937 if (!p.type.isAnonymous) { 13938 if (context[i] && context[i] != p.name) 13939 return false; 13940 i--; 13941 } 13942 } 13943 return true; 13944} 13945class BufferContext { 13946 constructor(parent, buffer, index, start) { 13947 this.parent = parent; 13948 this.buffer = buffer; 13949 this.index = index; 13950 this.start = start; 13951 } 13952} 13953class BufferNode { 13954 get name() { return this.type.name; } 13955 get from() { return this.context.start + this.context.buffer.buffer[this.index + 1]; } 13956 get to() { return this.context.start + this.context.buffer.buffer[this.index + 2]; } 13957 constructor(context, _parent, index) { 13958 this.context = context; 13959 this._parent = _parent; 13960 this.index = index; 13961 this.type = context.buffer.set.types[context.buffer.buffer[index]]; 13962 } 13963 child(dir, pos, side) { 13964 let { buffer } = this.context; 13965 let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.context.start, side); 13966 return index < 0 ? null : new BufferNode(this.context, this, index); 13967 } 13968 get firstChild() { return this.child(1, 0, 4 /* Side.DontCare */); } 13969 get lastChild() { return this.child(-1, 0, 4 /* Side.DontCare */); } 13970 childAfter(pos) { return this.child(1, pos, 2 /* Side.After */); } 13971 childBefore(pos) { return this.child(-1, pos, -2 /* Side.Before */); } 13972 enter(pos, side, mode = 0) { 13973 if (mode & IterMode.ExcludeBuffers) 13974 return null; 13975 let { buffer } = this.context; 13976 let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], side > 0 ? 1 : -1, pos - this.context.start, side); 13977 return index < 0 ? null : new BufferNode(this.context, this, index); 13978 } 13979 get parent() { 13980 return this._parent || this.context.parent.nextSignificantParent(); 13981 } 13982 externalSibling(dir) { 13983 return this._parent ? null : this.context.parent.nextChild(this.context.index + dir, dir, 0, 4 /* Side.DontCare */); 13984 } 13985 get nextSibling() { 13986 let { buffer } = this.context; 13987 let after = buffer.buffer[this.index + 3]; 13988 if (after < (this._parent ? buffer.buffer[this._parent.index + 3] : buffer.buffer.length)) 13989 return new BufferNode(this.context, this._parent, after); 13990 return this.externalSibling(1); 13991 } 13992 get prevSibling() { 13993 let { buffer } = this.context; 13994 let parentStart = this._parent ? this._parent.index + 4 : 0; 13995 if (this.index == parentStart) 13996 return this.externalSibling(-1); 13997 return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* Side.DontCare */)); 13998 } 13999 cursor(mode = 0) { return new TreeCursor(this, mode); } 14000 get tree() { return null; } 14001 toTree() { 14002 let children = [], positions = []; 14003 let { buffer } = this.context; 14004 let startI = this.index + 4, endI = buffer.buffer[this.index + 3]; 14005 if (endI > startI) { 14006 let from = buffer.buffer[this.index + 1]; 14007 children.push(buffer.slice(startI, endI, from)); 14008 positions.push(0); 14009 } 14010 return new Tree(this.type, children, positions, this.to - this.from); 14011 } 14012 resolve(pos, side = 0) { 14013 return resolveNode(this, pos, side, false); 14014 } 14015 resolveInner(pos, side = 0) { 14016 return resolveNode(this, pos, side, true); 14017 } 14018 enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); } 14019 /// @internal 14020 toString() { return this.context.buffer.childString(this.index); } 14021 getChild(type, before = null, after = null) { 14022 let r = getChildren(this, type, before, after); 14023 return r.length ? r[0] : null; 14024 } 14025 getChildren(type, before = null, after = null) { 14026 return getChildren(this, type, before, after); 14027 } 14028 get node() { return this; } 14029 matchContext(context) { return matchNodeContext(this, context); } 14030} 14031/// A tree cursor object focuses on a given node in a syntax tree, and 14032/// allows you to move to adjacent nodes. 14033class TreeCursor { 14034 /// Shorthand for `.type.name`. 14035 get name() { return this.type.name; } 14036 /// @internal 14037 constructor(node, 14038 /// @internal 14039 mode = 0) { 14040 this.mode = mode; 14041 /// @internal 14042 this.buffer = null; 14043 this.stack = []; 14044 /// @internal 14045 this.index = 0; 14046 this.bufferNode = null; 14047 if (node instanceof TreeNode) { 14048 this.yieldNode(node); 14049 } 14050 else { 14051 this._tree = node.context.parent; 14052 this.buffer = node.context; 14053 for (let n = node._parent; n; n = n._parent) 14054 this.stack.unshift(n.index); 14055 this.bufferNode = node; 14056 this.yieldBuf(node.index); 14057 } 14058 } 14059 yieldNode(node) { 14060 if (!node) 14061 return false;
vendor: 8,108 bytes, lines 14062-14246
14062 this._tree = node; 14063 this.type = node.type; 14064 this.from = node.from; 14065 this.to = node.to; 14066 return true; 14067 } 14068 yieldBuf(index, type) { 14069 this.index = index; 14070 let { start, buffer } = this.buffer; 14071 this.type = type || buffer.set.types[buffer.buffer[index]]; 14072 this.from = start + buffer.buffer[index + 1]; 14073 this.to = start + buffer.buffer[index + 2]; 14074 return true; 14075 } 14076 yield(node) { 14077 if (!node) 14078 return false; 14079 if (node instanceof TreeNode) { 14080 this.buffer = null; 14081 return this.yieldNode(node); 14082 } 14083 this.buffer = node.context; 14084 return this.yieldBuf(node.index, node.type); 14085 } 14086 /// @internal 14087 toString() { 14088 return this.buffer ? this.buffer.buffer.childString(this.index) : this._tree.toString(); 14089 } 14090 /// @internal 14091 enterChild(dir, pos, side) { 14092 if (!this.buffer) 14093 return this.yield(this._tree.nextChild(dir < 0 ? this._tree._tree.children.length - 1 : 0, dir, pos, side, this.mode)); 14094 let { buffer } = this.buffer; 14095 let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.buffer.start, side); 14096 if (index < 0) 14097 return false; 14098 this.stack.push(this.index); 14099 return this.yieldBuf(index); 14100 } 14101 /// Move the cursor to this node's first child. When this returns 14102 /// false, the node has no child, and the cursor has not been moved. 14103 firstChild() { return this.enterChild(1, 0, 4 /* Side.DontCare */); } 14104 /// Move the cursor to this node's last child. 14105 lastChild() { return this.enterChild(-1, 0, 4 /* Side.DontCare */); } 14106 /// Move the cursor to the first child that ends after `pos`. 14107 childAfter(pos) { return this.enterChild(1, pos, 2 /* Side.After */); } 14108 /// Move to the last child that starts before `pos`. 14109 childBefore(pos) { return this.enterChild(-1, pos, -2 /* Side.Before */); } 14110 /// Move the cursor to the child around `pos`. If side is -1 the 14111 /// child may end at that position, when 1 it may start there. This 14112 /// will also enter [overlaid](#common.MountedTree.overlay) 14113 /// [mounted](#common.NodeProp^mounted) trees unless `overlays` is 14114 /// set to false. 14115 enter(pos, side, mode = this.mode) { 14116 if (!this.buffer) 14117 return this.yield(this._tree.enter(pos, side, mode)); 14118 return mode & IterMode.ExcludeBuffers ? false : this.enterChild(1, pos, side); 14119 } 14120 /// Move to the node's parent node, if this isn't the top node. 14121 parent() { 14122 if (!this.buffer) 14123 return this.yieldNode((this.mode & IterMode.IncludeAnonymous) ? this._tree._parent : this._tree.parent); 14124 if (this.stack.length) 14125 return this.yieldBuf(this.stack.pop()); 14126 let parent = (this.mode & IterMode.IncludeAnonymous) ? this.buffer.parent : this.buffer.parent.nextSignificantParent(); 14127 this.buffer = null; 14128 return this.yieldNode(parent); 14129 } 14130 /// @internal 14131 sibling(dir) { 14132 if (!this.buffer) 14133 return !this._tree._parent ? false 14134 : this.yield(this._tree.index < 0 ? null 14135 : this._tree._parent.nextChild(this._tree.index + dir, dir, 0, 4 /* Side.DontCare */, this.mode)); 14136 let { buffer } = this.buffer, d = this.stack.length - 1; 14137 if (dir < 0) { 14138 let parentStart = d < 0 ? 0 : this.stack[d] + 4; 14139 if (this.index != parentStart) 14140 return this.yieldBuf(buffer.findChild(parentStart, this.index, -1, 0, 4 /* Side.DontCare */)); 14141 } 14142 else { 14143 let after = buffer.buffer[this.index + 3]; 14144 if (after < (d < 0 ? buffer.buffer.length : buffer.buffer[this.stack[d] + 3])) 14145 return this.yieldBuf(after); 14146 } 14147 return d < 0 ? this.yield(this.buffer.parent.nextChild(this.buffer.index + dir, dir, 0, 4 /* Side.DontCare */, this.mode)) : false; 14148 } 14149 /// Move to this node's next sibling, if any. 14150 nextSibling() { return this.sibling(1); } 14151 /// Move to this node's previous sibling, if any. 14152 prevSibling() { return this.sibling(-1); } 14153 atLastNode(dir) { 14154 let index, parent, { buffer } = this; 14155 if (buffer) { 14156 if (dir > 0) { 14157 if (this.index < buffer.buffer.buffer.length) 14158 return false; 14159 } 14160 else { 14161 for (let i = 0; i < this.index; i++) 14162 if (buffer.buffer.buffer[i + 3] < this.index) 14163 return false; 14164 } 14165 ({ index, parent } = buffer); 14166 } 14167 else { 14168 ({ index, _parent: parent } = this._tree); 14169 } 14170 for (; parent; { index, _parent: parent } = parent) { 14171 if (index > -1) 14172 for (let i = index + dir, e = dir < 0 ? -1 : parent._tree.children.length; i != e; i += dir) { 14173 let child = parent._tree.children[i]; 14174 if ((this.mode & IterMode.IncludeAnonymous) || 14175 child instanceof TreeBuffer || 14176 !child.type.isAnonymous || 14177 hasChild(child)) 14178 return false; 14179 } 14180 } 14181 return true; 14182 } 14183 move(dir, enter) { 14184 if (enter && this.enterChild(dir, 0, 4 /* Side.DontCare */)) 14185 return true; 14186 for (;;) { 14187 if (this.sibling(dir)) 14188 return true; 14189 if (this.atLastNode(dir) || !this.parent()) 14190 return false; 14191 } 14192 } 14193 /// Move to the next node in a 14194 /// [pre-order](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order,_NLR) 14195 /// traversal, going from a node to its first child or, if the 14196 /// current node is empty or `enter` is false, its next sibling or 14197 /// the next sibling of the first parent node that has one. 14198 next(enter = true) { return this.move(1, enter); } 14199 /// Move to the next node in a last-to-first pre-order traveral. A 14200 /// node is followed by its last child or, if it has none, its 14201 /// previous sibling or the previous sibling of the first parent 14202 /// node that has one. 14203 prev(enter = true) { return this.move(-1, enter); } 14204 /// Move the cursor to the innermost node that covers `pos`. If 14205 /// `side` is -1, it will enter nodes that end at `pos`. If it is 1, 14206 /// it will enter nodes that start at `pos`. 14207 moveTo(pos, side = 0) { 14208 // Move up to a node that actually holds the position, if possible 14209 while (this.from == this.to || 14210 (side < 1 ? this.from >= pos : this.from > pos) || 14211 (side > -1 ? this.to <= pos : this.to < pos)) 14212 if (!this.parent()) 14213 break; 14214 // Then scan down into child nodes as far as possible 14215 while (this.enterChild(1, pos, side)) { } 14216 return this; 14217 } 14218 /// Get a [syntax node](#common.SyntaxNode) at the cursor's current 14219 /// position. 14220 get node() { 14221 if (!this.buffer) 14222 return this._tree; 14223 let cache = this.bufferNode, result = null, depth = 0; 14224 if (cache && cache.context == this.buffer) { 14225 scan: for (let index = this.index, d = this.stack.length; d >= 0;) { 14226 for (let c = cache; c; c = c._parent) 14227 if (c.index == index) { 14228 if (index == this.index) 14229 return c; 14230 result = c; 14231 depth = d + 1; 14232 break scan; 14233 } 14234 index = this.stack[--d]; 14235 } 14236 } 14237 for (let i = depth; i < this.stack.length; i++) 14238 result = new BufferNode(this.buffer, result, this.stack[i]); 14239 return this.bufferNode = new BufferNode(this.buffer, result, this.index); 14240 } 14241 /// Get the [tree](#common.Tree) that represents the current node, if 14242 /// any. Will return null when the node is in a [tree 14243 /// buffer](#common.TreeBuffer). 14244 get tree() { 14245 return this.buffer ? null : this._tree._tree; 14246 }
vendor: 6,631 bytes, lines 14247-14395
14247 /// Iterate over the current node and all its descendants, calling 14248 /// `enter` when entering a node and `leave`, if given, when leaving 14249 /// one. When `enter` returns `false`, any children of that node are 14250 /// skipped, and `leave` isn't called for it. 14251 iterate(enter, leave) { 14252 for (let depth = 0;;) { 14253 let mustLeave = false; 14254 if (this.type.isAnonymous || enter(this) !== false) { 14255 if (this.firstChild()) { 14256 depth++; 14257 continue; 14258 } 14259 if (!this.type.isAnonymous) 14260 mustLeave = true; 14261 } 14262 for (;;) { 14263 if (mustLeave && leave) 14264 leave(this); 14265 mustLeave = this.type.isAnonymous; 14266 if (this.nextSibling()) 14267 break; 14268 if (!depth) 14269 return; 14270 this.parent(); 14271 depth--; 14272 mustLeave = true; 14273 } 14274 } 14275 } 14276 /// Test whether the current node matches a given contextâa sequence 14277 /// of direct parent node names. Empty strings in the context array 14278 /// are treated as wildcards. 14279 matchContext(context) { 14280 if (!this.buffer) 14281 return matchNodeContext(this.node, context); 14282 let { buffer } = this.buffer, { types } = buffer.set; 14283 for (let i = context.length - 1, d = this.stack.length - 1; i >= 0; d--) { 14284 if (d < 0) 14285 return matchNodeContext(this.node, context, i); 14286 let type = types[buffer.buffer[this.stack[d]]]; 14287 if (!type.isAnonymous) { 14288 if (context[i] && context[i] != type.name) 14289 return false; 14290 i--; 14291 } 14292 } 14293 return true; 14294 } 14295} 14296function hasChild(tree) { 14297 return tree.children.some(ch => ch instanceof TreeBuffer || !ch.type.isAnonymous || hasChild(ch)); 14298} 14299function buildTree(data) { 14300 var _a; 14301 let { buffer, nodeSet, maxBufferLength = DefaultBufferLength, reused = [], minRepeatType = nodeSet.types.length } = data; 14302 let cursor = Array.isArray(buffer) ? new FlatBufferCursor(buffer, buffer.length) : buffer; 14303 let types = nodeSet.types; 14304 let contextHash = 0, lookAhead = 0; 14305 function takeNode(parentStart, minPos, children, positions, inRepeat) { 14306 let { id, start, end, size } = cursor; 14307 let lookAheadAtStart = lookAhead; 14308 while (size < 0) { 14309 cursor.next(); 14310 if (size == -1 /* SpecialRecord.Reuse */) { 14311 let node = reused[id]; 14312 children.push(node); 14313 positions.push(start - parentStart); 14314 return; 14315 } 14316 else if (size == -3 /* SpecialRecord.ContextChange */) { // Context change 14317 contextHash = id; 14318 return; 14319 } 14320 else if (size == -4 /* SpecialRecord.LookAhead */) { 14321 lookAhead = id; 14322 return; 14323 } 14324 else { 14325 throw new RangeError(`Unrecognized record size: ${size}`); 14326 } 14327 } 14328 let type = types[id], node, buffer; 14329 let startPos = start - parentStart; 14330 if (end - start <= maxBufferLength && (buffer = findBufferSize(cursor.pos - minPos, inRepeat))) { 14331 // Small enough for a buffer, and no reused nodes inside 14332 let data = new Uint16Array(buffer.size - buffer.skip); 14333 let endPos = cursor.pos - buffer.size, index = data.length; 14334 while (cursor.pos > endPos) 14335 index = copyToBuffer(buffer.start, data, index); 14336 node = new TreeBuffer(data, end - buffer.start, nodeSet); 14337 startPos = buffer.start - parentStart; 14338 } 14339 else { // Make it a node 14340 let endPos = cursor.pos - size; 14341 cursor.next(); 14342 let localChildren = [], localPositions = []; 14343 let localInRepeat = id >= minRepeatType ? id : -1; 14344 let lastGroup = 0, lastEnd = end; 14345 while (cursor.pos > endPos) { 14346 if (localInRepeat >= 0 && cursor.id == localInRepeat && cursor.size >= 0) { 14347 if (cursor.end <= lastEnd - maxBufferLength) { 14348 makeRepeatLeaf(localChildren, localPositions, start, lastGroup, cursor.end, lastEnd, localInRepeat, lookAheadAtStart); 14349 lastGroup = localChildren.length; 14350 lastEnd = cursor.end; 14351 } 14352 cursor.next(); 14353 } 14354 else { 14355 takeNode(start, endPos, localChildren, localPositions, localInRepeat); 14356 } 14357 } 14358 if (localInRepeat >= 0 && lastGroup > 0 && lastGroup < localChildren.length) 14359 makeRepeatLeaf(localChildren, localPositions, start, lastGroup, start, lastEnd, localInRepeat, lookAheadAtStart); 14360 localChildren.reverse(); 14361 localPositions.reverse(); 14362 if (localInRepeat > -1 && lastGroup > 0) { 14363 let make = makeBalanced(type); 14364 node = balanceRange(type, localChildren, localPositions, 0, localChildren.length, 0, end - start, make, make); 14365 } 14366 else { 14367 node = makeTree(type, localChildren, localPositions, end - start, lookAheadAtStart - end); 14368 } 14369 } 14370 children.push(node); 14371 positions.push(startPos); 14372 } 14373 function makeBalanced(type) { 14374 return (children, positions, length) => { 14375 let lookAhead = 0, lastI = children.length - 1, last, lookAheadProp; 14376 if (lastI >= 0 && (last = children[lastI]) instanceof Tree) { 14377 if (!lastI && last.type == type && last.length == length) 14378 return last; 14379 if (lookAheadProp = last.prop(NodeProp.lookAhead)) 14380 lookAhead = positions[lastI] + last.length + lookAheadProp; 14381 } 14382 return makeTree(type, children, positions, length, lookAhead); 14383 }; 14384 } 14385 function makeRepeatLeaf(children, positions, base, i, from, to, type, lookAhead) { 14386 let localChildren = [], localPositions = []; 14387 while (children.length > i) { 14388 localChildren.push(children.pop()); 14389 localPositions.push(positions.pop() + base - from); 14390 } 14391 children.push(makeTree(nodeSet.types[type], localChildren, localPositions, to - from, lookAhead - to)); 14392 positions.push(from - base); 14393 } 14394 function makeTree(type, children, positions, length, lookAhead = 0, props) { 14395 if (contextHash) {
vendor: 8,079 bytes, lines 14396-14598
14396 let pair = [NodeProp.contextHash, contextHash]; 14397 props = props ? [pair].concat(props) : [pair]; 14398 } 14399 if (lookAhead > 25) { 14400 let pair = [NodeProp.lookAhead, lookAhead]; 14401 props = props ? [pair].concat(props) : [pair]; 14402 } 14403 return new Tree(type, children, positions, length, props); 14404 } 14405 function findBufferSize(maxSize, inRepeat) { 14406 // Scan through the buffer to find previous siblings that fit 14407 // together in a TreeBuffer, and don't contain any reused nodes 14408 // (which can't be stored in a buffer). 14409 // If `inRepeat` is > -1, ignore node boundaries of that type for 14410 // nesting, but make sure the end falls either at the start 14411 // (`maxSize`) or before such a node. 14412 let fork = cursor.fork(); 14413 let size = 0, start = 0, skip = 0, minStart = fork.end - maxBufferLength; 14414 let result = { size: 0, start: 0, skip: 0 }; 14415 scan: for (let minPos = fork.pos - maxSize; fork.pos > minPos;) { 14416 let nodeSize = fork.size; 14417 // Pretend nested repeat nodes of the same type don't exist 14418 if (fork.id == inRepeat && nodeSize >= 0) { 14419 // Except that we store the current state as a valid return 14420 // value. 14421 result.size = size; 14422 result.start = start; 14423 result.skip = skip; 14424 skip += 4; 14425 size += 4; 14426 fork.next(); 14427 continue; 14428 } 14429 let startPos = fork.pos - nodeSize; 14430 if (nodeSize < 0 || startPos < minPos || fork.start < minStart) 14431 break; 14432 let localSkipped = fork.id >= minRepeatType ? 4 : 0; 14433 let nodeStart = fork.start; 14434 fork.next(); 14435 while (fork.pos > startPos) { 14436 if (fork.size < 0) { 14437 if (fork.size == -3 /* SpecialRecord.ContextChange */) 14438 localSkipped += 4; 14439 else 14440 break scan; 14441 } 14442 else if (fork.id >= minRepeatType) { 14443 localSkipped += 4; 14444 } 14445 fork.next(); 14446 } 14447 start = nodeStart; 14448 size += nodeSize; 14449 skip += localSkipped; 14450 } 14451 if (inRepeat < 0 || size == maxSize) { 14452 result.size = size; 14453 result.start = start; 14454 result.skip = skip; 14455 } 14456 return result.size > 4 ? result : undefined; 14457 } 14458 function copyToBuffer(bufferStart, buffer, index) { 14459 let { id, start, end, size } = cursor; 14460 cursor.next(); 14461 if (size >= 0 && id < minRepeatType) { 14462 let startIndex = index; 14463 if (size > 4) { 14464 let endPos = cursor.pos - (size - 4); 14465 while (cursor.pos > endPos) 14466 index = copyToBuffer(bufferStart, buffer, index); 14467 } 14468 buffer[--index] = startIndex; 14469 buffer[--index] = end - bufferStart; 14470 buffer[--index] = start - bufferStart; 14471 buffer[--index] = id; 14472 } 14473 else if (size == -3 /* SpecialRecord.ContextChange */) { 14474 contextHash = id; 14475 } 14476 else if (size == -4 /* SpecialRecord.LookAhead */) { 14477 lookAhead = id; 14478 } 14479 return index; 14480 } 14481 let children = [], positions = []; 14482 while (cursor.pos > 0) 14483 takeNode(data.start || 0, data.bufferStart || 0, children, positions, -1); 14484 let length = (_a = data.length) !== null && _a !== void 0 ? _a : (children.length ? positions[0] + children[0].length : 0); 14485 return new Tree(types[data.topID], children.reverse(), positions.reverse(), length); 14486} 14487const nodeSizeCache = new WeakMap; 14488function nodeSize(balanceType, node) { 14489 if (!balanceType.isAnonymous || node instanceof TreeBuffer || node.type != balanceType) 14490 return 1; 14491 let size = nodeSizeCache.get(node); 14492 if (size == null) { 14493 size = 1; 14494 for (let child of node.children) { 14495 if (child.type != balanceType || !(child instanceof Tree)) { 14496 size = 1; 14497 break; 14498 } 14499 size += nodeSize(balanceType, child); 14500 } 14501 nodeSizeCache.set(node, size); 14502 } 14503 return size; 14504} 14505function balanceRange( 14506// The type the balanced tree's inner nodes. 14507balanceType, 14508// The direct children and their positions 14509children, positions, 14510// The index range in children/positions to use 14511from, to, 14512// The start position of the nodes, relative to their parent. 14513start, 14514// Length of the outer node 14515length, 14516// Function to build the top node of the balanced tree 14517mkTop, 14518// Function to build internal nodes for the balanced tree 14519mkTree) { 14520 let total = 0; 14521 for (let i = from; i < to; i++) 14522 total += nodeSize(balanceType, children[i]); 14523 let maxChild = Math.ceil((total * 1.5) / 8 /* Balance.BranchFactor */); 14524 let localChildren = [], localPositions = []; 14525 function divide(children, positions, from, to, offset) { 14526 for (let i = from; i < to;) { 14527 let groupFrom = i, groupStart = positions[i], groupSize = nodeSize(balanceType, children[i]); 14528 i++; 14529 for (; i < to; i++) { 14530 let nextSize = nodeSize(balanceType, children[i]); 14531 if (groupSize + nextSize >= maxChild) 14532 break; 14533 groupSize += nextSize; 14534 } 14535 if (i == groupFrom + 1) { 14536 if (groupSize > maxChild) { 14537 let only = children[groupFrom]; // Only trees can have a size > 1 14538 divide(only.children, only.positions, 0, only.children.length, positions[groupFrom] + offset); 14539 continue; 14540 } 14541 localChildren.push(children[groupFrom]); 14542 } 14543 else { 14544 let length = positions[i - 1] + children[i - 1].length - groupStart; 14545 localChildren.push(balanceRange(balanceType, children, positions, groupFrom, i, groupStart, length, null, mkTree)); 14546 } 14547 localPositions.push(groupStart + offset - start); 14548 } 14549 } 14550 divide(children, positions, from, to, 0); 14551 return (mkTop || mkTree)(localChildren, localPositions, length); 14552} 14553/// Provides a way to associate values with pieces of trees. As long 14554/// as that part of the tree is reused, the associated values can be 14555/// retrieved from an updated tree. 14556class NodeWeakMap { 14557 constructor() { 14558 this.map = new WeakMap(); 14559 } 14560 setBuffer(buffer, index, value) { 14561 let inner = this.map.get(buffer); 14562 if (!inner) 14563 this.map.set(buffer, inner = new Map); 14564 inner.set(index, value); 14565 } 14566 getBuffer(buffer, index) { 14567 let inner = this.map.get(buffer); 14568 return inner && inner.get(index); 14569 } 14570 /// Set the value for this syntax node. 14571 set(node, value) { 14572 if (node instanceof BufferNode) 14573 this.setBuffer(node.context.buffer, node.index, value); 14574 else if (node instanceof TreeNode) 14575 this.map.set(node.tree, value); 14576 } 14577 /// Retrieve value for this syntax node, if it exists in the map. 14578 get(node) { 14579 return node instanceof BufferNode ? this.getBuffer(node.context.buffer, node.index) 14580 : node instanceof TreeNode ? this.map.get(node.tree) : undefined; 14581 } 14582 /// Set the value for the node that a cursor currently points to. 14583 cursorSet(cursor, value) { 14584 if (cursor.buffer) 14585 this.setBuffer(cursor.buffer.buffer, cursor.index, value); 14586 else 14587 this.map.set(cursor.tree, value); 14588 } 14589 /// Retrieve the value for the node that a cursor currently points 14590 /// to. 14591 cursorGet(cursor) { 14592 return cursor.buffer ? this.getBuffer(cursor.buffer.buffer, cursor.index) : this.map.get(cursor.tree); 14593 } 14594} 14595 14596/// Tree fragments are used during [incremental 14597/// parsing](#common.Parser.startParse) to track parts of old trees 14598/// that can be reused in a new parse. An array of fragments is used
14599/// to track regions of an old tree whose nodes might be reused in new 14600/// parses. Use the static 14601/// [`applyChanges`](#common.TreeFragment^applyChanges) method to 14602/// update fragments for document changes. 14603class TreeFragment { 14604 /// Construct a tree fragment. You'll usually want to use 14605 /// [`addTree`](#common.TreeFragment^addTree) and 14606 /// [`applyChanges`](#common.TreeFragment^applyChanges) instead of 14607 /// calling this directly. 14608 constructor( 14609 /// The start of the unchanged range pointed to by this fragment. 14610 /// This refers to an offset in the _updated_ document (as opposed 14611 /// to the original tree). 14612 from, 14613 /// The end of the unchanged range. 14614 to, 14615 /// The tree that this fragment is based on. 14616 tree, 14617 /// The offset between the fragment's tree and the document that 14618 /// this fragment can be used against. Add this when going from 14619 /// document to tree positions, subtract it to go from tree to 14620 /// document positions. 14621 offset, openStart = false, openEnd = false) { 14622 this.from = from; 14623 this.to = to; 14624 this.tree = tree; 14625 this.offset = offset; 14626 this.open = (openStart ? 1 /* Open.Start */ : 0) | (openEnd ? 2 /* Open.End */ : 0); 14627 } 14628 /// Whether the start of the fragment represents the start of a 14629 /// parse, or the end of a change. (In the second case, it may not
vendor: 4,367 bytes, lines 14630-14728
14630 /// be safe to reuse some nodes at the start, depending on the 14631 /// parsing algorithm.) 14632 get openStart() { return (this.open & 1 /* Open.Start */) > 0; } 14633 /// Whether the end of the fragment represents the end of a 14634 /// full-document parse, or the start of a change. 14635 get openEnd() { return (this.open & 2 /* Open.End */) > 0; } 14636 /// Create a set of fragments from a freshly parsed tree, or update 14637 /// an existing set of fragments by replacing the ones that overlap 14638 /// with a tree with content from the new tree. When `partial` is 14639 /// true, the parse is treated as incomplete, and the resulting 14640 /// fragment has [`openEnd`](#common.TreeFragment.openEnd) set to 14641 /// true. 14642 static addTree(tree, fragments = [], partial = false) { 14643 let result = [new TreeFragment(0, tree.length, tree, 0, false, partial)]; 14644 for (let f of fragments) 14645 if (f.to > tree.length) 14646 result.push(f); 14647 return result; 14648 } 14649 /// Apply a set of edits to an array of fragments, removing or 14650 /// splitting fragments as necessary to remove edited ranges, and 14651 /// adjusting offsets for fragments that moved. 14652 static applyChanges(fragments, changes, minGap = 128) { 14653 if (!changes.length) 14654 return fragments; 14655 let result = []; 14656 let fI = 1, nextF = fragments.length ? fragments[0] : null; 14657 for (let cI = 0, pos = 0, off = 0;; cI++) { 14658 let nextC = cI < changes.length ? changes[cI] : null; 14659 let nextPos = nextC ? nextC.fromA : 1e9; 14660 if (nextPos - pos >= minGap) 14661 while (nextF && nextF.from < nextPos) { 14662 let cut = nextF; 14663 if (pos >= cut.from || nextPos <= cut.to || off) { 14664 let fFrom = Math.max(cut.from, pos) - off, fTo = Math.min(cut.to, nextPos) - off; 14665 cut = fFrom >= fTo ? null : new TreeFragment(fFrom, fTo, cut.tree, cut.offset + off, cI > 0, !!nextC); 14666 } 14667 if (cut) 14668 result.push(cut); 14669 if (nextF.to > nextPos) 14670 break; 14671 nextF = fI < fragments.length ? fragments[fI++] : null; 14672 } 14673 if (!nextC) 14674 break; 14675 pos = nextC.toA; 14676 off = nextC.toA - nextC.toB; 14677 } 14678 return result; 14679 } 14680} 14681/// A superclass that parsers should extend. 14682class Parser { 14683 /// Start a parse, returning a [partial parse](#common.PartialParse) 14684 /// object. [`fragments`](#common.TreeFragment) can be passed in to 14685 /// make the parse incremental. 14686 /// 14687 /// By default, the entire input is parsed. You can pass `ranges`, 14688 /// which should be a sorted array of non-empty, non-overlapping 14689 /// ranges, to parse only those ranges. The tree returned in that 14690 /// case will start at `ranges[0].from`. 14691 startParse(input, fragments, ranges) { 14692 if (typeof input == "string") 14693 input = new StringInput(input); 14694 ranges = !ranges ? [new Range(0, input.length)] : ranges.length ? ranges.map(r => new Range(r.from, r.to)) : [new Range(0, 0)]; 14695 return this.createParse(input, fragments || [], ranges); 14696 } 14697 /// Run a full parse, returning the resulting tree. 14698 parse(input, fragments, ranges) { 14699 let parse = this.startParse(input, fragments, ranges); 14700 for (;;) { 14701 let done = parse.advance(); 14702 if (done) 14703 return done; 14704 } 14705 } 14706} 14707class StringInput { 14708 constructor(string) { 14709 this.string = string; 14710 } 14711 get length() { return this.string.length; } 14712 chunk(from) { return this.string.slice(from); } 14713 get lineChunks() { return false; } 14714 read(from, to) { return this.string.slice(from, to); } 14715} 14716 14717/// Create a parse wrapper that, after the inner parse completes, 14718/// scans its tree for mixed language regions with the `nest` 14719/// function, runs the resulting [inner parses](#common.NestedParse), 14720/// and then [mounts](#common.NodeProp^mounted) their results onto the 14721/// tree. 14722function parseMixed(nest) { 14723 return (parse, input, fragments, ranges) => new MixedParse(parse, nest, input, fragments, ranges); 14724} 14725class InnerParse { 14726 constructor(parser, parse, overlay, target, ranges) { 14727 this.parser = parser; 14728 this.parse = parse;
14729 this.overlay = overlay; 14730 this.target = target; 14731 this.ranges = ranges; 14732 } 14733} 14734class ActiveOverlay { 14735 constructor(parser, predicate, mounts, index, start, target, prev) { 14736 this.parser = parser; 14737 this.predicate = predicate; 14738 this.mounts = mounts; 14739 this.index = index; 14740 this.start = start; 14741 this.target = target; 14742 this.prev = prev; 14743 this.depth = 0; 14744 this.ranges = []; 14745 } 14746} 14747const stoppedInner = new NodeProp({ perNode: true }); 14748class MixedParse { 14749 constructor(base, nest, input, fragments, ranges) { 14750 this.nest = nest; 14751 this.input = input; 14752 this.fragments = fragments; 14753 this.ranges = ranges; 14754 this.inner = []; 14755 this.innerDone = 0; 14756 this.baseTree = null; 14757 this.stoppedAt = null; 14758 this.baseParse = base; 14759 } 14760 advance() { 14761 if (this.baseParse) { 14762 let done = this.baseParse.advance(); 14763 if (!done) 14764 return null; 14765 this.baseParse = null; 14766 this.baseTree = done; 14767 this.startInner(); 14768 if (this.stoppedAt != null) 14769 for (let inner of this.inner) 14770 inner.parse.stopAt(this.stoppedAt); 14771 } 14772 if (this.innerDone == this.inner.length) { 14773 let result = this.baseTree; 14774 if (this.stoppedAt != null) 14775 result = new Tree(result.type, result.children, result.positions, result.length, result.propValues.concat([[stoppedInner, this.stoppedAt]])); 14776 return result; 14777 } 14778 let inner = this.inner[this.innerDone], done = inner.parse.advance(); 14779 if (done) { 14780 this.innerDone++; 14781 // This is a somewhat dodgy but super helpful hack where we 14782 // patch up nodes created by the inner parse (and thus 14783 // presumably not aliased anywhere else) to hold the information 14784 // about the inner parse. 14785 let props = Object.assign(Object.create(null), inner.target.props); 14786 props[NodeProp.mounted.id] = new MountedTree(done, inner.overlay, inner.parser); 14787 inner.target.props = props; 14788 } 14789 return null; 14790 } 14791 get parsedPos() { 14792 if (this.baseParse) 14793 return 0; 14794 let pos = this.input.length; 14795 for (let i = this.innerDone; i < this.inner.length; i++) { 14796 if (this.inner[i].ranges[0].from < pos) 14797 pos = Math.min(pos, this.inner[i].parse.parsedPos); 14798 } 14799 return pos; 14800 } 14801 stopAt(pos) { 14802 this.stoppedAt = pos; 14803 if (this.baseParse) 14804 this.baseParse.stopAt(pos); 14805 else 14806 for (let i = this.innerDone; i < this.inner.length; i++) 14807 this.inner[i].parse.stopAt(pos); 14808 } 14809 startInner() { 14810 let fragmentCursor = new FragmentCursor(this.fragments); 14811 let overlay = null; 14812 let covered = null; 14813 let cursor = new TreeCursor(new TreeNode(this.baseTree, this.ranges[0].from, 0, null), IterMode.IncludeAnonymous | IterMode.IgnoreMounts); 14814 scan: for (let nest, isCovered; this.stoppedAt == null || cursor.from < this.stoppedAt;) { 14815 let enter = true, range; 14816 if (fragmentCursor.hasNode(cursor)) { 14817 if (overlay) { 14818 let match = overlay.mounts.find(m => m.frag.from <= cursor.from && m.frag.to >= cursor.to && m.mount.overlay); 14819 if (match) 14820 for (let r of match.mount.overlay) { 14821 let from = r.from + match.pos, to = r.to + match.pos; 14822 if (from >= cursor.from && to <= cursor.to && !overlay.ranges.some(r => r.from < to && r.to > from)) 14823 overlay.ranges.push({ from, to }); 14824 } 14825 } 14826 enter = false; 14827 } 14828 else if (covered && (isCovered = checkCover(covered.ranges, cursor.from, cursor.to))) { 14829 enter = isCovered != 2 /* Cover.Full */; 14830 } 14831 else if (!cursor.type.isAnonymous && cursor.from < cursor.to && (nest = this.nest(cursor, this.input))) { 14832 if (!cursor.tree) 14833 materialize(cursor); 14834 let oldMounts = fragmentCursor.findMounts(cursor.from, nest.parser);
14835 if (typeof nest.overlay == "function") { 14836 overlay = new ActiveOverlay(nest.parser, nest.overlay, oldMounts, this.inner.length, cursor.from, cursor.tree, overlay); 14837 } 14838 else { 14839 let ranges = punchRanges(this.ranges, nest.overlay || [new Range(cursor.from, cursor.to)]); 14840 if (ranges.length) 14841 this.inner.push(new InnerParse(nest.parser, nest.parser.startParse(this.input, enterFragments(oldMounts, ranges), ranges), nest.overlay ? nest.overlay.map(r => new Range(r.from - cursor.from, r.to - cursor.from)) : null, cursor.tree, ranges)); 14842 if (!nest.overlay) 14843 enter = false; 14844 else if (ranges.length) 14845 covered = { ranges, depth: 0, prev: covered }; 14846 } 14847 } 14848 else if (overlay && (range = overlay.predicate(cursor))) { 14849 if (range === true) 14850 range = new Range(cursor.from, cursor.to); 14851 if (range.from < range.to) 14852 overlay.ranges.push(range); 14853 } 14854 if (enter && cursor.firstChild()) { 14855 if (overlay) 14856 overlay.depth++; 14857 if (covered) 14858 covered.depth++; 14859 } 14860 else { 14861 for (;;) { 14862 if (cursor.nextSibling()) 14863 break; 14864 if (!cursor.parent()) 14865 break scan; 14866 if (overlay && !--overlay.depth) { 14867 let ranges = punchRanges(this.ranges, overlay.ranges); 14868 if (ranges.length) 14869 this.inner.splice(overlay.index, 0, new InnerParse(overlay.parser, overlay.parser.startParse(this.input, enterFragments(overlay.mounts, ranges), ranges), overlay.ranges.map(r => new Range(r.from - overlay.start, r.to - overlay.start)), overlay.target, ranges)); 14870 overlay = overlay.prev; 14871 } 14872 if (covered && !--covered.depth) 14873 covered = covered.prev; 14874 } 14875 } 14876 } 14877 } 14878} 14879function checkCover(covered, from, to) { 14880 for (let range of covered) { 14881 if (range.from >= to) 14882 break; 14883 if (range.to > from) 14884 return range.from <= from && range.to >= to ? 2 /* Cover.Full */ : 1 /* Cover.Partial */; 14885 } 14886 return 0 /* Cover.None */; 14887} 14888// Take a piece of buffer and convert it into a stand-alone 14889// TreeBuffer. 14890function sliceBuf(buf, startI, endI, nodes, positions, off) { 14891 if (startI < endI) { 14892 let from = buf.buffer[startI + 1]; 14893 nodes.push(buf.slice(startI, endI, from)); 14894 positions.push(from - off); 14895 } 14896} 14897// This function takes a node that's in a buffer, and converts it, and 14898// its parent buffer nodes, into a Tree. This is again acting on the 14899// assumption that the trees and buffers have been constructed by the 14900// parse that was ran via the mix parser, and thus aren't shared with 14901// any other code, making violations of the immutability safe. 14902function materialize(cursor) { 14903 let { node } = cursor, depth = 0; 14904 // Scan up to the nearest tree 14905 do { 14906 cursor.parent(); 14907 depth++; 14908 } while (!cursor.tree); 14909 // Find the index of the buffer in that tree 14910 let i = 0, base = cursor.tree, off = 0; 14911 for (;; i++) { 14912 off = base.positions[i] + cursor.from; 14913 if (off <= node.from && off + base.children[i].length >= node.to) 14914 break; 14915 } 14916 let buf = base.children[i], b = buf.buffer; 14917 // Split a level in the buffer, putting the nodes before and after 14918 // the child that contains `node` into new buffers. 14919 function split(startI, endI, type, innerOffset, length) { 14920 let i = startI; 14921 while (b[i + 2] + off <= node.from) 14922 i = b[i + 3]; 14923 let children = [], positions = []; 14924 sliceBuf(buf, startI, i, children, positions, innerOffset); 14925 let from = b[i + 1], to = b[i + 2]; 14926 let isTarget = from + off == node.from && to + off == node.to && b[i] == node.type.id; 14927 children.push(isTarget ? node.toTree() : split(i + 4, b[i + 3], buf.set.types[b[i]], from, to - from)); 14928 positions.push(from - innerOffset); 14929 sliceBuf(buf, b[i + 3], endI, children, positions, innerOffset); 14930 return new Tree(type, children, positions, length); 14931 } 14932 base.children[i] = split(0, b.length, NodeType.none, 0, buf.length); 14933 // Move the cursor back to the target node 14934 for (let d = 0; d <= depth; d++) 14935 cursor.childAfter(node.from); 14936} 14937class StructureCursor { 14938 constructor(root, offset) { 14939 this.offset = offset; 14940 this.done = false;
vendor: 3,180 bytes, lines 14941-15024
14941 this.cursor = root.cursor(IterMode.IncludeAnonymous | IterMode.IgnoreMounts); 14942 } 14943 // Move to the first node (in pre-order) that starts at or after `pos`. 14944 moveTo(pos) { 14945 let { cursor } = this, p = pos - this.offset; 14946 while (!this.done && cursor.from < p) { 14947 if (cursor.to >= pos && cursor.enter(p, 1, IterMode.IgnoreOverlays | IterMode.ExcludeBuffers)) ; 14948 else if (!cursor.next(false)) 14949 this.done = true; 14950 } 14951 } 14952 hasNode(cursor) { 14953 this.moveTo(cursor.from); 14954 if (!this.done && this.cursor.from + this.offset == cursor.from && this.cursor.tree) { 14955 for (let tree = this.cursor.tree;;) { 14956 if (tree == cursor.tree) 14957 return true; 14958 if (tree.children.length && tree.positions[0] == 0 && tree.children[0] instanceof Tree) 14959 tree = tree.children[0]; 14960 else 14961 break; 14962 } 14963 } 14964 return false; 14965 } 14966} 14967class FragmentCursor { 14968 constructor(fragments) { 14969 var _a; 14970 this.fragments = fragments; 14971 this.curTo = 0; 14972 this.fragI = 0; 14973 if (fragments.length) { 14974 let first = this.curFrag = fragments[0]; 14975 this.curTo = (_a = first.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : first.to; 14976 this.inner = new StructureCursor(first.tree, -first.offset); 14977 } 14978 else { 14979 this.curFrag = this.inner = null; 14980 } 14981 } 14982 hasNode(node) { 14983 while (this.curFrag && node.from >= this.curTo) 14984 this.nextFrag(); 14985 return this.curFrag && this.curFrag.from <= node.from && this.curTo >= node.to && this.inner.hasNode(node); 14986 } 14987 nextFrag() { 14988 var _a; 14989 this.fragI++; 14990 if (this.fragI == this.fragments.length) { 14991 this.curFrag = this.inner = null; 14992 } 14993 else { 14994 let frag = this.curFrag = this.fragments[this.fragI]; 14995 this.curTo = (_a = frag.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : frag.to; 14996 this.inner = new StructureCursor(frag.tree, -frag.offset); 14997 } 14998 } 14999 findMounts(pos, parser) { 15000 var _a; 15001 let result = []; 15002 if (this.inner) { 15003 this.inner.cursor.moveTo(pos, 1); 15004 for (let pos = this.inner.cursor.node; pos; pos = pos.parent) { 15005 let mount = (_a = pos.tree) === null || _a === void 0 ? void 0 : _a.prop(NodeProp.mounted); 15006 if (mount && mount.parser == parser) { 15007 for (let i = this.fragI; i < this.fragments.length; i++) { 15008 let frag = this.fragments[i]; 15009 if (frag.from >= pos.to) 15010 break; 15011 if (frag.tree == this.curFrag.tree) 15012 result.push({ 15013 frag, 15014 pos: pos.from - frag.offset, 15015 mount 15016 }); 15017 } 15018 } 15019 } 15020 } 15021 return result; 15022 } 15023} 15024function punchRanges(outer, ranges) {
15025 let copy = null, current = ranges; 15026 for (let i = 1, j = 0; i < outer.length; i++) { 15027 let gapFrom = outer[i - 1].to, gapTo = outer[i].from; 15028 for (; j < current.length; j++) { 15029 let r = current[j]; 15030 if (r.from >= gapTo) 15031 break; 15032 if (r.to <= gapFrom) 15033 continue; 15034 if (!copy) 15035 current = copy = ranges.slice(); 15036 if (r.from < gapFrom) { 15037 copy[j] = new Range(r.from, gapFrom); 15038 if (r.to > gapTo) 15039 copy.splice(j + 1, 0, new Range(gapTo, r.to)); 15040 } 15041 else if (r.to > gapTo) { 15042 copy[j--] = new Range(gapTo, r.to); 15043 } 15044 else { 15045 copy.splice(j--, 1); 15046 } 15047 } 15048 } 15049 return current; 15050} 15051function findCoverChanges(a, b, from, to) { 15052 let iA = 0, iB = 0, inA = false, inB = false, pos = -1e9; 15053 let result = []; 15054 for (;;) { 15055 let nextA = iA == a.length ? 1e9 : inA ? a[iA].to : a[iA].from; 15056 let nextB = iB == b.length ? 1e9 : inB ? b[iB].to : b[iB].from; 15057 if (inA != inB) { 15058 let start = Math.max(pos, from), end = Math.min(nextA, nextB, to); 15059 if (start < end) 15060 result.push(new Range(start, end)); 15061 } 15062 pos = Math.min(nextA, nextB); 15063 if (pos == 1e9) 15064 break; 15065 if (nextA == pos) { 15066 if (!inA) 15067 inA = true; 15068 else { 15069 inA = false; 15070 iA++; 15071 } 15072 } 15073 if (nextB == pos) { 15074 if (!inB) 15075 inB = true; 15076 else { 15077 inB = false; 15078 iB++; 15079 } 15080 } 15081 } 15082 return result; 15083} 15084// Given a number of fragments for the outer tree, and a set of ranges 15085// to parse, find fragments for inner trees mounted around those 15086// ranges, if any. 15087function enterFragments(mounts, ranges) { 15088 let result = []; 15089 for (let { pos, mount, frag } of mounts) { 15090 let startPos = pos + (mount.overlay ? mount.overlay[0].from : 0), endPos = startPos + mount.tree.length; 15091 let from = Math.max(frag.from, startPos), to = Math.min(frag.to, endPos); 15092 if (mount.overlay) { 15093 let overlay = mount.overlay.map(r => new Range(r.from + pos, r.to + pos)); 15094 let changes = findCoverChanges(ranges, overlay, from, to); 15095 for (let i = 0, pos = from;; i++) { 15096 let last = i == changes.length, end = last ? to : changes[i].from; 15097 if (end > pos) 15098 result.push(new TreeFragment(pos, end, mount.tree, -startPos, frag.from >= pos || frag.openStart, frag.to <= end || frag.openEnd)); 15099 if (last) 15100 break; 15101 pos = changes[i].to; 15102 } 15103 } 15104 else { 15105 result.push(new TreeFragment(from, to, mount.tree, -startPos, frag.from >= startPos || frag.openStart, frag.to <= endPos || frag.openEnd)); 15106 } 15107 } 15108 return result; 15109} 15110 15111let nextTagID = 0; 15112/// Highlighting tags are markers that denote a highlighting category. 15113/// They are [associated](#highlight.styleTags) with parts of a syntax 15114/// tree by a language mode, and then mapped to an actual CSS style by 15115/// a [highlighter](#highlight.Highlighter). 15116/// 15117/// Because syntax tree node types and highlight styles have to be 15118/// able to talk the same language, CodeMirror uses a mostly _closed_ 15119/// [vocabulary](#highlight.tags) of syntax tags (as opposed to 15120/// traditional open string-based systems, which make it hard for 15121/// highlighting themes to cover all the tokens produced by the 15122/// various languages). 15123/// 15124/// It _is_ possible to [define](#highlight.Tag^define) your own 15125/// highlighting tags for system-internal use (where you control both 15126/// the language package and the highlighter), but such tags will not 15127/// be picked up by regular highlighters (though you can derive them 15128/// from standard tags to allow highlighters to fall back to those). 15129class Tag { 15130 /// @internal 15131 constructor( 15132 /// The set of this tag and all its parent tags, starting with 15133 /// this one itself and sorted in order of decreasing specificity. 15134 set, 15135 /// The base unmodified tag that this one is based on, if it's 15136 /// modified @internal 15137 base, 15138 /// The modifiers applied to this.base @internal 15139 modified) { 15140 this.set = set; 15141 this.base = base; 15142 this.modified = modified; 15143 /// @internal 15144 this.id = nextTagID++; 15145 } 15146 /// Define a new tag. If `parent` is given, the tag is treated as a 15147 /// sub-tag of that parent, and 15148 /// [highlighters](#highlight.tagHighlighter) that don't mention 15149 /// this tag will try to fall back to the parent tag (or grandparent 15150 /// tag, etc). 15151 static define(parent) { 15152 if (parent === null || parent === void 0 ? void 0 : parent.base) 15153 throw new Error("Can not derive from a modified tag"); 15154 let tag = new Tag([], null, []); 15155 tag.set.push(tag); 15156 if (parent) 15157 for (let t of parent.set) 15158 tag.set.push(t); 15159 return tag; 15160 } 15161 /// Define a tag _modifier_, which is a function that, given a tag, 15162 /// will return a tag that is a subtag of the original. Applying the 15163 /// same modifier to a twice tag will return the same value (`m1(t1) 15164 /// == m1(t1)`) and applying multiple modifiers will, regardless or 15165 /// order, produce the same tag (`m1(m2(t1)) == m2(m1(t1))`). 15166 /// 15167 /// When multiple modifiers are applied to a given base tag, each 15168 /// smaller set of modifiers is registered as a parent, so that for 15169 /// example `m1(m2(m3(t1)))` is a subtype of `m1(m2(t1))`, 15170 /// `m1(m3(t1)`, and so on. 15171 static defineModifier() { 15172 let mod = new Modifier; 15173 return (tag) => { 15174 if (tag.modified.indexOf(mod) > -1) 15175 return tag; 15176 return Modifier.get(tag.base || tag, tag.modified.concat(mod).sort((a, b) => a.id - b.id)); 15177 }; 15178 } 15179} 15180let nextModifierID = 0; 15181class Modifier { 15182 constructor() { 15183 this.instances = []; 15184 this.id = nextModifierID++; 15185 } 15186 static get(base, mods) { 15187 if (!mods.length) 15188 return base; 15189 let exists = mods[0].instances.find(t => t.base == base && sameArray(mods, t.modified)); 15190 if (exists) 15191 return exists; 15192 let set = [], tag = new Tag(set, base, mods); 15193 for (let m of mods) 15194 m.instances.push(tag); 15195 let configs = powerSet(mods); 15196 for (let parent of base.set) 15197 if (!parent.modified.length) 15198 for (let config of configs) 15199 set.push(Modifier.get(parent, config)); 15200 return tag; 15201 } 15202} 15203function sameArray(a, b) { 15204 return a.length == b.length && a.every((x, i) => x == b[i]); 15205} 15206function powerSet(array) { 15207 let sets = [[]]; 15208 for (let i = 0; i < array.length; i++) { 15209 for (let j = 0, e = sets.length; j < e; j++) { 15210 sets.push(sets[j].concat(array[i])); 15211 } 15212 } 15213 return sets.sort((a, b) => b.length - a.length); 15214} 15215/// This function is used to add a set of tags to a language syntax 15216/// via [`NodeSet.extend`](#common.NodeSet.extend) or 15217/// [`LRParser.configure`](#lr.LRParser.configure). 15218/// 15219/// The argument object maps node selectors to [highlighting 15220/// tags](#highlight.Tag) or arrays of tags. 15221/// 15222/// Node selectors may hold one or more (space-separated) node paths.
15223/// Such a path can be a [node name](#common.NodeType.name), or 15224/// multiple node names (or `*` wildcards) separated by slash 15225/// characters, as in `"Block/Declaration/VariableName"`. Such a path 15226/// matches the final node but only if its direct parent nodes are the 15227/// other nodes mentioned. A `*` in such a path matches any parent, 15228/// but only a single levelâwildcards that match multiple parents 15229/// aren't supported, both for efficiency reasons and because Lezer 15230/// trees make it rather hard to reason about what they would match.) 15231/// 15232/// A path can be ended with `/...` to indicate that the tag assigned 15233/// to the node should also apply to all child nodes, even if they 15234/// match their own style (by default, only the innermost style is 15235/// used). 15236/// 15237/// When a path ends in `!`, as in `Attribute!`, no further matching 15238/// happens for the node's child nodes, and the entire node gets the 15239/// given style. 15240/// 15241/// In this notation, node names that contain `/`, `!`, `*`, or `...` 15242/// must be quoted as JSON strings. 15243/// 15244/// For example: 15245/// 15246/// ```javascript 15247/// parser.withProps( 15248/// styleTags({ 15249/// // Style Number and BigNumber nodes 15250/// "Number BigNumber": tags.number, 15251/// // Style Escape nodes whose parent is String 15252/// "String/Escape": tags.escape, 15253/// // Style anything inside Attributes nodes 15254/// "Attributes!": tags.meta, 15255/// // Add a style to all content inside Italic nodes 15256/// "Italic/...": tags.emphasis,
vendor: 8,169 bytes, lines 15257-15467
15257/// // Style InvalidString nodes as both `string` and `invalid` 15258/// "InvalidString": [tags.string, tags.invalid], 15259/// // Style the node named "/" as punctuation 15260/// '"/"': tags.punctuation 15261/// }) 15262/// ) 15263/// ``` 15264function styleTags(spec) { 15265 let byName = Object.create(null); 15266 for (let prop in spec) { 15267 let tags = spec[prop]; 15268 if (!Array.isArray(tags)) 15269 tags = [tags]; 15270 for (let part of prop.split(" ")) 15271 if (part) { 15272 let pieces = [], mode = 2 /* Mode.Normal */, rest = part; 15273 for (let pos = 0;;) { 15274 if (rest == "..." && pos > 0 && pos + 3 == part.length) { 15275 mode = 1 /* Mode.Inherit */; 15276 break; 15277 } 15278 let m = /^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(rest); 15279 if (!m) 15280 throw new RangeError("Invalid path: " + part); 15281 pieces.push(m[0] == "*" ? "" : m[0][0] == '"' ? JSON.parse(m[0]) : m[0]); 15282 pos += m[0].length; 15283 if (pos == part.length) 15284 break; 15285 let next = part[pos++]; 15286 if (pos == part.length && next == "!") { 15287 mode = 0 /* Mode.Opaque */; 15288 break; 15289 } 15290 if (next != "/") 15291 throw new RangeError("Invalid path: " + part); 15292 rest = part.slice(pos); 15293 } 15294 let last = pieces.length - 1, inner = pieces[last]; 15295 if (!inner) 15296 throw new RangeError("Invalid path: " + part); 15297 let rule = new Rule(tags, mode, last > 0 ? pieces.slice(0, last) : null); 15298 byName[inner] = rule.sort(byName[inner]); 15299 } 15300 } 15301 return ruleNodeProp.add(byName); 15302} 15303const ruleNodeProp = new NodeProp(); 15304class Rule { 15305 constructor(tags, mode, context, next) { 15306 this.tags = tags; 15307 this.mode = mode; 15308 this.context = context; 15309 this.next = next; 15310 } 15311 get opaque() { return this.mode == 0 /* Mode.Opaque */; } 15312 get inherit() { return this.mode == 1 /* Mode.Inherit */; } 15313 sort(other) { 15314 if (!other || other.depth < this.depth) { 15315 this.next = other; 15316 return this; 15317 } 15318 other.next = this.sort(other.next); 15319 return other; 15320 } 15321 get depth() { return this.context ? this.context.length : 0; } 15322} 15323Rule.empty = new Rule([], 2 /* Mode.Normal */, null); 15324/// Define a [highlighter](#highlight.Highlighter) from an array of 15325/// tag/class pairs. Classes associated with more specific tags will 15326/// take precedence. 15327function tagHighlighter(tags, options) { 15328 let map = Object.create(null); 15329 for (let style of tags) { 15330 if (!Array.isArray(style.tag)) 15331 map[style.tag.id] = style.class; 15332 else 15333 for (let tag of style.tag) 15334 map[tag.id] = style.class; 15335 } 15336 let { scope, all = null } = options || {}; 15337 return { 15338 style: (tags) => { 15339 let cls = all; 15340 for (let tag of tags) { 15341 for (let sub of tag.set) { 15342 let tagClass = map[sub.id]; 15343 if (tagClass) { 15344 cls = cls ? cls + " " + tagClass : tagClass; 15345 break; 15346 } 15347 } 15348 } 15349 return cls; 15350 }, 15351 scope 15352 }; 15353} 15354function highlightTags(highlighters, tags) { 15355 let result = null; 15356 for (let highlighter of highlighters) { 15357 let value = highlighter.style(tags); 15358 if (value) 15359 result = result ? result + " " + value : value; 15360 } 15361 return result; 15362} 15363/// Highlight the given [tree](#common.Tree) with the given 15364/// [highlighter](#highlight.Highlighter). 15365function highlightTree(tree, highlighter, 15366/// Assign styling to a region of the text. Will be called, in order 15367/// of position, for any ranges where more than zero classes apply. 15368/// `classes` is a space separated string of CSS classes. 15369putStyle, 15370/// The start of the range to highlight. 15371from = 0, 15372/// The end of the range. 15373to = tree.length) { 15374 let builder = new HighlightBuilder(from, Array.isArray(highlighter) ? highlighter : [highlighter], putStyle); 15375 builder.highlightRange(tree.cursor(), from, to, "", builder.highlighters); 15376 builder.flush(to); 15377} 15378class HighlightBuilder { 15379 constructor(at, highlighters, span) { 15380 this.at = at; 15381 this.highlighters = highlighters; 15382 this.span = span; 15383 this.class = ""; 15384 } 15385 startSpan(at, cls) { 15386 if (cls != this.class) { 15387 this.flush(at); 15388 if (at > this.at) 15389 this.at = at; 15390 this.class = cls; 15391 } 15392 } 15393 flush(to) { 15394 if (to > this.at && this.class) 15395 this.span(this.at, to, this.class); 15396 } 15397 highlightRange(cursor, from, to, inheritedClass, highlighters) { 15398 let { type, from: start, to: end } = cursor; 15399 if (start >= to || end <= from) 15400 return; 15401 if (type.isTop) 15402 highlighters = this.highlighters.filter(h => !h.scope || h.scope(type)); 15403 let cls = inheritedClass; 15404 let rule = getStyleTags(cursor) || Rule.empty; 15405 let tagCls = highlightTags(highlighters, rule.tags); 15406 if (tagCls) { 15407 if (cls) 15408 cls += " "; 15409 cls += tagCls; 15410 if (rule.mode == 1 /* Mode.Inherit */) 15411 inheritedClass += (inheritedClass ? " " : "") + tagCls; 15412 } 15413 this.startSpan(cursor.from, cls); 15414 if (rule.opaque) 15415 return; 15416 let mounted = cursor.tree && cursor.tree.prop(NodeProp.mounted); 15417 if (mounted && mounted.overlay) { 15418 let inner = cursor.node.enter(mounted.overlay[0].from + start, 1); 15419 let innerHighlighters = this.highlighters.filter(h => !h.scope || h.scope(mounted.tree.type)); 15420 let hasChild = cursor.firstChild(); 15421 for (let i = 0, pos = start;; i++) { 15422 let next = i < mounted.overlay.length ? mounted.overlay[i] : null; 15423 let nextPos = next ? next.from + start : end; 15424 let rangeFrom = Math.max(from, pos), rangeTo = Math.min(to, nextPos); 15425 if (rangeFrom < rangeTo && hasChild) { 15426 while (cursor.from < rangeTo) { 15427 this.highlightRange(cursor, rangeFrom, rangeTo, inheritedClass, highlighters); 15428 this.startSpan(Math.min(rangeTo, cursor.to), cls); 15429 if (cursor.to >= nextPos || !cursor.nextSibling()) 15430 break; 15431 } 15432 } 15433 if (!next || nextPos > to) 15434 break; 15435 pos = next.to + start; 15436 if (pos > from) { 15437 this.highlightRange(inner.cursor(), Math.max(from, next.from + start), Math.min(to, pos), inheritedClass, innerHighlighters); 15438 this.startSpan(pos, cls); 15439 } 15440 } 15441 if (hasChild) 15442 cursor.parent(); 15443 } 15444 else if (cursor.firstChild()) { 15445 do { 15446 if (cursor.to <= from) 15447 continue; 15448 if (cursor.from >= to) 15449 break; 15450 this.highlightRange(cursor, from, to, inheritedClass, highlighters); 15451 this.startSpan(Math.min(to, cursor.to), cls); 15452 } while (cursor.nextSibling()); 15453 cursor.parent(); 15454 } 15455 } 15456} 15457/// Match a syntax node's [highlight rules](#highlight.styleTags). If 15458/// there's a match, return its set of tags, and whether it is 15459/// opaque (uses a `!`) or applies to all child nodes (`/...`). 15460function getStyleTags(node) { 15461 let rule = node.type.prop(ruleNodeProp); 15462 while (rule && rule.context && !node.matchContext(rule.context)) 15463 rule = rule.next; 15464 return rule || null; 15465} 15466const t = Tag.define; 15467const comment = t(), name = t(), typeName = t(name), propertyName = t(name), literal = t(), string = t(literal), number = t(literal), c
15467ontent = t(), heading = t(content), keyword = t(), operator = t(), punctuation = t(), bracket = t(punctuation), meta = t(); 15468/// The default set of highlighting [tags](#highlight.Tag). 15469/// 15470/// This collection is heavily biased towards programming languages, 15471/// and necessarily incomplete. A full ontology of syntactic 15472/// constructs would fill a stack of books, and be impractical to 15473/// write themes for. So try to make do with this set. If all else 15474/// fails, [open an 15475/// issue](https://github.com/codemirror/codemirror.next) to propose a 15476/// new tag, or [define](#highlight.Tag^define) a local custom tag for 15477/// your use case. 15478/// 15479/// Note that it is not obligatory to always attach the most specific 15480/// tag possible to an elementâif your grammar can't easily 15481/// distinguish a certain type of element (such as a local variable), 15482/// it is okay to style it as its more general variant (a variable). 15483/// 15484/// For tags that extend some parent tag, the documentation links to 15485/// the parent. 15486const tags = { 15487 /// A comment. 15488 comment, 15489 /// A line [comment](#highlight.tags.comment). 15490 lineComment: t(comment), 15491 /// A block [comment](#highlight.tags.comment). 15492 blockComment: t(comment), 15493 /// A documentation [comment](#highlight.tags.comment). 15494 docComment: t(comment), 15495 /// Any kind of identifier. 15496 name, 15497 /// The [name](#highlight.tags.name) of a variable. 15498 variableName: t(name), 15499 /// A type [name](#highlight.tags.name). 15500 typeName: typeName, 15501 /// A tag name (subtag of [`typeName`](#highlight.tags.typeName)). 15502 tagName: t(typeName), 15503 /// A property or field [name](#highlight.tags.name). 15504 propertyName: propertyName, 15505 /// An attribute name (subtag of [`propertyName`](#highlight.tags.propertyName)). 15506 attributeName: t(propertyName), 15507 /// The [name](#highlight.tags.name) of a class. 15508 className: t(name), 15509 /// A label [name](#highlight.tags.name). 15510 labelName: t(name), 15511 /// A namespace [name](#highlight.tags.name). 15512 namespace: t(name), 15513 /// The [name](#highlight.tags.name) of a macro. 15514 macroName: t(name), 15515 /// A literal value. 15516 literal, 15517 /// A string [literal](#highlight.tags.literal). 15518 string, 15519 /// A documentation [string](#highlight.tags.string). 15520 docString: t(string), 15521 /// A character literal (subtag of [string](#highlight.tags.string)). 15522 character: t(string), 15523 /// An attribute value (subtag of [string](#highlight.tags.string)). 15524 attributeValue: t(string), 15525 /// A number [literal](#highlight.tags.literal). 15526 number, 15527 /// An integer [number](#highlight.tags.number) literal. 15528 integer: t(number), 15529 /// A floating-point [number](#highlight.tags.number) literal. 15530 float: t(number), 15531 /// A boolean [literal](#highlight.tags.literal). 15532 bool: t(literal), 15533 /// Regular expression [literal](#highlight.tags.literal). 15534 regexp: t(literal), 15535 /// An escape [literal](#highlight.tags.literal), for example a 15536 /// backslash escape in a string. 15537 escape: t(literal), 15538 /// A color [literal](#highlight.tags.literal). 15539 color: t(literal), 15540 /// A URL [literal](#highlight.tags.literal). 15541 url: t(literal), 15542 /// A language keyword. 15543 keyword, 15544 /// The [keyword](#highlight.tags.keyword) for the self or this 15545 /// object. 15546 self: t(keyword), 15547 /// The [keyword](#highlight.tags.keyword) for null. 15548 null: t(keyword), 15549 /// A [keyword](#highlight.tags.keyword) denoting some atomic value. 15550 atom: t(keyword), 15551 /// A [keyword](#highlight.tags.keyword) that represents a unit. 15552 unit: t(keyword), 15553 /// A modifier [keyword](#highlight.tags.keyword). 15554 modifier: t(keyword), 15555 /// A [keyword](#highlight.tags.keyword) that acts as an operator. 15556 operatorKeyword: t(keyword), 15557 /// A control-flow related [keyword](#highlight.tags.keyword). 15558 controlKeyword: t(keyword), 15559 /// A [keyword](#highlight.tags.keyword) that defines something. 15560 definitionKeyword: t(keyword), 15561 /// A [keyword](#highlight.tags.keyword) related to defining or 15562 /// interfacing with modules. 15563 moduleKeyword: t(keyword), 15564 /// An operator. 15565 operator, 15566 /// An [operator](#highlight.tags.operator) that dereferences something. 15567 derefOperator: t(operator), 15568 /// Arithmetic-related [operator](#highlight.tags.operator). 15569 arithmeticOperator: t(operator), 15570 /// Logical [operator](#highlight.tags.operator). 15571 logicOperator: t(operator), 15572 /// Bit [operator](#highlight.tags.operator). 15573 bitwiseOperator: t(operator), 15574 /// Comparison [operator](#highlight.tags.operator). 15575 compareOperator: t(operator), 15576 /// [Operator](#highlight.tags.operator) that updates its operand. 15577 updateOperator: t(operator), 15578 /// [Operator](#highlight.tags.operator) that defines something. 15579 definitionOperator: t(operator), 15580 /// Type-related [operator](#highlight.tags.operator). 15581 typeOperator: t(operator), 15582 /// Control-flow [operator](#highlight.tags.operator). 15583 controlOperator: t(operator), 15584 /// Program or markup punctuation. 15585 punctuation, 15586 /// [Punctuation](#highlight.tags.punctuation) that separates 15587 /// things. 15588 separator: t(punctuation), 15589 /// Bracket-style [punctuation](#highlight.tags.punctuation). 15590 bracket,
15591 /// Angle [brackets](#highlight.tags.bracket) (usually `<` and `>` 15592 /// tokens). 15593 angleBracket: t(bracket), 15594 /// Square [brackets](#highlight.tags.bracket) (usually `[` and `]` 15595 /// tokens). 15596 squareBracket: t(bracket), 15597 /// Parentheses (usually `(` and `)` tokens). Subtag of 15598 /// [bracket](#highlight.tags.bracket). 15599 paren: t(bracket), 15600 /// Braces (usually `{` and `}` tokens). Subtag of 15601 /// [bracket](#highlight.tags.bracket). 15602 brace: t(bracket), 15603 /// Content, for example plain text in XML or markup documents. 15604 content, 15605 /// [Content](#highlight.tags.content) that represents a heading. 15606 heading, 15607 /// A level 1 [heading](#highlight.tags.heading). 15608 heading1: t(heading), 15609 /// A level 2 [heading](#highlight.tags.heading). 15610 heading2: t(heading), 15611 /// A level 3 [heading](#highlight.tags.heading). 15612 heading3: t(heading), 15613 /// A level 4 [heading](#highlight.tags.heading). 15614 heading4: t(heading), 15615 /// A level 5 [heading](#highlight.tags.heading). 15616 heading5: t(heading), 15617 /// A level 6 [heading](#highlight.tags.heading). 15618 heading6: t(heading), 15619 /// A prose separator (such as a horizontal rule). 15620 contentSeparator: t(content), 15621 /// [Content](#highlight.tags.content) that represents a list. 15622 list: t(content), 15623 /// [Content](#highlight.tags.content) that represents a quote. 15624 quote: t(content), 15625 /// [Content](#highlight.tags.content) that is emphasized. 15626 emphasis: t(content), 15627 /// [Content](#highlight.tags.content) that is styled strong. 15628 strong: t(content), 15629 /// [Content](#highlight.tags.content) that is part of a link. 15630 link: t(content), 15631 /// [Content](#highlight.tags.content) that is styled as code or 15632 /// monospace. 15633 monospace: t(content), 15634 /// [Content](#highlight.tags.content) that has a strike-through 15635 /// style. 15636 strikethrough: t(content), 15637 /// Inserted text in a change-tracking format. 15638 inserted: t(), 15639 /// Deleted text. 15640 deleted: t(), 15641 /// Changed text. 15642 changed: t(), 15643 /// An invalid or unsyntactic element. 15644 invalid: t(), 15645 /// Metadata or meta-instruction. 15646 meta, 15647 /// [Metadata](#highlight.tags.meta) that applies to the entire 15648 /// document. 15649 documentMeta: t(meta), 15650 /// [Metadata](#highlight.tags.meta) that annotates or adds 15651 /// attributes to a given syntactic element. 15652 annotation: t(meta), 15653 /// Processing instruction or preprocessor directive. Subtag of 15654 /// [meta](#highlight.tags.meta). 15655 processingInstruction: t(meta), 15656 /// [Modifier](#highlight.Tag^defineModifier) that indicates that a 15657 /// given element is being defined. Expected to be used with the 15658 /// various [name](#highlight.tags.name) tags. 15659 definition: Tag.defineModifier(), 15660 /// [Modifier](#highlight.Tag^defineModifier) that indicates that 15661 /// something is constant. Mostly expected to be used with 15662 /// [variable names](#highlight.tags.variableName). 15663 constant: Tag.defineModifier(), 15664 /// [Modifier](#highlight.Tag^defineModifier) used to indicate that 15665 /// a [variable](#highlight.tags.variableName) or [property 15666 /// name](#highlight.tags.propertyName) is being called or defined 15667 /// as a function. 15668 function: Tag.defineModifier(), 15669 /// [Modifier](#highlight.Tag^defineModifier) that can be applied to 15670 /// [names](#highlight.tags.name) to indicate that they belong to 15671 /// the language's standard environment. 15672 standard: Tag.defineModifier(), 15673 /// [Modifier](#highlight.Tag^defineModifier) that indicates a given 15674 /// [names](#highlight.tags.name) is local to some scope. 15675 local: Tag.defineModifier(), 15676 /// A generic variant [modifier](#highlight.Tag^defineModifier) that 15677 /// can be used to tag language-specific alternative variants of 15678 /// some common tag. It is recommended for themes to define special 15679 /// forms of at least the [string](#highlight.tags.string) and 15680 /// [variable name](#highlight.tags.variableName) tags, since those 15681 /// come up a lot. 15682 special: Tag.defineModifier() 15683}; 15684/// This is a highlighter that adds stable, predictable classes to 15685/// tokens, for styling with external CSS. 15686/// 15687/// The following tags are mapped to their name prefixed with `"tok-"` 15688/// (for example `"tok-comment"`): 15689/// 15690/// * [`link`](#highlight.tags.link) 15691/// * [`heading`](#highlight.tags.heading) 15692/// * [`emphasis`](#highlight.tags.emphasis) 15693/// * [`strong`](#highlight.tags.strong) 15694/// * [`keyword`](#highlight.tags.keyword) 15695/// * [`atom`](#highlight.tags.atom) 15696/// * [`bool`](#highlight.tags.bool) 15697/// * [`url`](#highlight.tags.url) 15698/// * [`labelName`](#highlight.tags.labelName) 15699/// * [`inserted`](#highlight.tags.inserted) 15700/// * [`deleted`](#highlight.tags.deleted) 15701/// * [`literal`](#highlight.tags.literal) 15702/// * [`string`](#highlight.tags.string) 15703/// * [`number`](#highlight.tags.number) 15704/// * [`variableName`](#highlight.tags.variableName) 15705/// * [`typeName`](#highlight.tags.typeName) 15706/// * [`namespace`](#highlight.tags.namespace) 15707/// * [`className`](#highlight.tags.className) 15708/// * [`macroName`](#highlight.tags.macroName) 15709/// * [`propertyName`](#highlight.tags.propertyName) 15710/// * [`operator`](#highlight.tags.operator) 15711/// * [`comment`](#highlight.tags.comment) 15712/// * [`meta`](#highlight.tags.meta) 15713/// * [`punctuation`](#highlight.tags.punctuation) 15714/// * [`invalid`](#highlight.tags.invalid) 15715/// 15716/// In addition, these mappings are provided: 15717/// 15718/// * [`regexp`](#highlight.tags.regexp), 15719/// [`escape`](#highlight.tags.escape), and 15720/// [`special`](#highlight.tags.special)[`(string)`](#highlight.tags.string) 15721/// are mapped to `"tok-string2"` 15722/// * [`special`](#highlight.tags.special)[`(variableName)`](#highlight.tags.variableName) 15723/// to `"tok-variableName2"` 15724/// * [`local`](#highlight.tags.local)[`(variableName)`](#highlight.tags.variableName) 15725/// to `"tok-variableName tok-local"` 15726/// * [`definition`](#highlight.tags.definition)[`(variableName)`](#highlight.tags.variableName) 15727/// to `"tok-variableName tok-definition"` 15728/// * [`definition`](#highlight.tags.definition)[`(propertyName)`](#highlight.tags.propertyName) 15729/// to `"tok-propertyName tok-definition"` 15730tagHighlighter([ 15731 { tag: tags.link, class: "tok-link" }, 15732 { tag: tags.heading, class: "tok-heading" }, 15733 { tag: tags.emphasis, class: "tok-emphasis" }, 15734 { tag: tags.strong, class: "tok-strong" }, 15735 { tag: tags.keyword, class: "tok-keyword" }, 15736 { tag: tags.atom, class: "tok-atom" }, 15737 { tag: tags.bool, class: "tok-bool" }, 15738 { tag: tags.url, class: "tok-url" }, 15739 { tag: tags.labelName, class: "tok-labelName" }, 15740 { tag: tags.inserted, class: "tok-inserted" }, 15741 { tag: tags.deleted, class: "tok-deleted" }, 15742 { tag: tags.literal, class: "tok-literal" }, 15743 { tag: tags.string, class: "tok-string" },
vendor: 4,887 bytes, lines 15744-15854
15744 { tag: tags.number, class: "tok-number" }, 15745 { tag: [tags.regexp, tags.escape, tags.special(tags.string)], class: "tok-string2" }, 15746 { tag: tags.variableName, class: "tok-variableName" }, 15747 { tag: tags.local(tags.variableName), class: "tok-variableName tok-local" }, 15748 { tag: tags.definition(tags.variableName), class: "tok-variableName tok-definition" }, 15749 { tag: tags.special(tags.variableName), class: "tok-variableName2" }, 15750 { tag: tags.definition(tags.propertyName), class: "tok-propertyName tok-definition" }, 15751 { tag: tags.typeName, class: "tok-typeName" }, 15752 { tag: tags.namespace, class: "tok-namespace" }, 15753 { tag: tags.className, class: "tok-className" }, 15754 { tag: tags.macroName, class: "tok-macroName" }, 15755 { tag: tags.propertyName, class: "tok-propertyName" }, 15756 { tag: tags.operator, class: "tok-operator" }, 15757 { tag: tags.comment, class: "tok-comment" }, 15758 { tag: tags.meta, class: "tok-meta" }, 15759 { tag: tags.invalid, class: "tok-invalid" }, 15760 { tag: tags.punctuation, class: "tok-punctuation" } 15761]); 15762 15763var _a; 15764/** 15765Node prop stored in a parser's top syntax node to provide the 15766facet that stores language-specific data for that language. 15767*/ 15768const languageDataProp = /*@__PURE__*/new NodeProp(); 15769/** 15770Helper function to define a facet (to be added to the top syntax 15771node(s) for a language via 15772[`languageDataProp`](https://codemirror.net/6/docs/ref/#language.languageDataProp)), that will be 15773used to associate language data with the language. You 15774probably only need this when subclassing 15775[`Language`](https://codemirror.net/6/docs/ref/#language.Language). 15776*/ 15777function defineLanguageFacet(baseData) { 15778 return Facet.define({ 15779 combine: baseData ? values => values.concat(baseData) : undefined 15780 }); 15781} 15782/** 15783Syntax node prop used to register sublangauges. Should be added to 15784the top level node type for the language. 15785*/ 15786const sublanguageProp = /*@__PURE__*/new NodeProp(); 15787/** 15788A language object manages parsing and per-language 15789[metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is 15790managed as a [Lezer](https://lezer.codemirror.net) tree. The class 15791can be used directly, via the [`LRLanguage`](https://codemirror.net/6/docs/ref/#language.LRLanguage) 15792subclass for [Lezer](https://lezer.codemirror.net/) LR parsers, or 15793via the [`StreamLanguage`](https://codemirror.net/6/docs/ref/#language.StreamLanguage) subclass 15794for stream parsers. 15795*/ 15796class Language { 15797 /** 15798 Construct a language object. If you need to invoke this 15799 directly, first define a data facet with 15800 [`defineLanguageFacet`](https://codemirror.net/6/docs/ref/#language.defineLanguageFacet), and then 15801 configure your parser to [attach](https://codemirror.net/6/docs/ref/#language.languageDataProp) it 15802 to the language's outer syntax node. 15803 */ 15804 constructor( 15805 /** 15806 The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) facet 15807 used for this language. 15808 */ 15809 data, parser, extraExtensions = [], 15810 /** 15811 A language name. 15812 */ 15813 name = "") { 15814 this.data = data; 15815 this.name = name; 15816 // Kludge to define EditorState.tree as a debugging helper, 15817 // without the EditorState package actually knowing about 15818 // languages and lezer trees. 15819 if (!EditorState.prototype.hasOwnProperty("tree")) 15820 Object.defineProperty(EditorState.prototype, "tree", { get() { return syntaxTree(this); } }); 15821 this.parser = parser; 15822 this.extension = [ 15823 language.of(this), 15824 EditorState.languageData.of((state, pos, side) => { 15825 let top = topNodeAt(state, pos, side), data = top.type.prop(languageDataProp); 15826 if (!data) 15827 return []; 15828 let base = state.facet(data), sub = top.type.prop(sublanguageProp); 15829 if (sub) { 15830 let innerNode = top.resolve(pos - top.from, side); 15831 for (let sublang of sub) 15832 if (sublang.test(innerNode, state)) { 15833 let data = state.facet(sublang.facet); 15834 return sublang.type == "replace" ? data : data.concat(base); 15835 } 15836 } 15837 return base; 15838 }) 15839 ].concat(extraExtensions); 15840 } 15841 /** 15842 Query whether this language is active at the given position. 15843 */ 15844 isActiveAt(state, pos, side = -1) { 15845 return topNodeAt(state, pos, side).type.prop(languageDataProp) == this.data; 15846 } 15847 /** 15848 Find the document regions that were parsed using this language. 15849 The returned regions will _include_ any nested languages rooted 15850 in this language, when those exist. 15851 */ 15852 findRegions(state) { 15853 let lang = state.facet(language); 15854 if ((lang === null || lang === void 0 ? void 0 : lang.data) == this.data)
vendor: 3,337 bytes, lines 15855-15948
15855 return [{ from: 0, to: state.doc.length }]; 15856 if (!lang || !lang.allowsNesting) 15857 return []; 15858 let result = []; 15859 let explore = (tree, from) => { 15860 if (tree.prop(languageDataProp) == this.data) { 15861 result.push({ from, to: from + tree.length }); 15862 return; 15863 } 15864 let mount = tree.prop(NodeProp.mounted); 15865 if (mount) { 15866 if (mount.tree.prop(languageDataProp) == this.data) { 15867 if (mount.overlay) 15868 for (let r of mount.overlay) 15869 result.push({ from: r.from + from, to: r.to + from }); 15870 else 15871 result.push({ from: from, to: from + tree.length }); 15872 return; 15873 } 15874 else if (mount.overlay) { 15875 let size = result.length; 15876 explore(mount.tree, mount.overlay[0].from + from); 15877 if (result.length > size) 15878 return; 15879 } 15880 } 15881 for (let i = 0; i < tree.children.length; i++) { 15882 let ch = tree.children[i]; 15883 if (ch instanceof Tree) 15884 explore(ch, tree.positions[i] + from); 15885 } 15886 }; 15887 explore(syntaxTree(state), 0); 15888 return result; 15889 } 15890 /** 15891 Indicates whether this language allows nested languages. The 15892 default implementation returns true. 15893 */ 15894 get allowsNesting() { return true; } 15895} 15896/** 15897@internal 15898*/ 15899Language.setState = /*@__PURE__*/StateEffect.define(); 15900function topNodeAt(state, pos, side) { 15901 let topLang = state.facet(language), tree = syntaxTree(state).topNode; 15902 if (!topLang || topLang.allowsNesting) { 15903 for (let node = tree; node; node = node.enter(pos, side, IterMode.ExcludeBuffers)) 15904 if (node.type.isTop) 15905 tree = node; 15906 } 15907 return tree; 15908} 15909/** 15910A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer 15911[LR parsers](https://lezer.codemirror.net/docs/ref#lr.LRParser) 15912parsers. 15913*/ 15914class LRLanguage extends Language { 15915 constructor(data, parser, name) { 15916 super(data, parser, [], name); 15917 this.parser = parser; 15918 } 15919 /** 15920 Define a language from a parser. 15921 */ 15922 static define(spec) { 15923 let data = defineLanguageFacet(spec.languageData); 15924 return new LRLanguage(data, spec.parser.configure({ 15925 props: [languageDataProp.add(type => type.isTop ? data : undefined)] 15926 }), spec.name); 15927 } 15928 /** 15929 Create a new instance of this language with a reconfigured 15930 version of its parser and optionally a new name. 15931 */ 15932 configure(options, name) { 15933 return new LRLanguage(this.data, this.parser.configure(options), name || this.name); 15934 } 15935 get allowsNesting() { return this.parser.hasWrappers(); } 15936} 15937/** 15938Get the syntax tree for a state, which is the current (possibly 15939incomplete) parse tree of the active 15940[language](https://codemirror.net/6/docs/ref/#language.Language), or the empty tree if there is no 15941language available. 15942*/ 15943function syntaxTree(state) { 15944 let field = state.field(Language.state, false); 15945 return field ? field.tree : Tree.empty; 15946} 15947// Lezer-style Input object for a Text document. 15948class DocInput {
vendor: 19,960 bytes, lines 15948-16501
15948 15949 constructor(doc) { 15950 this.doc = doc; 15951 this.cursorPos = 0; 15952 this.string = ""; 15953 this.cursor = doc.iter(); 15954 } 15955 get length() { return this.doc.length; } 15956 syncTo(pos) { 15957 this.string = this.cursor.next(pos - this.cursorPos).value; 15958 this.cursorPos = pos + this.string.length; 15959 return this.cursorPos - this.string.length; 15960 } 15961 chunk(pos) { 15962 this.syncTo(pos); 15963 return this.string; 15964 } 15965 get lineChunks() { return true; } 15966 read(from, to) { 15967 let stringStart = this.cursorPos - this.string.length; 15968 if (from < stringStart || to >= this.cursorPos) 15969 return this.doc.sliceString(from, to); 15970 else 15971 return this.string.slice(from - stringStart, to - stringStart); 15972 } 15973} 15974let currentContext = null; 15975/** 15976A parse context provided to parsers working on the editor content. 15977*/ 15978class ParseContext { 15979 constructor(parser, 15980 /** 15981 The current editor state. 15982 */ 15983 state, 15984 /** 15985 Tree fragments that can be reused by incremental re-parses. 15986 */ 15987 fragments = [], 15988 /** 15989 @internal 15990 */ 15991 tree, 15992 /** 15993 @internal 15994 */ 15995 treeLen, 15996 /** 15997 The current editor viewport (or some overapproximation 15998 thereof). Intended to be used for opportunistically avoiding 15999 work (in which case 16000 [`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.ParseContext.skipUntilInView) 16001 should be called to make sure the parser is restarted when the 16002 skipped region becomes visible). 16003 */ 16004 viewport, 16005 /** 16006 @internal 16007 */ 16008 skipped, 16009 /** 16010 This is where skipping parsers can register a promise that, 16011 when resolved, will schedule a new parse. It is cleared when 16012 the parse worker picks up the promise. @internal 16013 */ 16014 scheduleOn) { 16015 this.parser = parser; 16016 this.state = state; 16017 this.fragments = fragments; 16018 this.tree = tree; 16019 this.treeLen = treeLen; 16020 this.viewport = viewport; 16021 this.skipped = skipped; 16022 this.scheduleOn = scheduleOn; 16023 this.parse = null; 16024 /** 16025 @internal 16026 */ 16027 this.tempSkipped = []; 16028 } 16029 /** 16030 @internal 16031 */ 16032 static create(parser, state, viewport) { 16033 return new ParseContext(parser, state, [], Tree.empty, 0, viewport, [], null); 16034 } 16035 startParse() { 16036 return this.parser.startParse(new DocInput(this.state.doc), this.fragments); 16037 } 16038 /** 16039 @internal 16040 */ 16041 work(until, upto) { 16042 if (upto != null && upto >= this.state.doc.length) 16043 upto = undefined; 16044 if (this.tree != Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) { 16045 this.takeTree(); 16046 return true; 16047 } 16048 return this.withContext(() => { 16049 var _a; 16050 if (typeof until == "number") { 16051 let endTime = Date.now() + until; 16052 until = () => Date.now() > endTime; 16053 } 16054 if (!this.parse) 16055 this.parse = this.startParse(); 16056 if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) && 16057 upto < this.state.doc.length) 16058 this.parse.stopAt(upto); 16059 for (;;) { 16060 let done = this.parse.advance(); 16061 if (done) { 16062 this.fragments = this.withoutTempSkipped(TreeFragment.addTree(done, this.fragments, this.parse.stoppedAt != null)); 16063 this.treeLen = (_a = this.parse.stoppedAt) !== null && _a !== void 0 ? _a : this.state.doc.length; 16064 this.tree = done; 16065 this.parse = null; 16066 if (this.treeLen < (upto !== null && upto !== void 0 ? upto : this.state.doc.length)) 16067 this.parse = this.startParse(); 16068 else 16069 return true; 16070 } 16071 if (until()) 16072 return false; 16073 } 16074 }); 16075 } 16076 /** 16077 @internal 16078 */ 16079 takeTree() { 16080 let pos, tree; 16081 if (this.parse && (pos = this.parse.parsedPos) >= this.treeLen) { 16082 if (this.parse.stoppedAt == null || this.parse.stoppedAt > pos) 16083 this.parse.stopAt(pos); 16084 this.withContext(() => { while (!(tree = this.parse.advance())) { } }); 16085 this.treeLen = pos; 16086 this.tree = tree; 16087 this.fragments = this.withoutTempSkipped(TreeFragment.addTree(this.tree, this.fragments, true)); 16088 this.parse = null; 16089 } 16090 } 16091 withContext(f) { 16092 let prev = currentContext; 16093 currentContext = this; 16094 try { 16095 return f(); 16096 } 16097 finally { 16098 currentContext = prev; 16099 } 16100 } 16101 withoutTempSkipped(fragments) { 16102 for (let r; r = this.tempSkipped.pop();) 16103 fragments = cutFragments(fragments, r.from, r.to); 16104 return fragments; 16105 } 16106 /** 16107 @internal 16108 */ 16109 changes(changes, newState) { 16110 let { fragments, tree, treeLen, viewport, skipped } = this; 16111 this.takeTree(); 16112 if (!changes.empty) { 16113 let ranges = []; 16114 changes.iterChangedRanges((fromA, toA, fromB, toB) => ranges.push({ fromA, toA, fromB, toB })); 16115 fragments = TreeFragment.applyChanges(fragments, ranges); 16116 tree = Tree.empty; 16117 treeLen = 0; 16118 viewport = { from: changes.mapPos(viewport.from, -1), to: changes.mapPos(viewport.to, 1) }; 16119 if (this.skipped.length) { 16120 skipped = []; 16121 for (let r of this.skipped) { 16122 let from = changes.mapPos(r.from, 1), to = changes.mapPos(r.to, -1); 16123 if (from < to) 16124 skipped.push({ from, to }); 16125 } 16126 } 16127 } 16128 return new ParseContext(this.parser, newState, fragments, tree, treeLen, viewport, skipped, this.scheduleOn); 16129 } 16130 /** 16131 @internal 16132 */ 16133 updateViewport(viewport) { 16134 if (this.viewport.from == viewport.from && this.viewport.to == viewport.to) 16135 return false; 16136 this.viewport = viewport; 16137 let startLen = this.skipped.length; 16138 for (let i = 0; i < this.skipped.length; i++) { 16139 let { from, to } = this.skipped[i]; 16140 if (from < viewport.to && to > viewport.from) { 16141 this.fragments = cutFragments(this.fragments, from, to); 16142 this.skipped.splice(i--, 1); 16143 } 16144 } 16145 if (this.skipped.length >= startLen) 16146 return false; 16147 this.reset(); 16148 return true; 16149 } 16150 /** 16151 @internal 16152 */ 16153 reset() { 16154 if (this.parse) { 16155 this.takeTree(); 16156 this.parse = null; 16157 } 16158 } 16159 /** 16160 Notify the parse scheduler that the given region was skipped 16161 because it wasn't in view, and the parse should be restarted 16162 when it comes into view. 16163 */ 16164 skipUntilInView(from, to) { 16165 this.skipped.push({ from, to }); 16166 } 16167 /** 16168 Returns a parser intended to be used as placeholder when 16169 asynchronously loading a nested parser. It'll skip its input and 16170 mark it as not-really-parsed, so that the next update will parse 16171 it again. 16172 16173 When `until` is given, a reparse will be scheduled when that 16174 promise resolves. 16175 */ 16176 static getSkippingParser(until) { 16177 return new class extends Parser { 16178 createParse(input, fragments, ranges) { 16179 let from = ranges[0].from, to = ranges[ranges.length - 1].to; 16180 let parser = { 16181 parsedPos: from, 16182 advance() { 16183 let cx = currentContext; 16184 if (cx) { 16185 for (let r of ranges) 16186 cx.tempSkipped.push(r); 16187 if (until) 16188 cx.scheduleOn = cx.scheduleOn ? Promise.all([cx.scheduleOn, until]) : until; 16189 } 16190 this.parsedPos = to; 16191 return new Tree(NodeType.none, [], [], to - from); 16192 }, 16193 stoppedAt: null, 16194 stopAt() { } 16195 }; 16196 return parser; 16197 } 16198 }; 16199 } 16200 /** 16201 @internal 16202 */ 16203 isDone(upto) { 16204 upto = Math.min(upto, this.state.doc.length); 16205 let frags = this.fragments; 16206 return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto; 16207 } 16208 /** 16209 Get the context for the current parse, or `null` if no editor 16210 parse is in progress. 16211 */ 16212 static get() { return currentContext; } 16213} 16214function cutFragments(fragments, from, to) { 16215 return TreeFragment.applyChanges(fragments, [{ fromA: from, toA: to, fromB: from, toB: to }]); 16216} 16217class LanguageState { 16218 constructor( 16219 // A mutable parse state that is used to preserve work done during 16220 // the lifetime of a state when moving to the next state. 16221 context) { 16222 this.context = context; 16223 this.tree = context.tree; 16224 } 16225 apply(tr) { 16226 if (!tr.docChanged && this.tree == this.context.tree) 16227 return this; 16228 let newCx = this.context.changes(tr.changes, tr.state); 16229 // If the previous parse wasn't done, go forward only up to its 16230 // end position or the end of the viewport, to avoid slowing down 16231 // state updates with parse work beyond the viewport. 16232 let upto = this.context.treeLen == tr.startState.doc.length ? undefined 16233 : Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to); 16234 if (!newCx.work(20 /* Work.Apply */, upto)) 16235 newCx.takeTree(); 16236 return new LanguageState(newCx); 16237 } 16238 static init(state) { 16239 let vpTo = Math.min(3000 /* Work.InitViewport */, state.doc.length); 16240 let parseState = ParseContext.create(state.facet(language).parser, state, { from: 0, to: vpTo }); 16241 if (!parseState.work(20 /* Work.Apply */, vpTo)) 16242 parseState.takeTree(); 16243 return new LanguageState(parseState); 16244 } 16245} 16246Language.state = /*@__PURE__*/StateField.define({ 16247 create: LanguageState.init, 16248 update(value, tr) { 16249 for (let e of tr.effects) 16250 if (e.is(Language.setState)) 16251 return e.value; 16252 if (tr.startState.facet(language) != tr.state.facet(language)) 16253 return LanguageState.init(tr.state); 16254 return value.apply(tr); 16255 } 16256}); 16257let requestIdle = (callback) => { 16258 let timeout = setTimeout(() => callback(), 500 /* Work.MaxPause */); 16259 return () => clearTimeout(timeout); 16260}; 16261if (typeof requestIdleCallback != "undefined") 16262 requestIdle = (callback) => { 16263 let idle = -1, timeout = setTimeout(() => { 16264 idle = requestIdleCallback(callback, { timeout: 500 /* Work.MaxPause */ - 100 /* Work.MinPause */ }); 16265 }, 100 /* Work.MinPause */); 16266 return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle); 16267 }; 16268const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending) 16269 ? () => navigator.scheduling.isInputPending() : null; 16270const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker { 16271 constructor(view) { 16272 this.view = view; 16273 this.working = null; 16274 this.workScheduled = 0; 16275 // End of the current time chunk 16276 this.chunkEnd = -1; 16277 // Milliseconds of budget left for this chunk 16278 this.chunkBudget = -1; 16279 this.work = this.work.bind(this); 16280 this.scheduleWork(); 16281 } 16282 update(update) { 16283 let cx = this.view.state.field(Language.state).context; 16284 if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen) 16285 this.scheduleWork(); 16286 if (update.docChanged) { 16287 if (this.view.hasFocus) 16288 this.chunkBudget += 50 /* Work.ChangeBonus */; 16289 this.scheduleWork(); 16290 } 16291 this.checkAsyncSchedule(cx); 16292 } 16293 scheduleWork() { 16294 if (this.working) 16295 return; 16296 let { state } = this.view, field = state.field(Language.state); 16297 if (field.tree != field.context.tree || !field.context.isDone(state.doc.length)) 16298 this.working = requestIdle(this.work); 16299 } 16300 work(deadline) { 16301 this.working = null; 16302 let now = Date.now(); 16303 if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk 16304 this.chunkEnd = now + 30000 /* Work.ChunkTime */; 16305 this.chunkBudget = 3000 /* Work.ChunkBudget */; 16306 } 16307 if (this.chunkBudget <= 0) 16308 return; // No more budget 16309 let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state); 16310 if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* Work.MaxParseAhead */)) 16311 return; 16312 let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Work.Slice */, deadline && !isInputPending ? Math.max(25 /* Work.MinSlice */, deadline.timeRemaining() - 5) : 1e9); 16313 let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000; 16314 let done = field.context.work(() => { 16315 return isInputPending && isInputPending() || Date.now() > endTime; 16316 }, vpTo + (viewportFirst ? 0 : 100000 /* Work.MaxParseAhead */)); 16317 this.chunkBudget -= Date.now() - now; 16318 if (done || this.chunkBudget <= 0) { 16319 field.context.takeTree(); 16320 this.view.dispatch({ effects: Language.setState.of(new LanguageState(field.context)) }); 16321 } 16322 if (this.chunkBudget > 0 && !(done && !viewportFirst)) 16323 this.scheduleWork(); 16324 this.checkAsyncSchedule(field.context); 16325 } 16326 checkAsyncSchedule(cx) { 16327 if (cx.scheduleOn) { 16328 this.workScheduled++; 16329 cx.scheduleOn 16330 .then(() => this.scheduleWork()) 16331 .catch(err => logException(this.view.state, err)) 16332 .then(() => this.workScheduled--); 16333 cx.scheduleOn = null; 16334 } 16335 } 16336 destroy() { 16337 if (this.working) 16338 this.working(); 16339 } 16340 isWorking() { 16341 return !!(this.working || this.workScheduled > 0); 16342 } 16343}, { 16344 eventHandlers: { focus() { this.scheduleWork(); } } 16345}); 16346/** 16347The facet used to associate a language with an editor state. Used 16348by `Language` object's `extension` property (so you don't need to 16349manually wrap your languages in this). Can be used to access the 16350current language on a state. 16351*/ 16352const language = /*@__PURE__*/Facet.define({ 16353 combine(languages) { return languages.length ? languages[0] : null; }, 16354 enables: language => [ 16355 Language.state, 16356 parseWorker, 16357 EditorView.contentAttributes.compute([language], state => { 16358 let lang = state.facet(language); 16359 return lang && lang.name ? { "data-language": lang.name } : {}; 16360 }) 16361 ] 16362}); 16363/** 16364This class bundles a [language](https://codemirror.net/6/docs/ref/#language.Language) with an 16365optional set of supporting extensions. Language packages are 16366encouraged to export a function that optionally takes a 16367configuration object and returns a `LanguageSupport` instance, as 16368the main way for client code to use the package. 16369*/ 16370class LanguageSupport { 16371 /** 16372 Create a language support object. 16373 */ 16374 constructor( 16375 /** 16376 The language object. 16377 */ 16378 language, 16379 /** 16380 An optional set of supporting extensions. When nesting a 16381 language in another language, the outer language is encouraged 16382 to include the supporting extensions for its inner languages 16383 in its own set of support extensions. 16384 */ 16385 support = []) { 16386 this.language = language; 16387 this.support = support; 16388 this.extension = [language, support]; 16389 } 16390} 16391/** 16392Language descriptions are used to store metadata about languages 16393and to dynamically load them. Their main role is finding the 16394appropriate language for a filename or dynamically loading nested 16395parsers. 16396*/ 16397class LanguageDescription { 16398 constructor( 16399 /** 16400 The name of this language. 16401 */ 16402 name, 16403 /** 16404 Alternative names for the mode (lowercased, includes `this.name`). 16405 */ 16406 alias, 16407 /** 16408 File extensions associated with this language. 16409 */ 16410 extensions, 16411 /** 16412 Optional filename pattern that should be associated with this 16413 language. 16414 */ 16415 filename, loadFunc, 16416 /** 16417 If the language has been loaded, this will hold its value. 16418 */ 16419 support = undefined) { 16420 this.name = name; 16421 this.alias = alias; 16422 this.extensions = extensions; 16423 this.filename = filename; 16424 this.loadFunc = loadFunc; 16425 this.support = support; 16426 this.loading = null; 16427 } 16428 /** 16429 Start loading the the language. Will return a promise that 16430 resolves to a [`LanguageSupport`](https://codemirror.net/6/docs/ref/#language.LanguageSupport) 16431 object when the language successfully loads. 16432 */ 16433 load() { 16434 return this.loading || (this.loading = this.loadFunc().then(support => this.support = support, err => { this.loading = null; throw err; })); 16435 } 16436 /** 16437 Create a language description. 16438 */ 16439 static of(spec) { 16440 let { load, support } = spec; 16441 if (!load) { 16442 if (!support) 16443 throw new RangeError("Must pass either 'load' or 'support' to LanguageDescription.of"); 16444 load = () => Promise.resolve(support); 16445 } 16446 return new LanguageDescription(spec.name, (spec.alias || []).concat(spec.name).map(s => s.toLowerCase()), spec.extensions || [], spec.filename, load, support); 16447 } 16448 /** 16449 Look for a language in the given array of descriptions that 16450 matches the filename. Will first match 16451 [`filename`](https://codemirror.net/6/docs/ref/#language.LanguageDescription.filename) patterns, 16452 and then [extensions](https://codemirror.net/6/docs/ref/#language.LanguageDescription.extensions), 16453 and return the first language that matches. 16454 */ 16455 static matchFilename(descs, filename) { 16456 for (let d of descs) 16457 if (d.filename && d.filename.test(filename)) 16458 return d; 16459 let ext = /\.([^.]+)$/.exec(filename); 16460 if (ext) 16461 for (let d of descs) 16462 if (d.extensions.indexOf(ext[1]) > -1) 16463 return d; 16464 return null; 16465 } 16466 /** 16467 Look for a language whose name or alias matches the the given 16468 name (case-insensitively). If `fuzzy` is true, and no direct 16469 matchs is found, this'll also search for a language whose name 16470 or alias occurs in the string (for names shorter than three 16471 characters, only when surrounded by non-word characters). 16472 */ 16473 static matchLanguageName(descs, name, fuzzy = true) { 16474 name = name.toLowerCase(); 16475 for (let d of descs) 16476 if (d.alias.some(a => a == name)) 16477 return d; 16478 if (fuzzy) 16479 for (let d of descs) 16480 for (let a of d.alias) { 16481 let found = name.indexOf(a); 16482 if (found > -1 && (a.length > 2 || !/\w/.test(name[found - 1]) && !/\w/.test(name[found + a.length]))) 16483 return d; 16484 } 16485 return null; 16486 } 16487} 16488 16489/** 16490Facet that defines a way to provide a function that computes the 16491appropriate indentation depth, as a column number (see 16492[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)), at the start of a given 16493line. A return value of `null` indicates no indentation can be 16494determined, and the line should inherit the indentation of the one 16495above it. A return value of `undefined` defers to the next indent 16496service. 16497*/ 16498const indentService = /*@__PURE__*/Facet.define(); 16499/** 16500Facet for overriding the unit by which indentation happens. Should 16501be a string consisting e
vendor: 8,075 bytes, lines 16501-16727
16501ither entirely of the same whitespace 16502character. When not set, this defaults to 2 spaces. 16503*/ 16504const indentUnit = /*@__PURE__*/Facet.define({ 16505 combine: values => { 16506 if (!values.length) 16507 return " "; 16508 let unit = values[0]; 16509 if (!unit || /\S/.test(unit) || Array.from(unit).some(e => e != unit[0])) 16510 throw new Error("Invalid indent unit: " + JSON.stringify(values[0])); 16511 return unit; 16512 } 16513}); 16514/** 16515Return the _column width_ of an indent unit in the state. 16516Determined by the [`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit) 16517facet, and [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) when that 16518contains tabs. 16519*/ 16520function getIndentUnit(state) { 16521 let unit = state.facet(indentUnit); 16522 return unit.charCodeAt(0) == 9 ? state.tabSize * unit.length : unit.length; 16523} 16524/** 16525Create an indentation string that covers columns 0 to `cols`. 16526Will use tabs for as much of the columns as possible when the 16527[`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit) facet contains 16528tabs. 16529*/ 16530function indentString(state, cols) { 16531 let result = "", ts = state.tabSize, ch = state.facet(indentUnit)[0]; 16532 if (ch == "\t") { 16533 while (cols >= ts) { 16534 result += "\t"; 16535 cols -= ts; 16536 } 16537 ch = " "; 16538 } 16539 for (let i = 0; i < cols; i++) 16540 result += ch; 16541 return result; 16542} 16543/** 16544Get the indentation, as a column number, at the given position. 16545Will first consult any [indent services](https://codemirror.net/6/docs/ref/#language.indentService) 16546that are registered, and if none of those return an indentation, 16547this will check the syntax tree for the [indent node 16548prop](https://codemirror.net/6/docs/ref/#language.indentNodeProp) and use that if found. Returns a 16549number when an indentation could be determined, and null 16550otherwise. 16551*/ 16552function getIndentation(context, pos) { 16553 if (context instanceof EditorState) 16554 context = new IndentContext(context); 16555 for (let service of context.state.facet(indentService)) { 16556 let result = service(context, pos); 16557 if (result !== undefined) 16558 return result; 16559 } 16560 let tree = syntaxTree(context.state); 16561 return tree ? syntaxIndentation(context, tree, pos) : null; 16562} 16563/** 16564Indentation contexts are used when calling [indentation 16565services](https://codemirror.net/6/docs/ref/#language.indentService). They provide helper utilities 16566useful in indentation logic, and can selectively override the 16567indentation reported for some lines. 16568*/ 16569class IndentContext { 16570 /** 16571 Create an indent context. 16572 */ 16573 constructor( 16574 /** 16575 The editor state. 16576 */ 16577 state, 16578 /** 16579 @internal 16580 */ 16581 options = {}) { 16582 this.state = state; 16583 this.options = options; 16584 this.unit = getIndentUnit(state); 16585 } 16586 /** 16587 Get a description of the line at the given position, taking 16588 [simulated line 16589 breaks](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak) 16590 into account. If there is such a break at `pos`, the `bias` 16591 argument determines whether the part of the line line before or 16592 after the break is used. 16593 */ 16594 lineAt(pos, bias = 1) { 16595 let line = this.state.doc.lineAt(pos); 16596 let { simulateBreak, simulateDoubleBreak } = this.options; 16597 if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) { 16598 if (simulateDoubleBreak && simulateBreak == pos) 16599 return { text: "", from: pos }; 16600 else if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos) 16601 return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak }; 16602 else 16603 return { text: line.text.slice(0, simulateBreak - line.from), from: line.from }; 16604 } 16605 return line; 16606 } 16607 /** 16608 Get the text directly after `pos`, either the entire line 16609 or the next 100 characters, whichever is shorter. 16610 */ 16611 textAfterPos(pos, bias = 1) { 16612 if (this.options.simulateDoubleBreak && pos == this.options.simulateBreak) 16613 return ""; 16614 let { text, from } = this.lineAt(pos, bias); 16615 return text.slice(pos - from, Math.min(text.length, pos + 100 - from)); 16616 } 16617 /** 16618 Find the column for the given position. 16619 */ 16620 column(pos, bias = 1) { 16621 let { text, from } = this.lineAt(pos, bias); 16622 let result = this.countColumn(text, pos - from); 16623 let override = this.options.overrideIndentation ? this.options.overrideIndentation(from) : -1; 16624 if (override > -1) 16625 result += override - this.countColumn(text, text.search(/\S|$/)); 16626 return result; 16627 } 16628 /** 16629 Find the column position (taking tabs into account) of the given 16630 position in the given string. 16631 */ 16632 countColumn(line, pos = line.length) { 16633 return countColumn(line, this.state.tabSize, pos); 16634 } 16635 /** 16636 Find the indentation column of the line at the given point. 16637 */ 16638 lineIndent(pos, bias = 1) { 16639 let { text, from } = this.lineAt(pos, bias); 16640 let override = this.options.overrideIndentation; 16641 if (override) { 16642 let overriden = override(from); 16643 if (overriden > -1) 16644 return overriden; 16645 } 16646 return this.countColumn(text, text.search(/\S|$/)); 16647 } 16648 /** 16649 Returns the [simulated line 16650 break](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak) 16651 for this context, if any. 16652 */ 16653 get simulatedBreak() { 16654 return this.options.simulateBreak || null; 16655 } 16656} 16657/** 16658A syntax tree node prop used to associate indentation strategies 16659with node types. Such a strategy is a function from an indentation 16660context to a column number (see also 16661[`indentString`](https://codemirror.net/6/docs/ref/#language.indentString)) or null, where null 16662indicates that no definitive indentation can be determined. 16663*/ 16664const indentNodeProp = /*@__PURE__*/new NodeProp(); 16665// Compute the indentation for a given position from the syntax tree. 16666function syntaxIndentation(cx, ast, pos) { 16667 return indentFrom(ast.resolveInner(pos).enterUnfinishedNodesBefore(pos), pos, cx); 16668} 16669function ignoreClosed(cx) { 16670 return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak; 16671} 16672function indentStrategy(tree) { 16673 let strategy = tree.type.prop(indentNodeProp); 16674 if (strategy) 16675 return strategy; 16676 let first = tree.firstChild, close; 16677 if (first && (close = first.type.prop(NodeProp.closedBy))) { 16678 let last = tree.lastChild, closed = last && close.indexOf(last.name) > -1; 16679 return cx => delimitedStrategy(cx, true, 1, undefined, closed && !ignoreClosed(cx) ? last.from : undefined); 16680 } 16681 return tree.parent == null ? topIndent : null; 16682} 16683function indentFrom(node, pos, base) { 16684 for (; node; node = node.parent) { 16685 let strategy = indentStrategy(node); 16686 if (strategy) 16687 return strategy(TreeIndentContext.create(base, pos, node)); 16688 } 16689 return null; 16690} 16691function topIndent() { return 0; } 16692/** 16693Objects of this type provide context information and helper 16694methods to indentation functions registered on syntax nodes. 16695*/ 16696class TreeIndentContext extends IndentContext { 16697 constructor(base, 16698 /** 16699 The position at which indentation is being computed. 16700 */ 16701 pos, 16702 /** 16703 The syntax tree node to which the indentation strategy 16704 applies. 16705 */ 16706 node) { 16707 super(base.state, base.options); 16708 this.base = base; 16709 this.pos = pos; 16710 this.node = node; 16711 } 16712 /** 16713 @internal 16714 */ 16715 static create(base, pos, node) { 16716 return new TreeIndentContext(base, pos, node); 16717 } 16718 /** 16719 Get the text directly after `this.pos`, either the entire line 16720 or the next 100 characters, whichever is shorter. 16721 */ 16722 get textAfter() { 16723 return this.textAfterPos(this.pos); 16724 } 16725 /** 16726 Get the indentation at the reference line for `this.node`, which 16727 is the line on which it starts, unless there is a node that is
16728 _not_ a parent of this node covering the start of that line. If 16729 so, the line at the start of that node is tried, again skipping 16730 on if it is covered by another such node. 16731 */ 16732 get baseIndent() { 16733 let line = this.state.doc.lineAt(this.node.from); 16734 // Skip line starts that are covered by a sibling (or cousin, etc) 16735 for (;;) { 16736 let atBreak = this.node.resolve(line.from); 16737 while (atBreak.parent && atBreak.parent.from == atBreak.from) 16738 atBreak = atBreak.parent; 16739 if (isParent(atBreak, this.node)) 16740 break; 16741 line = this.state.doc.lineAt(atBreak.from); 16742 } 16743 return this.lineIndent(line.from); 16744 } 16745 /** 16746 Continue looking for indentations in the node's parent nodes, 16747 and return the result of that. 16748 */ 16749 continue() { 16750 let parent = this.node.parent; 16751 return parent ? indentFrom(parent, this.pos, this.base) : 0; 16752 } 16753} 16754function isParent(parent, of) { 16755 for (let cur = of; cur; cur = cur.parent) 16756 if (parent == cur) 16757 return true; 16758 return false; 16759} 16760// Check whether a delimited node is aligned (meaning there are 16761// non-skipped nodes on the same line as the opening delimiter). And 16762// if so, return the opening token. 16763function bracketedAligned(context) { 16764 let tree = context.node; 16765 let openToken = tree.childAfter(tree.from), last = tree.lastChild; 16766 if (!openToken) 16767 return null; 16768 let sim = context.options.simulateBreak; 16769 let openLine = context.state.doc.lineAt(openToken.from); 16770 let lineEnd = sim == null || sim <= openLine.from ? openLine.to : Math.min(openLine.to, sim); 16771 for (let pos = openToken.to;;) { 16772 let next = tree.childAfter(pos); 16773 if (!next || next == last) 16774 return null; 16775 if (!next.type.isSkipped) 16776 return next.from < lineEnd ? openToken : null; 16777 pos = next.to; 16778 } 16779} 16780/** 16781An indentation strategy for delimited (usually bracketed) nodes. 16782Will, by default, indent one unit more than the parent's base 16783indent unless the line starts with a closing token. When `align` 16784is true and there are non-skipped nodes on the node's opening 16785line, the content of the node will be aligned with the end of the 16786opening node, like this: 16787 16788 foo(bar, 16789 baz) 16790*/ 16791function delimitedIndent({ closing, align = true, units = 1 }) { 16792 return (context) => delimitedStrategy(context, align, units, closing); 16793} 16794function delimitedStrategy(context, align, units, closing, closedAt) { 16795 let after = context.textAfter, space = after.match(/^\s*/)[0].length; 16796 let closed = closing && after.slice(space, space + closing.length) == closing || closedAt == context.pos + space; 16797 let aligned = align ? bracketedAligned(context) : null; 16798 if (aligned) 16799 return closed ? context.column(aligned.from) : context.column(aligned.to); 16800 return context.baseIndent + (closed ? 0 : context.unit * units); 16801} 16802/** 16803An indentation strategy that aligns a node's content to its base 16804indentation. 16805*/ 16806const flatIndent = (context) => context.baseIndent; 16807/** 16808Creates an indentation strategy that, by default, indents 16809continued lines one unit more than the node's base indentation. 16810You can provide `except` to prevent indentation of lines that 16811match a pattern (for example `/^else\b/` in `if`/`else`
vendor: 5,153 bytes, lines 16812-16939
16812constructs), and you can change the amount of units used with the 16813`units` option. 16814*/ 16815function continuedIndent({ except, units = 1 } = {}) { 16816 return (context) => { 16817 let matchExcept = except && except.test(context.textAfter); 16818 return context.baseIndent + (matchExcept ? 0 : units * context.unit); 16819 }; 16820} 16821const DontIndentBeyond = 200; 16822/** 16823Enables reindentation on input. When a language defines an 16824`indentOnInput` field in its [language 16825data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt), which must hold a regular 16826expression, the line at the cursor will be reindented whenever new 16827text is typed and the input from the start of the line up to the 16828cursor matches that regexp. 16829 16830To avoid unneccesary reindents, it is recommended to start the 16831regexp with `^` (usually followed by `\s*`), and end it with `$`. 16832For example, `/^\s*\}$/` will reindent when a closing brace is 16833added at the start of a line. 16834*/ 16835function indentOnInput() { 16836 return EditorState.transactionFilter.of(tr => { 16837 if (!tr.docChanged || !tr.isUserEvent("input.type") && !tr.isUserEvent("input.complete")) 16838 return tr; 16839 let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head); 16840 if (!rules.length) 16841 return tr; 16842 let doc = tr.newDoc, { head } = tr.newSelection.main, line = doc.lineAt(head); 16843 if (head > line.from + DontIndentBeyond) 16844 return tr; 16845 let lineStart = doc.sliceString(line.from, head); 16846 if (!rules.some(r => r.test(lineStart))) 16847 return tr; 16848 let { state } = tr, last = -1, changes = []; 16849 for (let { head } of state.selection.ranges) { 16850 let line = state.doc.lineAt(head); 16851 if (line.from == last) 16852 continue; 16853 last = line.from; 16854 let indent = getIndentation(state, line.from); 16855 if (indent == null) 16856 continue; 16857 let cur = /^\s*/.exec(line.text)[0]; 16858 let norm = indentString(state, indent); 16859 if (cur != norm) 16860 changes.push({ from: line.from, to: line.from + cur.length, insert: norm }); 16861 } 16862 return changes.length ? [tr, { changes, sequential: true }] : tr; 16863 }); 16864} 16865 16866/** 16867A facet that registers a code folding service. When called with 16868the extent of a line, such a function should return a foldable 16869range that starts on that line (but continues beyond it), if one 16870can be found. 16871*/ 16872const foldService = /*@__PURE__*/Facet.define(); 16873/** 16874This node prop is used to associate folding information with 16875syntax node types. Given a syntax node, it should check whether 16876that tree is foldable and return the range that can be collapsed 16877when it is. 16878*/ 16879const foldNodeProp = /*@__PURE__*/new NodeProp(); 16880/** 16881[Fold](https://codemirror.net/6/docs/ref/#language.foldNodeProp) function that folds everything but 16882the first and the last child of a syntax node. Useful for nodes 16883that start and end with delimiters. 16884*/ 16885function foldInside(node) { 16886 let first = node.firstChild, last = node.lastChild; 16887 return first && first.to < last.from ? { from: first.to, to: last.type.isError ? node.to : last.from } : null; 16888} 16889function syntaxFolding(state, start, end) { 16890 let tree = syntaxTree(state); 16891 if (tree.length < end) 16892 return null; 16893 let inner = tree.resolveInner(end, 1); 16894 let found = null; 16895 for (let cur = inner; cur; cur = cur.parent) { 16896 if (cur.to <= end || cur.from > end) 16897 continue; 16898 if (found && cur.from < start) 16899 break; 16900 let prop = cur.type.prop(foldNodeProp); 16901 if (prop && (cur.to < tree.length - 50 || tree.length == state.doc.length || !isUnfinished(cur))) { 16902 let value = prop(cur, state); 16903 if (value && value.from <= end && value.from >= start && value.to > end) 16904 found = value; 16905 } 16906 } 16907 return found; 16908} 16909function isUnfinished(node) { 16910 let ch = node.lastChild; 16911 return ch && ch.to == node.to && ch.type.isError; 16912} 16913/** 16914Check whether the given line is foldable. First asks any fold 16915services registered through 16916[`foldService`](https://codemirror.net/6/docs/ref/#language.foldService), and if none of them return 16917a result, tries to query the [fold node 16918prop](https://codemirror.net/6/docs/ref/#language.foldNodeProp) of syntax nodes that cover the end 16919of the line. 16920*/ 16921function foldable(state, lineStart, lineEnd) { 16922 for (let service of state.facet(foldService)) { 16923 let result = service(state, lineStart, lineEnd); 16924 if (result) 16925 return result; 16926 } 16927 return syntaxFolding(state, lineStart, lineEnd); 16928} 16929function mapRange(range, mapping) { 16930 let from = mapping.mapPos(range.from, 1), to = mapping.mapPos(range.to, -1); 16931 return from >= to ? undefined : { from, to }; 16932} 16933/** 16934State effect that can be attached to a transaction to fold the 16935given range. (You probably only need this in exceptional 16936circumstancesâusually you'll just want to let 16937[`foldCode`](https://codemirror.net/6/docs/ref/#language.foldCode) and the [fold 16938gutter](https://codemirror.net/6/docs/ref/#language.foldGutter) create the transactions.) 16939*/
16940const foldEffect = /*@__PURE__*/StateEffect.define({ map: mapRange }); 16941/** 16942State effect that unfolds the given range (if it was folded). 16943*/ 16944const unfoldEffect = /*@__PURE__*/StateEffect.define({ map: mapRange }); 16945function selectedLines(view) { 16946 let lines = []; 16947 for (let { head } of view.state.selection.ranges) { 16948 if (lines.some(l => l.from <= head && l.to >= head)) 16949 continue; 16950 lines.push(view.lineBlockAt(head)); 16951 } 16952 return lines; 16953} 16954/** 16955The state field that stores the folded ranges (as a [decoration 16956set](https://codemirror.net/6/docs/ref/#view.DecorationSet)). Can be passed to 16957[`EditorState.toJSON`](https://codemirror.net/6/docs/ref/#state.EditorState.toJSON) and 16958[`fromJSON`](https://codemirror.net/6/docs/ref/#state.EditorState^fromJSON) to serialize the fold 16959state. 16960*/ 16961const foldState = /*@__PURE__*/StateField.define({ 16962 create() { 16963 return Decoration.none; 16964 }, 16965 update(folded, tr) { 16966 folded = folded.map(tr.changes); 16967 for (let e of tr.effects) { 16968 if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to)) 16969 folded = folded.update({ add: [foldWidget.range(e.value.from, e.value.to)] }); 16970 else if (e.is(unfoldEffect)) 16971 folded = folded.update({ filter: (from, to) => e.value.from != from || e.value.to != to, 16972 filterFrom: e.value.from, filterTo: e.value.to }); 16973 } 16974 // Clear folded ranges that cover the selection head 16975 if (tr.selection) { 16976 let onSelection = false, { head } = tr.selection.main; 16977 folded.between(head, head, (a, b) => { if (a < head && b > head) 16978 onSelection = true; }); 16979 if (onSelection) 16980 folded = folded.update({ 16981 filterFrom: head, 16982 filterTo: head, 16983 filter: (a, b) => b <= head || a >= head 16984 }); 16985 } 16986 return folded; 16987 }, 16988 provide: f => EditorView.decorations.from(f), 16989 toJSON(folded, state) { 16990 let ranges = []; 16991 folded.between(0, state.doc.length, (from, to) => { ranges.push(from, to); }); 16992 return ranges; 16993 }, 16994 fromJSON(value) { 16995 if (!Array.isArray(value) || value.length % 2) 16996 throw new RangeError("Invalid JSON for fold state"); 16997 let ranges = []; 16998 for (let i = 0; i < value.length;) { 16999 let from = value[i++], to = value[i++]; 17000 if (typeof from != "number" || typeof to != "number") 17001 throw new RangeError("Invalid JSON for fold state"); 17002 ranges.push(foldWidget.range(from, to)); 17003 } 17004 return Decoration.set(ranges, true); 17005 } 17006}); 17007function findFold(state, from, to) { 17008 var _a; 17009 let found = null; 17010 (_a = state.field(foldState, false)) === null || _a === void 0 ? void 0 : _a.between(from, to, (from, to) => { 17011 if (!found || found.from > from) 17012 found = { from, to }; 17013 }); 17014 return found; 17015} 17016function foldExists(folded, from, to) { 17017 let found = false; 17018 folded.between(from, from, (a, b) => { if (a == from && b == to) 17019 found = true; }); 17020 return found; 17021} 17022function maybeEnable(state, other) { 17023 return state.field(foldState, false) ? other : other.concat(StateEffect.appendConfig.of(codeFolding())); 17024} 17025/** 17026Fold the lines that are selected, if possible. 17027*/ 17028const foldCode = view => { 17029 for (let line of selectedLines(view)) { 17030 let range = foldable(view.state, line.from, line.to); 17031 if (range) { 17032 view.dispatch({ effects: maybeEnable(view.state, [foldEffect.of(range), announceFold(view, range)]) }); 17033 return true; 17034 } 17035 } 17036 return false; 17037}; 17038/** 17039Unfold folded ranges on selected lines. 17040*/ 17041const unfoldCode = view => { 17042 if (!view.state.field(foldState, false)) 17043 return false; 17044 let effects = []; 17045 for (let line of selectedLines(view)) { 17046 let folded = findFold(view.state, line.from, line.to); 17047 if (folded) 17048 effects.push(unfoldEffect.of(folded), announceFold(view, folded, false)); 17049 } 17050 if (effects.length) 17051 view.dispatch({ effects }); 17052 return effects.length > 0; 17053}; 17054function announceFold(view, range, fold = true) { 17055 let lineFrom = view.state.doc.lineAt(range.from).number, lineTo = view.state.doc.lineAt(range.to).number; 17056 return EditorView.announce.of(`${view.state.phrase(fold ? "Folded lines" : "Unfolded lines")} ${lineFrom} ${view.state.phrase("to")} ${lineTo}.`); 17057} 17058/** 17059Fold all top-level foldable ranges. Note that, in most cases, 17060folding information will depend on the [syntax 17061tree](https://codemirror.net/6/docs/ref/#language.syntaxTree), and folding everything may not work 17062reliably when the document hasn't been fully parsed (either 17063because the editor state was only just initialized, or because the 17064document is so big that the parser decided not to parse it 17065entirely). 17066*/ 17067const foldAll = view => { 17068 let { state } = view, effects = []; 17069 for (let pos = 0; pos < state.doc.length;) { 17070 let line = view.lineBlockAt(pos), range = foldable(state, line.from, line.to); 17071 if (range) 17072 effects.push(foldEffect.of(range)); 17073 pos = (range ? view.lineBlockAt(range.to) : line).to + 1; 17074 } 17075 if (effects.length) 17076 view.dispatch({ effects: maybeEnable(view.state, effects) }); 17077 return !!effects.length; 17078}; 17079/** 17080Unfold all folded code. 17081*/ 17082const unfoldAll = view => { 17083 let field = view.state.field(foldState, false); 17084 if (!field || !field.size) 17085 return false;
17086 let effects = []; 17087 field.between(0, view.state.doc.length, (from, to) => { effects.push(unfoldEffect.of({ from, to })); }); 17088 view.dispatch({ effects }); 17089 return true; 17090}; 17091/** 17092Default fold-related key bindings. 17093 17094 - Ctrl-Shift-[ (Cmd-Alt-[ on macOS): [`foldCode`](https://codemirror.net/6/docs/ref/#language.foldCode). 17095 - Ctrl-Shift-] (Cmd-Alt-] on macOS): [`unfoldCode`](https://codemirror.net/6/docs/ref/#language.unfoldCode). 17096 - Ctrl-Alt-[: [`foldAll`](https://codemirror.net/6/docs/ref/#language.foldAll). 17097 - Ctrl-Alt-]: [`unfoldAll`](https://codemirror.net/6/docs/ref/#language.unfoldAll). 17098*/ 17099const foldKeymap = [ 17100 { key: "Ctrl-Shift-[", mac: "Cmd-Alt-[", run: foldCode }, 17101 { key: "Ctrl-Shift-]", mac: "Cmd-Alt-]", run: unfoldCode }, 17102 { key: "Ctrl-Alt-[", run: foldAll }, 17103 { key: "Ctrl-Alt-]", run: unfoldAll } 17104]; 17105const defaultConfig = { 17106 placeholderDOM: null, 17107 placeholderText: "â¦" 17108}; 17109const foldConfig = /*@__PURE__*/Facet.define({ 17110 combine(values) { return combineConfig(values, defaultConfig); } 17111}); 17112/** 17113Create an extension that configures code folding. 17114*/ 17115function codeFolding(config) { 17116 let result = [foldState, baseTheme$1$1]; 17117 if (config) 17118 result.push(foldConfig.of(config)); 17119 return result; 17120} 17121const foldWidget = /*@__PURE__*/Decoration.replace({ widget: /*@__PURE__*/new class extends WidgetType { 17122 toDOM(view) { 17123 let { state } = view, conf = state.facet(foldConfig); 17124 let onclick = (event) => { 17125 let line = view.lineBlockAt(view.posAtDOM(event.target)); 17126 let folded = findFold(view.state, line.from, line.to); 17127 if (folded) 17128 view.dispatch({ effects: unfoldEffect.of(folded) }); 17129 event.preventDefault(); 17130 }; 17131 if (conf.placeholderDOM) 17132 return conf.placeholderDOM(view, onclick); 17133 let element = document.createElement("span"); 17134 element.textContent = conf.placeholderText; 17135 element.setAttribute("aria-label", state.phrase("folded code")); 17136 element.title = state.phrase("unfold"); 17137 element.className = "cm-foldPlaceholder"; 17138 element.onclick = onclick; 17139 return element; 17140 } 17141 } }); 17142const foldGutterDefaults = { 17143 openText: "â", 17144 closedText: "âº", 17145 markerDOM: null, 17146 domEventHandlers: {}, 17147 foldingChanged: () => false 17148}; 17149class FoldMarker extends GutterMarker { 17150 constructor(config, open) { 17151 super(); 17152 this.config = config; 17153 this.open = open; 17154 } 17155 eq(other) { return this.config == other.config && this.open == other.open; } 17156 toDOM(view) { 17157 if (this.config.markerDOM) 17158 return this.config.markerDOM(this.open); 17159 let span = document.createElement("span"); 17160 span.textContent = this.open ? this.config.openText : this.config.closedText; 17161 span.title = view.state.phrase(this.open ? "Fold line" : "Unfold line"); 17162 return span; 17163 } 17164} 17165/** 17166Create an extension that registers a fold gutter, which shows a 17167fold status indicator before foldable lines (which can be clicked 17168to fold or unfold the line). 17169*/ 17170function foldGutter(config = {}) { 17171 let fullConfig = Object.assign(Object.assign({}, foldGutterDefaults), config); 17172 let canFold = new FoldMarker(fullConfig, true), canUnfold = new FoldMarker(fullConfig, false); 17173 let markers = ViewPlugin.fromClass(class { 17174 constructor(view) { 17175 this.from = view.viewport.from; 17176 this.markers = this.buildMarkers(view); 17177 } 17178 update(update) { 17179 if (update.docChanged || update.viewportChanged || 17180 update.startState.facet(language) != update.state.facet(language) || 17181 update.startState.field(foldState, false) != update.state.field(foldState, false) || 17182 syntaxTree(update.startState) != syntaxTree(update.state) || 17183 fullConfig.foldingChanged(update)) 17184 this.markers = this.buildMarkers(update.view); 17185 } 17186 buildMarkers(view) { 17187 let builder = new RangeSetBuilder(); 17188 for (let line of view.viewportLineBlocks) {
vendor: 27,585 bytes, lines 17189-17916
17189 let mark = findFold(view.state, line.from, line.to) ? canUnfold 17190 : foldable(view.state, line.from, line.to) ? canFold : null; 17191 if (mark) 17192 builder.add(line.from, line.from, mark); 17193 } 17194 return builder.finish(); 17195 } 17196 }); 17197 let { domEventHandlers } = fullConfig; 17198 return [ 17199 markers, 17200 gutter({ 17201 class: "cm-foldGutter", 17202 markers(view) { var _a; return ((_a = view.plugin(markers)) === null || _a === void 0 ? void 0 : _a.markers) || RangeSet.empty; }, 17203 initialSpacer() { 17204 return new FoldMarker(fullConfig, false); 17205 }, 17206 domEventHandlers: Object.assign(Object.assign({}, domEventHandlers), { click: (view, line, event) => { 17207 if (domEventHandlers.click && domEventHandlers.click(view, line, event)) 17208 return true; 17209 let folded = findFold(view.state, line.from, line.to); 17210 if (folded) { 17211 view.dispatch({ effects: unfoldEffect.of(folded) }); 17212 return true; 17213 } 17214 let range = foldable(view.state, line.from, line.to); 17215 if (range) { 17216 view.dispatch({ effects: foldEffect.of(range) }); 17217 return true; 17218 } 17219 return false; 17220 } }) 17221 }), 17222 codeFolding() 17223 ]; 17224} 17225const baseTheme$1$1 = /*@__PURE__*/EditorView.baseTheme({ 17226 ".cm-foldPlaceholder": { 17227 backgroundColor: "#eee", 17228 border: "1px solid #ddd", 17229 color: "#888", 17230 borderRadius: ".2em", 17231 margin: "0 1px", 17232 padding: "0 1px", 17233 cursor: "pointer" 17234 }, 17235 ".cm-foldGutter span": { 17236 padding: "0 1px", 17237 cursor: "pointer" 17238 } 17239}); 17240 17241/** 17242A highlight style associates CSS styles with higlighting 17243[tags](https://lezer.codemirror.net/docs/ref#highlight.Tag). 17244*/ 17245class HighlightStyle { 17246 constructor( 17247 /** 17248 The tag styles used to create this highlight style. 17249 */ 17250 specs, options) { 17251 this.specs = specs; 17252 let modSpec; 17253 function def(spec) { 17254 let cls = StyleModule.newName(); 17255 (modSpec || (modSpec = Object.create(null)))["." + cls] = spec; 17256 return cls; 17257 } 17258 const all = typeof options.all == "string" ? options.all : options.all ? def(options.all) : undefined; 17259 const scopeOpt = options.scope; 17260 this.scope = scopeOpt instanceof Language ? (type) => type.prop(languageDataProp) == scopeOpt.data 17261 : scopeOpt ? (type) => type == scopeOpt : undefined; 17262 this.style = tagHighlighter(specs.map(style => ({ 17263 tag: style.tag, 17264 class: style.class || def(Object.assign({}, style, { tag: null })) 17265 })), { 17266 all, 17267 }).style; 17268 this.module = modSpec ? new StyleModule(modSpec) : null; 17269 this.themeType = options.themeType; 17270 } 17271 /** 17272 Create a highlighter style that associates the given styles to 17273 the given tags. The specs must be objects that hold a style tag 17274 or array of tags in their `tag` property, and either a single 17275 `class` property providing a static CSS class (for highlighter 17276 that rely on external styling), or a 17277 [`style-mod`](https://github.com/marijnh/style-mod#documentation)-style 17278 set of CSS properties (which define the styling for those tags). 17279 17280 The CSS rules created for a highlighter will be emitted in the 17281 order of the spec's properties. That means that for elements that 17282 have multiple tags associated with them, styles defined further 17283 down in the list will have a higher CSS precedence than styles 17284 defined earlier. 17285 */ 17286 static define(specs, options) { 17287 return new HighlightStyle(specs, options || {}); 17288 } 17289} 17290const highlighterFacet = /*@__PURE__*/Facet.define(); 17291const fallbackHighlighter = /*@__PURE__*/Facet.define({ 17292 combine(values) { return values.length ? [values[0]] : null; } 17293}); 17294function getHighlighters(state) { 17295 let main = state.facet(highlighterFacet); 17296 return main.length ? main : state.facet(fallbackHighlighter); 17297} 17298/** 17299Wrap a highlighter in an editor extension that uses it to apply 17300syntax highlighting to the editor content. 17301 17302When multiple (non-fallback) styles are provided, the styling 17303applied is the union of the classes they emit. 17304*/ 17305function syntaxHighlighting(highlighter, options) { 17306 let ext = [treeHighlighter], themeType; 17307 if (highlighter instanceof HighlightStyle) { 17308 if (highlighter.module) 17309 ext.push(EditorView.styleModule.of(highlighter.module)); 17310 themeType = highlighter.themeType; 17311 } 17312 if (options === null || options === void 0 ? void 0 : options.fallback) 17313 ext.push(fallbackHighlighter.of(highlighter)); 17314 else if (themeType) 17315 ext.push(highlighterFacet.computeN([EditorView.darkTheme], state => { 17316 return state.facet(EditorView.darkTheme) == (themeType == "dark") ? [highlighter] : []; 17317 })); 17318 else 17319 ext.push(highlighterFacet.of(highlighter)); 17320 return ext; 17321} 17322class TreeHighlighter { 17323 constructor(view) { 17324 this.markCache = Object.create(null); 17325 this.tree = syntaxTree(view.state); 17326 this.decorations = this.buildDeco(view, getHighlighters(view.state)); 17327 } 17328 update(update) { 17329 let tree = syntaxTree(update.state), highlighters = getHighlighters(update.state); 17330 let styleChange = highlighters != getHighlighters(update.startState); 17331 if (tree.length < update.view.viewport.to && !styleChange && tree.type == this.tree.type) { 17332 this.decorations = this.decorations.map(update.changes); 17333 } 17334 else if (tree != this.tree || update.viewportChanged || styleChange) { 17335 this.tree = tree; 17336 this.decorations = this.buildDeco(update.view, highlighters); 17337 } 17338 } 17339 buildDeco(view, highlighters) { 17340 if (!highlighters || !this.tree.length) 17341 return Decoration.none; 17342 let builder = new RangeSetBuilder(); 17343 for (let { from, to } of view.visibleRanges) { 17344 highlightTree(this.tree, highlighters, (from, to, style) => { 17345 builder.add(from, to, this.markCache[style] || (this.markCache[style] = Decoration.mark({ class: style }))); 17346 }, from, to); 17347 } 17348 return builder.finish(); 17349 } 17350} 17351const treeHighlighter = /*@__PURE__*/Prec.high(/*@__PURE__*/ViewPlugin.fromClass(TreeHighlighter, { 17352 decorations: v => v.decorations 17353})); 17354/** 17355A default highlight style (works well with light themes). 17356*/ 17357const defaultHighlightStyle = /*@__PURE__*/HighlightStyle.define([ 17358 { tag: tags.meta, 17359 color: "#404740" }, 17360 { tag: tags.link, 17361 textDecoration: "underline" }, 17362 { tag: tags.heading, 17363 textDecoration: "underline", 17364 fontWeight: "bold" }, 17365 { tag: tags.emphasis, 17366 fontStyle: "italic" }, 17367 { tag: tags.strong, 17368 fontWeight: "bold" }, 17369 { tag: tags.strikethrough, 17370 textDecoration: "line-through" }, 17371 { tag: tags.keyword, 17372 color: "#708" }, 17373 { tag: [tags.atom, tags.bool, tags.url, tags.contentSeparator, tags.labelName], 17374 color: "#219" }, 17375 { tag: [tags.literal, tags.inserted], 17376 color: "#164" }, 17377 { tag: [tags.string, tags.deleted], 17378 color: "#a11" }, 17379 { tag: [tags.regexp, tags.escape, /*@__PURE__*/tags.special(tags.string)], 17380 color: "#e40" }, 17381 { tag: /*@__PURE__*/tags.definition(tags.variableName), 17382 color: "#00f" }, 17383 { tag: /*@__PURE__*/tags.local(tags.variableName), 17384 color: "#30a" }, 17385 { tag: [tags.typeName, tags.namespace], 17386 color: "#085" }, 17387 { tag: tags.className, 17388 color: "#167" }, 17389 { tag: [/*@__PURE__*/tags.special(tags.variableName), tags.macroName], 17390 color: "#256" }, 17391 { tag: /*@__PURE__*/tags.definition(tags.propertyName), 17392 color: "#00c" }, 17393 { tag: tags.comment, 17394 color: "#940" }, 17395 { tag: tags.invalid, 17396 color: "#f00" } 17397]); 17398const DefaultScanDist = 10000, DefaultBrackets = "()[]{}"; 17399/** 17400When larger syntax nodes, such as HTML tags, are marked as 17401opening/closing, it can be a bit messy to treat the whole node as 17402a matchable bracket. This node prop allows you to define, for such 17403a node, a âhandleââthe part of the node that is highlighted, and 17404that the cursor must be on to activate highlighting in the first 17405place. 17406*/ 17407const bracketMatchingHandle = /*@__PURE__*/new NodeProp(); 17408function matchingNodes(node, dir, brackets) { 17409 let byProp = node.prop(dir < 0 ? NodeProp.openedBy : NodeProp.closedBy); 17410 if (byProp) 17411 return byProp; 17412 if (node.name.length == 1) { 17413 let index = brackets.indexOf(node.name); 17414 if (index > -1 && index % 2 == (dir < 0 ? 1 : 0)) 17415 return [brackets[index + dir]]; 17416 } 17417 return null; 17418} 17419function findHandle(node) { 17420 let hasHandle = node.type.prop(bracketMatchingHandle); 17421 return hasHandle ? hasHandle(node.node) : node; 17422} 17423/** 17424Find the matching bracket for the token at `pos`, scanning 17425direction `dir`. Only the `brackets` and `maxScanDistance` 17426properties are used from `config`, if given. Returns null if no 17427bracket was found at `pos`, or a match result otherwise. 17428*/ 17429function matchBrackets(state, pos, dir, config = {}) { 17430 let maxScanDistance = config.maxScanDistance || DefaultScanDist, brackets = config.brackets || DefaultBrackets; 17431 let tree = syntaxTree(state), node = tree.resolveInner(pos, dir); 17432 for (let cur = node; cur; cur = cur.parent) { 17433 let matches = matchingNodes(cur.type, dir, brackets); 17434 if (matches && cur.from < cur.to) { 17435 let handle = findHandle(cur); 17436 if (handle && (dir > 0 ? pos >= handle.from && pos < handle.to : pos > handle.from && pos <= handle.to)) 17437 return matchMarkedBrackets(state, pos, dir, cur, handle, matches, brackets); 17438 } 17439 } 17440 return matchPlainBrackets(state, pos, dir, tree, node.type, maxScanDistance, brackets); 17441} 17442function matchMarkedBrackets(_state, _pos, dir, token, handle, matching, brackets) { 17443 let parent = token.parent, firstToken = { from: handle.from, to: handle.to }; 17444 let depth = 0, cursor = parent === null || parent === void 0 ? void 0 : parent.cursor(); 17445 if (cursor && (dir < 0 ? cursor.childBefore(token.from) : cursor.childAfter(token.to))) 17446 do { 17447 if (dir < 0 ? cursor.to <= token.from : cursor.from >= token.to) { 17448 if (depth == 0 && matching.indexOf(cursor.type.name) > -1 && cursor.from < cursor.to) { 17449 let endHandle = findHandle(cursor); 17450 return { start: firstToken, end: endHandle ? { from: endHandle.from, to: endHandle.to } : undefined, matched: true }; 17451 } 17452 else if (matchingNodes(cursor.type, dir, brackets)) { 17453 depth++; 17454 } 17455 else if (matchingNodes(cursor.type, -dir, brackets)) { 17456 if (depth == 0) { 17457 let endHandle = findHandle(cursor); 17458 return { 17459 start: firstToken, 17460 end: endHandle && endHandle.from < endHandle.to ? { from: endHandle.from, to: endHandle.to } : undefined, 17461 matched: false 17462 }; 17463 } 17464 depth--; 17465 } 17466 } 17467 } while (dir < 0 ? cursor.prevSibling() : cursor.nextSibling()); 17468 return { start: firstToken, matched: false }; 17469} 17470function matchPlainBrackets(state, pos, dir, tree, tokenType, maxScanDistance, brackets) { 17471 let startCh = dir < 0 ? state.sliceDoc(pos - 1, pos) : state.sliceDoc(pos, pos + 1); 17472 let bracket = brackets.indexOf(startCh); 17473 if (bracket < 0 || (bracket % 2 == 0) != (dir > 0)) 17474 return null; 17475 let startToken = { from: dir < 0 ? pos - 1 : pos, to: dir > 0 ? pos + 1 : pos }; 17476 let iter = state.doc.iterRange(pos, dir > 0 ? state.doc.length : 0), depth = 0; 17477 for (let distance = 0; !(iter.next()).done && distance <= maxScanDistance;) { 17478 let text = iter.value; 17479 if (dir < 0) 17480 distance += text.length; 17481 let basePos = pos + distance * dir; 17482 for (let pos = dir > 0 ? 0 : text.length - 1, end = dir > 0 ? text.length : -1; pos != end; pos += dir) { 17483 let found = brackets.indexOf(text[pos]); 17484 if (found < 0 || tree.resolveInner(basePos + pos, 1).type != tokenType) 17485 continue; 17486 if ((found % 2 == 0) == (dir > 0)) { 17487 depth++; 17488 } 17489 else if (depth == 1) { // Closing 17490 return { start: startToken, end: { from: basePos + pos, to: basePos + pos + 1 }, matched: (found >> 1) == (bracket >> 1) }; 17491 } 17492 else { 17493 depth--; 17494 } 17495 } 17496 if (dir > 0) 17497 distance += text.length; 17498 } 17499 return iter.done ? { start: startToken, matched: false } : null; 17500} 17501 17502// Counts the column offset in a string, taking tabs into account. 17503// Used mostly to find indentation. 17504function countCol(string, end, tabSize, startIndex = 0, startValue = 0) { 17505 if (end == null) { 17506 end = string.search(/[^\s\u00a0]/); 17507 if (end == -1) 17508 end = string.length; 17509 } 17510 let n = startValue; 17511 for (let i = startIndex; i < end; i++) { 17512 if (string.charCodeAt(i) == 9) 17513 n += tabSize - (n % tabSize); 17514 else 17515 n++; 17516 } 17517 return n; 17518} 17519/** 17520Encapsulates a single line of input. Given to stream syntax code, 17521which uses it to tokenize the content. 17522*/ 17523class StringStream { 17524 /** 17525 Create a stream. 17526 */ 17527 constructor( 17528 /** 17529 The line. 17530 */ 17531 string, tabSize, 17532 /** 17533 The current indent unit size. 17534 */ 17535 indentUnit, overrideIndent) { 17536 this.string = string; 17537 this.tabSize = tabSize; 17538 this.indentUnit = indentUnit; 17539 this.overrideIndent = overrideIndent; 17540 /** 17541 The current position on the line. 17542 */ 17543 this.pos = 0; 17544 /** 17545 The start position of the current token. 17546 */ 17547 this.start = 0; 17548 this.lastColumnPos = 0; 17549 this.lastColumnValue = 0; 17550 } 17551 /** 17552 True if we are at the end of the line. 17553 */ 17554 eol() { return this.pos >= this.string.length; } 17555 /** 17556 True if we are at the start of the line. 17557 */ 17558 sol() { return this.pos == 0; } 17559 /** 17560 Get the next code unit after the current position, or undefined 17561 if we're at the end of the line. 17562 */ 17563 peek() { return this.string.charAt(this.pos) || undefined; } 17564 /** 17565 Read the next code unit and advance `this.pos`. 17566 */ 17567 next() { 17568 if (this.pos < this.string.length) 17569 return this.string.charAt(this.pos++); 17570 } 17571 /** 17572 Match the next character against the given string, regular 17573 expression, or predicate. Consume and return it if it matches. 17574 */ 17575 eat(match) { 17576 let ch = this.string.charAt(this.pos); 17577 let ok; 17578 if (typeof match == "string") 17579 ok = ch == match; 17580 else 17581 ok = ch && (match instanceof RegExp ? match.test(ch) : match(ch)); 17582 if (ok) { 17583 ++this.pos; 17584 return ch; 17585 } 17586 } 17587 /** 17588 Continue matching characters that match the given string, 17589 regular expression, or predicate function. Return true if any 17590 characters were consumed. 17591 */ 17592 eatWhile(match) { 17593 let start = this.pos; 17594 while (this.eat(match)) { } 17595 return this.pos > start; 17596 } 17597 /** 17598 Consume whitespace ahead of `this.pos`. Return true if any was 17599 found. 17600 */ 17601 eatSpace() { 17602 let start = this.pos; 17603 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) 17604 ++this.pos; 17605 return this.pos > start; 17606 } 17607 /** 17608 Move to the end of the line. 17609 */ 17610 skipToEnd() { this.pos = this.string.length; } 17611 /** 17612 Move to directly before the given character, if found on the 17613 current line. 17614 */ 17615 skipTo(ch) { 17616 let found = this.string.indexOf(ch, this.pos); 17617 if (found > -1) { 17618 this.pos = found; 17619 return true; 17620 } 17621 } 17622 /** 17623 Move back `n` characters. 17624 */ 17625 backUp(n) { this.pos -= n; } 17626 /** 17627 Get the column position at `this.pos`. 17628 */ 17629 column() { 17630 if (this.lastColumnPos < this.start) { 17631 this.lastColumnValue = countCol(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); 17632 this.lastColumnPos = this.start; 17633 } 17634 return this.lastColumnValue; 17635 } 17636 /** 17637 Get the indentation column of the current line. 17638 */ 17639 indentation() { 17640 var _a; 17641 return (_a = this.overrideIndent) !== null && _a !== void 0 ? _a : countCol(this.string, null, this.tabSize); 17642 } 17643 /** 17644 Match the input against the given string or regular expression 17645 (which should start with a `^`). Return true or the regexp match 17646 if it matches. 17647 17648 Unless `consume` is set to `false`, this will move `this.pos` 17649 past the matched text. 17650 17651 When matching a string `caseInsensitive` can be set to true to 17652 make the match case-insensitive. 17653 */ 17654 match(pattern, consume, caseInsensitive) { 17655 if (typeof pattern == "string") { 17656 let cased = (str) => caseInsensitive ? str.toLowerCase() : str; 17657 let substr = this.string.substr(this.pos, pattern.length); 17658 if (cased(substr) == cased(pattern)) { 17659 if (consume !== false) 17660 this.pos += pattern.length; 17661 return true; 17662 } 17663 else 17664 return null; 17665 } 17666 else { 17667 let match = this.string.slice(this.pos).match(pattern); 17668 if (match && match.index > 0) 17669 return null; 17670 if (match && consume !== false) 17671 this.pos += match[0].length; 17672 return match; 17673 } 17674 } 17675 /** 17676 Get the current token. 17677 */ 17678 current() { return this.string.slice(this.start, this.pos); } 17679} 17680 17681function fullParser(spec) { 17682 return { 17683 name: spec.name || "", 17684 token: spec.token, 17685 blankLine: spec.blankLine || (() => { }), 17686 startState: spec.startState || (() => true), 17687 copyState: spec.copyState || defaultCopyState, 17688 indent: spec.indent || (() => null), 17689 languageData: spec.languageData || {}, 17690 tokenTable: spec.tokenTable || noTokens 17691 }; 17692} 17693function defaultCopyState(state) { 17694 if (typeof state != "object") 17695 return state; 17696 let newState = {}; 17697 for (let prop in state) { 17698 let val = state[prop]; 17699 newState[prop] = (val instanceof Array ? val.slice() : val); 17700 } 17701 return newState; 17702} 17703const IndentedFrom = /*@__PURE__*/new WeakMap(); 17704/** 17705A [language](https://codemirror.net/6/docs/ref/#language.Language) class based on a CodeMirror 177065-style [streaming parser](https://codemirror.net/6/docs/ref/#language.StreamParser). 17707*/ 17708class StreamLanguage extends Language { 17709 constructor(parser) { 17710 let data = defineLanguageFacet(parser.languageData); 17711 let p = fullParser(parser), self; 17712 let impl = new class extends Parser { 17713 createParse(input, fragments, ranges) { 17714 return new Parse(self, input, fragments, ranges); 17715 } 17716 }; 17717 super(data, impl, [indentService.of((cx, pos) => this.getIndent(cx, pos))], parser.name); 17718 this.topNode = docID(data); 17719 self = this; 17720 this.streamParser = p; 17721 this.stateAfter = new NodeProp({ perNode: true }); 17722 this.tokenTable = parser.tokenTable ? new TokenTable(p.tokenTable) : defaultTokenTable; 17723 } 17724 /** 17725 Define a stream language. 17726 */ 17727 static define(spec) { return new StreamLanguage(spec); } 17728 getIndent(cx, pos) { 17729 let tree = syntaxTree(cx.state), at = tree.resolve(pos); 17730 while (at && at.type != this.topNode) 17731 at = at.parent; 17732 if (!at) 17733 return null; 17734 let from = undefined; 17735 let { overrideIndentation } = cx.options; 17736 if (overrideIndentation) { 17737 from = IndentedFrom.get(cx.state); 17738 if (from != null && from < pos - 1e4) 17739 from = undefined; 17740 } 17741 let start = findState(this, tree, 0, at.from, from !== null && from !== void 0 ? from : pos), statePos, state; 17742 if (start) { 17743 state = start.state; 17744 statePos = start.pos + 1; 17745 } 17746 else { 17747 state = this.streamParser.startState(cx.unit); 17748 statePos = 0; 17749 } 17750 if (pos - statePos > 10000 /* C.MaxIndentScanDist */) 17751 return null; 17752 while (statePos < pos) { 17753 let line = cx.state.doc.lineAt(statePos), end = Math.min(pos, line.to); 17754 if (line.length) { 17755 let indentation = overrideIndentation ? overrideIndentation(line.from) : -1; 17756 let stream = new StringStream(line.text, cx.state.tabSize, cx.unit, indentation < 0 ? undefined : indentation); 17757 while (stream.pos < end - line.from) 17758 readToken(this.streamParser.token, stream, state); 17759 } 17760 else { 17761 this.streamParser.blankLine(state, cx.unit); 17762 } 17763 if (end == pos) 17764 break; 17765 statePos = line.to + 1; 17766 } 17767 let line = cx.lineAt(pos); 17768 if (overrideIndentation && from == null) 17769 IndentedFrom.set(cx.state, line.from); 17770 return this.streamParser.indent(state, /^\s*(.*)/.exec(line.text)[1], cx); 17771 } 17772 get allowsNesting() { return false; } 17773} 17774function findState(lang, tree, off, startPos, before) { 17775 let state = off >= startPos && off + tree.length <= before && tree.prop(lang.stateAfter); 17776 if (state) 17777 return { state: lang.streamParser.copyState(state), pos: off + tree.length }; 17778 for (let i = tree.children.length - 1; i >= 0; i--) { 17779 let child = tree.children[i], pos = off + tree.positions[i]; 17780 let found = child instanceof Tree && pos < before && findState(lang, child, pos, startPos, before); 17781 if (found) 17782 return found; 17783 } 17784 return null; 17785} 17786function cutTree(lang, tree, from, to, inside) { 17787 if (inside && from <= 0 && to >= tree.length) 17788 return tree; 17789 if (!inside && tree.type == lang.topNode) 17790 inside = true; 17791 for (let i = tree.children.length - 1; i >= 0; i--) { 17792 let pos = tree.positions[i], child = tree.children[i], inner; 17793 if (pos < to && child instanceof Tree) { 17794 if (!(inner = cutTree(lang, child, from - pos, to - pos, inside))) 17795 break; 17796 return !inside ? inner 17797 : new Tree(tree.type, tree.children.slice(0, i).concat(inner), tree.positions.slice(0, i + 1), pos + inner.length); 17798 } 17799 } 17800 return null; 17801} 17802function findStartInFragments(lang, fragments, startPos, editorState) { 17803 for (let f of fragments) { 17804 let from = f.from + (f.openStart ? 25 : 0), to = f.to - (f.openEnd ? 25 : 0); 17805 let found = from <= startPos && to > startPos && findState(lang, f.tree, 0 - f.offset, startPos, to), tree; 17806 if (found && (tree = cutTree(lang, f.tree, startPos + f.offset, found.pos + f.offset, false))) 17807 return { state: found.state, tree }; 17808 } 17809 return { state: lang.streamParser.startState(editorState ? getIndentUnit(editorState) : 4), tree: Tree.empty }; 17810} 17811class Parse { 17812 constructor(lang, input, fragments, ranges) { 17813 this.lang = lang; 17814 this.input = input; 17815 this.fragments = fragments; 17816 this.ranges = ranges; 17817 this.stoppedAt = null; 17818 this.chunks = []; 17819 this.chunkPos = []; 17820 this.chunk = []; 17821 this.chunkReused = undefined; 17822 this.rangeIndex = 0; 17823 this.to = ranges[ranges.length - 1].to; 17824 let context = ParseContext.get(), from = ranges[0].from; 17825 let { state, tree } = findStartInFragments(lang, fragments, from, context === null || context === void 0 ? void 0 : context.state); 17826 this.state = state; 17827 this.parsedPos = this.chunkStart = from + tree.length; 17828 for (let i = 0; i < tree.children.length; i++) { 17829 this.chunks.push(tree.children[i]); 17830 this.chunkPos.push(tree.positions[i]); 17831 } 17832 if (context && this.parsedPos < context.viewport.from - 100000 /* C.MaxDistanceBeforeViewport */) { 17833 this.state = this.lang.streamParser.startState(getIndentUnit(context.state)); 17834 context.skipUntilInView(this.parsedPos, context.viewport.from); 17835 this.parsedPos = context.viewport.from; 17836 } 17837 this.moveRangeIndex(); 17838 } 17839 advance() { 17840 let context = ParseContext.get(); 17841 let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt); 17842 let end = Math.min(parseEnd, this.chunkStart + 2048 /* C.ChunkSize */); 17843 if (context) 17844 end = Math.min(end, context.viewport.to); 17845 while (this.parsedPos < end) 17846 this.parseLine(context); 17847 if (this.chunkStart < this.parsedPos) 17848 this.finishChunk(); 17849 if (this.parsedPos >= parseEnd) 17850 return this.finish(); 17851 if (context && this.parsedPos >= context.viewport.to) { 17852 context.skipUntilInView(this.parsedPos, parseEnd); 17853 return this.finish(); 17854 } 17855 return null; 17856 } 17857 stopAt(pos) { 17858 this.stoppedAt = pos; 17859 } 17860 lineAfter(pos) { 17861 let chunk = this.input.chunk(pos); 17862 if (!this.input.lineChunks) { 17863 let eol = chunk.indexOf("\n"); 17864 if (eol > -1) 17865 chunk = chunk.slice(0, eol); 17866 } 17867 else if (chunk == "\n") { 17868 chunk = ""; 17869 } 17870 return pos + chunk.length <= this.to ? chunk : chunk.slice(0, this.to - pos); 17871 } 17872 nextLine() { 17873 let from = this.parsedPos, line = this.lineAfter(from), end = from + line.length; 17874 for (let index = this.rangeIndex;;) { 17875 let rangeEnd = this.ranges[index].to; 17876 if (rangeEnd >= end) 17877 break; 17878 line = line.slice(0, rangeEnd - (end - line.length)); 17879 index++; 17880 if (index == this.ranges.length) 17881 break; 17882 let rangeStart = this.ranges[index].from; 17883 let after = this.lineAfter(rangeStart); 17884 line += after; 17885 end = rangeStart + after.length; 17886 } 17887 return { line, end }; 17888 } 17889 skipGapsTo(pos, offset, side) { 17890 for (;;) { 17891 let end = this.ranges[this.rangeIndex].to, offPos = pos + offset; 17892 if (side > 0 ? end > offPos : end >= offPos) 17893 break; 17894 let start = this.ranges[++this.rangeIndex].from; 17895 offset += start - end; 17896 } 17897 return offset; 17898 } 17899 moveRangeIndex() { 17900 while (this.ranges[this.rangeIndex].to < this.parsedPos) 17901 this.rangeIndex++; 17902 } 17903 emitToken(id, from, to, size, offset) { 17904 if (this.ranges.length > 1) { 17905 offset = this.skipGapsTo(from, offset, 1); 17906 from += offset; 17907 let len0 = this.chunk.length; 17908 offset = this.skipGapsTo(to, offset, -1); 17909 to += offset; 17910 size += this.chunk.length - len0; 17911 } 17912 this.chunk.push(id, from, to, size); 17913 return offset; 17914 } 17915 parseLine(context) { 17916 let { line, end } = this.nextLine(), offset = 0, { streamParser }
17916 = this.lang; 17917 let stream = new StringStream(line, context ? context.state.tabSize : 4, context ? getIndentUnit(context.state) : 2); 17918 if (stream.eol()) { 17919 streamParser.blankLine(this.state, stream.indentUnit); 17920 } 17921 else { 17922 while (!stream.eol()) { 17923 let token = readToken(streamParser.token, stream, this.state); 17924 if (token) 17925 offset = this.emitToken(this.lang.tokenTable.resolve(token), this.parsedPos + stream.start, this.parsedPos + stream.pos, 4, offset); 17926 if (stream.start > 10000 /* C.MaxLineLength */) 17927 break; 17928 } 17929 } 17930 this.parsedPos = end; 17931 this.moveRangeIndex(); 17932 if (this.parsedPos < this.to) 17933 this.parsedPos++; 17934 } 17935 finishChunk() { 17936 let tree = Tree.build({ 17937 buffer: this.chunk, 17938 start: this.chunkStart, 17939 length: this.parsedPos - this.chunkStart, 17940 nodeSet, 17941 topID: 0, 17942 maxBufferLength: 2048 /* C.ChunkSize */, 17943 reused: this.chunkReused 17944 }); 17945 tree = new Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]); 17946 this.chunks.push(tree); 17947 this.chunkPos.push(this.chunkStart - this.ranges[0].from); 17948 this.chunk = []; 17949 this.chunkReused = undefined; 17950 this.chunkStart = this.parsedPos; 17951 } 17952 finish() { 17953 return new Tree(this.lang.topNode, this.chunks, this.chunkPos, this.parsedPos - this.ranges[0].from).balance(); 17954 } 17955} 17956function readToken(token, stream, state) { 17957 stream.start = stream.pos; 17958 for (let i = 0; i < 10; i++) { 17959 let result = token(stream, state); 17960 if (stream.pos > stream.start) 17961 return result; 17962 } 17963 throw new Error("Stream parser failed to advance stream."); 17964} 17965const noTokens = /*@__PURE__*/Object.create(null); 17966const typeArray = [NodeType.none]; 17967const nodeSet = /*@__PURE__*/new NodeSet(typeArray); 17968const warned = []; 17969const defaultTable = /*@__PURE__*/Object.create(null); 17970for (let [legacyName, name] of [ 17971 ["variable", "variableName"], 17972 ["variable-2", "variableName.special"], 17973 ["string-2", "string.special"], 17974 ["def", "variableName.definition"], 17975 ["tag", "tagName"], 17976 ["attribute", "attributeName"], 17977 ["type", "typeName"], 17978 ["builtin", "variableName.standard"], 17979 ["qualifier", "modifier"], 17980 ["error", "invalid"], 17981 ["header", "heading"], 17982 ["property", "propertyName"] 17983]) 17984 defaultTable[legacyName] = /*@__PURE__*/createTokenType(noTokens, name); 17985class TokenTable { 17986 constructor(extra) { 17987 this.extra = extra; 17988 this.table = Object.assign(Object.create(null), defaultTable); 17989 } 17990 resolve(tag) { 17991 return !tag ? 0 : this.table[tag] || (this.table[tag] = createTokenType(this.extra, tag)); 17992 } 17993} 17994const defaultTokenTable = /*@__PURE__*/new TokenTable(noTokens); 17995function warnForPart(part, msg) { 17996 if (warned.indexOf(part) > -1) 17997 return; 17998 warned.push(part); 17999 console.warn(msg); 18000} 18001function createTokenType(extra, tagStr) { 18002 let tag = null; 18003 for (let part of tagStr.split(".")) { 18004 let value = (extra[part] || tags[part]); 18005 if (!value) { 18006 warnForPart(part, `Unknown highlighting tag ${part}`); 18007 } 18008 else if (typeof value == "function") { 18009 if (!tag) 18010 warnForPart(part, `Modifier ${part} used at start of tag`); 18011 else 18012 tag = value(tag); 18013 } 18014 else { 18015 if (tag) 18016 warnForPart(part, `Tag ${part} used as modifier`); 18017 else 18018 tag = value; 18019 } 18020 } 18021 if (!tag) 18022 return 0; 18023 let name = tagStr.replace(/ /g, "_"), type = NodeType.define({ 18024 id: typeArray.length, 18025 name, 18026 props: [styleTags({ [name]: tag })] 18027 }); 18028 typeArray.push(type); 18029 return type.id; 18030} 18031function docID(data) { 18032 let type = NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)] }); 18033 typeArray.push(type); 18034 return type; 18035} 18036 18037/** 18038Comment or uncomment the current selection. Will use line comments 18039if available, otherwise falling back to block comments. 18040*/ 18041const toggleComment = target => {
vendor: 7,738 bytes, lines 18042-18213
18042 let config = getConfig(target.state); 18043 return config.line ? toggleLineComment(target) : config.block ? toggleBlockCommentByLine(target) : false; 18044}; 18045function command(f, option) { 18046 return ({ state, dispatch }) => { 18047 if (state.readOnly) 18048 return false; 18049 let tr = f(option, state); 18050 if (!tr) 18051 return false; 18052 dispatch(state.update(tr)); 18053 return true; 18054 }; 18055} 18056/** 18057Comment or uncomment the current selection using line comments. 18058The line comment syntax is taken from the 18059[`commentTokens`](https://codemirror.net/6/docs/ref/#commands.CommentTokens) [language 18060data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). 18061*/ 18062const toggleLineComment = /*@__PURE__*/command(changeLineComment, 0 /* CommentOption.Toggle */); 18063/** 18064Comment or uncomment the current selection using block comments. 18065The block comment syntax is taken from the 18066[`commentTokens`](https://codemirror.net/6/docs/ref/#commands.CommentTokens) [language 18067data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). 18068*/ 18069const toggleBlockComment = /*@__PURE__*/command(changeBlockComment, 0 /* CommentOption.Toggle */); 18070/** 18071Comment or uncomment the lines around the current selection using 18072block comments. 18073*/ 18074const toggleBlockCommentByLine = /*@__PURE__*/command((o, s) => changeBlockComment(o, s, selectedLineRanges(s)), 0 /* CommentOption.Toggle */); 18075function getConfig(state, pos = state.selection.main.head) { 18076 let data = state.languageDataAt("commentTokens", pos); 18077 return data.length ? data[0] : {}; 18078} 18079const SearchMargin = 50; 18080/** 18081Determines if the given range is block-commented in the given 18082state. 18083*/ 18084function findBlockComment(state, { open, close }, from, to) { 18085 let textBefore = state.sliceDoc(from - SearchMargin, from); 18086 let textAfter = state.sliceDoc(to, to + SearchMargin); 18087 let spaceBefore = /\s*$/.exec(textBefore)[0].length, spaceAfter = /^\s*/.exec(textAfter)[0].length; 18088 let beforeOff = textBefore.length - spaceBefore; 18089 if (textBefore.slice(beforeOff - open.length, beforeOff) == open && 18090 textAfter.slice(spaceAfter, spaceAfter + close.length) == close) { 18091 return { open: { pos: from - spaceBefore, margin: spaceBefore && 1 }, 18092 close: { pos: to + spaceAfter, margin: spaceAfter && 1 } }; 18093 } 18094 let startText, endText; 18095 if (to - from <= 2 * SearchMargin) { 18096 startText = endText = state.sliceDoc(from, to); 18097 } 18098 else { 18099 startText = state.sliceDoc(from, from + SearchMargin); 18100 endText = state.sliceDoc(to - SearchMargin, to); 18101 } 18102 let startSpace = /^\s*/.exec(startText)[0].length, endSpace = /\s*$/.exec(endText)[0].length; 18103 let endOff = endText.length - endSpace - close.length; 18104 if (startText.slice(startSpace, startSpace + open.length) == open && 18105 endText.slice(endOff, endOff + close.length) == close) { 18106 return { open: { pos: from + startSpace + open.length, 18107 margin: /\s/.test(startText.charAt(startSpace + open.length)) ? 1 : 0 }, 18108 close: { pos: to - endSpace - close.length, 18109 margin: /\s/.test(endText.charAt(endOff - 1)) ? 1 : 0 } }; 18110 } 18111 return null; 18112} 18113function selectedLineRanges(state) { 18114 let ranges = []; 18115 for (let r of state.selection.ranges) { 18116 let fromLine = state.doc.lineAt(r.from); 18117 let toLine = r.to <= fromLine.to ? fromLine : state.doc.lineAt(r.to); 18118 let last = ranges.length - 1; 18119 if (last >= 0 && ranges[last].to > fromLine.from) 18120 ranges[last].to = toLine.to; 18121 else 18122 ranges.push({ from: fromLine.from, to: toLine.to }); 18123 } 18124 return ranges; 18125} 18126// Performs toggle, comment and uncomment of block comments in 18127// languages that support them. 18128function changeBlockComment(option, state, ranges = state.selection.ranges) { 18129 let tokens = ranges.map(r => getConfig(state, r.from).block); 18130 if (!tokens.every(c => c)) 18131 return null; 18132 let comments = ranges.map((r, i) => findBlockComment(state, tokens[i], r.from, r.to)); 18133 if (option != 2 /* CommentOption.Uncomment */ && !comments.every(c => c)) { 18134 return { changes: state.changes(ranges.map((range, i) => { 18135 if (comments[i]) 18136 return []; 18137 return [{ from: range.from, insert: tokens[i].open + " " }, { from: range.to, insert: " " + tokens[i].close }]; 18138 })) }; 18139 } 18140 else if (option != 1 /* CommentOption.Comment */ && comments.some(c => c)) { 18141 let changes = []; 18142 for (let i = 0, comment; i < comments.length; i++) 18143 if (comment = comments[i]) { 18144 let token = tokens[i], { open, close } = comment; 18145 changes.push({ from: open.pos - token.open.length, to: open.pos + open.margin }, { from: close.pos - close.margin, to: close.pos + token.close.length }); 18146 } 18147 return { changes }; 18148 } 18149 return null; 18150} 18151// Performs toggle, comment and uncomment of line comments. 18152function changeLineComment(option, state, ranges = state.selection.ranges) { 18153 let lines = []; 18154 let prevLine = -1; 18155 for (let { from, to } of ranges) { 18156 let startI = lines.length, minIndent = 1e9; 18157 for (let pos = from; pos <= to;) { 18158 let line = state.doc.lineAt(pos); 18159 if (line.from > prevLine && (from == to || to > line.from)) { 18160 prevLine = line.from; 18161 let token = getConfig(state, pos).line; 18162 if (!token) 18163 continue; 18164 let indent = /^\s*/.exec(line.text)[0].length; 18165 let empty = indent == line.length; 18166 let comment = line.text.slice(indent, indent + token.length) == token ? indent : -1; 18167 if (indent < line.text.length && indent < minIndent) 18168 minIndent = indent; 18169 lines.push({ line, comment, token, indent, empty, single: false }); 18170 } 18171 pos = line.to + 1; 18172 } 18173 if (minIndent < 1e9) 18174 for (let i = startI; i < lines.length; i++) 18175 if (lines[i].indent < lines[i].line.text.length) 18176 lines[i].indent = minIndent; 18177 if (lines.length == startI + 1) 18178 lines[startI].single = true; 18179 } 18180 if (option != 2 /* CommentOption.Uncomment */ && lines.some(l => l.comment < 0 && (!l.empty || l.single))) { 18181 let changes = []; 18182 for (let { line, token, indent, empty, single } of lines) 18183 if (single || !empty) 18184 changes.push({ from: line.from + indent, insert: token + " " }); 18185 let changeSet = state.changes(changes); 18186 return { changes: changeSet, selection: state.selection.map(changeSet, 1) }; 18187 } 18188 else if (option != 1 /* CommentOption.Comment */ && lines.some(l => l.comment >= 0)) { 18189 let changes = []; 18190 for (let { line, comment, token } of lines) 18191 if (comment >= 0) { 18192 let from = line.from + comment, to = from + token.length; 18193 if (line.text[to - line.from] == " ") 18194 to++; 18195 changes.push({ from, to }); 18196 } 18197 return { changes }; 18198 } 18199 return null; 18200} 18201 18202const fromHistory = /*@__PURE__*/Annotation.define(); 18203/** 18204Transaction annotation that will prevent that transaction from 18205being combined with other transactions in the undo history. Given 18206`"before"`, it'll prevent merging with previous transactions. With 18207`"after"`, subsequent transactions won't be combined with this 18208one. With `"full"`, the transaction is isolated on both sides. 18209*/ 18210const isolateHistory = /*@__PURE__*/Annotation.define(); 18211/** 18212This facet provides a way to register functions that, given a 18213transaction, provide a set of effects that the history should
18214store when inverting the transaction. This can be used to 18215integrate some kinds of effects in the history, so that they can 18216be undone (and redone again). 18217*/ 18218const invertedEffects = /*@__PURE__*/Facet.define(); 18219const historyConfig = /*@__PURE__*/Facet.define({ 18220 combine(configs) { 18221 return combineConfig(configs, { 18222 minDepth: 100, 18223 newGroupDelay: 500 18224 }, { minDepth: Math.max, newGroupDelay: Math.min }); 18225 } 18226}); 18227function changeEnd(changes) { 18228 let end = 0; 18229 changes.iterChangedRanges((_, to) => end = to); 18230 return end; 18231} 18232const historyField_ = /*@__PURE__*/StateField.define({ 18233 create() { 18234 return HistoryState.empty; 18235 }, 18236 update(state, tr) { 18237 let config = tr.state.facet(historyConfig); 18238 let fromHist = tr.annotation(fromHistory); 18239 if (fromHist) { 18240 let selection = tr.docChanged ? EditorSelection.single(changeEnd(tr.changes)) : undefined; 18241 let item = HistEvent.fromTransaction(tr, selection), from = fromHist.side; 18242 let other = from == 0 /* BranchName.Done */ ? state.undone : state.done; 18243 if (item) 18244 other = updateBranch(other, other.length, config.minDepth, item); 18245 else 18246 other = addSelection(other, tr.startState.selection); 18247 return new HistoryState(from == 0 /* BranchName.Done */ ? fromHist.rest : other, from == 0 /* BranchName.Done */ ? other : fromHist.rest); 18248 } 18249 let isolate = tr.annotation(isolateHistory); 18250 if (isolate == "full" || isolate == "before") 18251 state = state.isolate(); 18252 if (tr.annotation(Transaction.addToHistory) === false) 18253 return !tr.changes.empty ? state.addMapping(tr.changes.desc) : state; 18254 let event = HistEvent.fromTransaction(tr); 18255 let time = tr.annotation(Transaction.time), userEvent = tr.annotation(Transaction.userEvent); 18256 if (event) 18257 state = state.addChanges(event, time, userEvent, config.newGroupDelay, config.minDepth); 18258 else if (tr.selection) 18259 state = state.addSelection(tr.startState.selection, time, userEvent, config.newGroupDelay); 18260 if (isolate == "full" || isolate == "after") 18261 state = state.isolate(); 18262 return state; 18263 }, 18264 toJSON(value) { 18265 return { done: value.done.map(e => e.toJSON()), undone: value.undone.map(e => e.toJSON()) }; 18266 }, 18267 fromJSON(json) { 18268 return new HistoryState(json.done.map(HistEvent.fromJSON), json.undone.map(HistEvent.fromJSON)); 18269 } 18270}); 18271/** 18272Create a history extension with the given configuration. 18273*/ 18274function history(config = {}) { 18275 return [ 18276 historyField_, 18277 historyConfig.of(config), 18278 EditorView.domEventHandlers({ 18279 beforeinput(e, view) { 18280 let command = e.inputType == "historyUndo" ? undo : e.inputType == "historyRedo" ? redo : null; 18281 if (!command) 18282 return false; 18283 e.preventDefault(); 18284 return command(view); 18285 } 18286 }) 18287 ]; 18288} 18289function cmd(side, selection) { 18290 return function ({ state, dispatch }) { 18291 if (!selection && state.readOnly) 18292 return false; 18293 let historyState = state.field(historyField_, false); 18294 if (!historyState) 18295 return false; 18296 let tr = historyState.pop(side, state, selection); 18297 if (!tr) 18298 return false; 18299 dispatch(tr); 18300 return true; 18301 }; 18302} 18303/** 18304Undo a single group of history events. Returns false if no group 18305was available. 18306*/ 18307const undo = /*@__PURE__*/cmd(0 /* BranchName.Done */, false); 18308/** 18309Redo a group of history events. Returns false if no group was 18310available. 18311*/ 18312const redo = /*@__PURE__*/cmd(1 /* BranchName.Undone */, false); 18313/** 18314Undo a change or selection change. 18315*/ 18316const undoSelection = /*@__PURE__*/cmd(0 /* BranchName.Done */, true); 18317/** 18318Redo a change or selection change. 18319*/ 18320const redoSelection = /*@__PURE__*/cmd(1 /* BranchName.Undone */, true); 18321// History events store groups of changes or effects that need to be 18322// undone/redone together. 18323class HistEvent { 18324 constructor( 18325 // The changes in this event. Normal events hold at least one 18326 // change or effect. But it may be necessary to store selection 18327 // events before the first change, in which case a special type of 18328 // instance is created which doesn't hold any changes, with 18329 // changes == startSelection == undefined 18330 changes, 18331 // The effects associated with this event 18332 effects, 18333 // Accumulated mapping (from addToHistory==false) that should be 18334 // applied to events below this one. 18335 mapped, 18336 // The selection before this event 18337 startSelection, 18338 // Stores selection changes after this event, to be used for 18339 // selection undo/redo. 18340 selectionsAfter) { 18341 this.changes = changes; 18342 this.effects = effects; 18343 this.mapped = mapped; 18344 this.startSelection = startSelection; 18345 this.selectionsAfter = selectionsAfter; 18346 } 18347 setSelAfter(after) { 18348 return new HistEvent(this.changes, this.effects, this.mapped, this.startSelection, after); 18349 } 18350 toJSON() { 18351 var _a, _b, _c; 18352 return { 18353 changes: (_a = this.changes) === null || _a === void 0 ? void 0 : _a.toJSON(), 18354 mapped: (_b = this.mapped) === null || _b === void 0 ? void 0 : _b.toJSON(), 18355 startSelection: (_c = this.startSelection) === null || _c === void 0 ? void 0 : _c.toJSON(), 18356 selectionsAfter: this.selectionsAfter.map(s => s.toJSON()) 18357 }; 18358 } 18359 static fromJSON(json) { 18360 return new HistEvent(json.changes && ChangeSet.fromJSON(json.changes), [], json.mapped && ChangeDesc.fromJSON(json.mapped), json.startSelection && EditorSelection.fromJSON(json.startSelection), json.selectionsAfter.map(EditorSelection.fromJSON)); 18361 } 18362 // This does not check `addToHistory` and such, it assumes the 18363 // transaction needs to be converted to an item. Returns null when 18364 // there are no changes or effects in the transaction. 18365 static fromTransaction(tr, selection) { 18366 let effects = none$1; 18367 for (let invert of tr.startState.facet(invertedEffects)) { 18368 let result = invert(tr); 18369 if (result.length)
vendor: 3,581 bytes, lines 18370-18455
18370 effects = effects.concat(result); 18371 } 18372 if (!effects.length && tr.changes.empty) 18373 return null; 18374 return new HistEvent(tr.changes.invert(tr.startState.doc), effects, undefined, selection || tr.startState.selection, none$1); 18375 } 18376 static selection(selections) { 18377 return new HistEvent(undefined, none$1, undefined, undefined, selections); 18378 } 18379} 18380function updateBranch(branch, to, maxLen, newEvent) { 18381 let start = to + 1 > maxLen + 20 ? to - maxLen - 1 : 0; 18382 let newBranch = branch.slice(start, to); 18383 newBranch.push(newEvent); 18384 return newBranch; 18385} 18386function isAdjacent(a, b) { 18387 let ranges = [], isAdjacent = false; 18388 a.iterChangedRanges((f, t) => ranges.push(f, t)); 18389 b.iterChangedRanges((_f, _t, f, t) => { 18390 for (let i = 0; i < ranges.length;) { 18391 let from = ranges[i++], to = ranges[i++]; 18392 if (t >= from && f <= to) 18393 isAdjacent = true; 18394 } 18395 }); 18396 return isAdjacent; 18397} 18398function eqSelectionShape(a, b) { 18399 return a.ranges.length == b.ranges.length && 18400 a.ranges.filter((r, i) => r.empty != b.ranges[i].empty).length === 0; 18401} 18402function conc(a, b) { 18403 return !a.length ? b : !b.length ? a : a.concat(b); 18404} 18405const none$1 = []; 18406const MaxSelectionsPerEvent = 200; 18407function addSelection(branch, selection) { 18408 if (!branch.length) { 18409 return [HistEvent.selection([selection])]; 18410 } 18411 else { 18412 let lastEvent = branch[branch.length - 1]; 18413 let sels = lastEvent.selectionsAfter.slice(Math.max(0, lastEvent.selectionsAfter.length - MaxSelectionsPerEvent)); 18414 if (sels.length && sels[sels.length - 1].eq(selection)) 18415 return branch; 18416 sels.push(selection); 18417 return updateBranch(branch, branch.length - 1, 1e9, lastEvent.setSelAfter(sels)); 18418 } 18419} 18420// Assumes the top item has one or more selectionAfter values 18421function popSelection(branch) { 18422 let last = branch[branch.length - 1]; 18423 let newBranch = branch.slice(); 18424 newBranch[branch.length - 1] = last.setSelAfter(last.selectionsAfter.slice(0, last.selectionsAfter.length - 1)); 18425 return newBranch; 18426} 18427// Add a mapping to the top event in the given branch. If this maps 18428// away all the changes and effects in that item, drop it and 18429// propagate the mapping to the next item. 18430function addMappingToBranch(branch, mapping) { 18431 if (!branch.length) 18432 return branch; 18433 let length = branch.length, selections = none$1; 18434 while (length) { 18435 let event = mapEvent(branch[length - 1], mapping, selections); 18436 if (event.changes && !event.changes.empty || event.effects.length) { // Event survived mapping 18437 let result = branch.slice(0, length); 18438 result[length - 1] = event; 18439 return result; 18440 } 18441 else { // Drop this event, since there's no changes or effects left 18442 mapping = event.mapped; 18443 length--; 18444 selections = event.selectionsAfter; 18445 } 18446 } 18447 return selections.length ? [HistEvent.selection(selections)] : none$1; 18448} 18449function mapEvent(event, mapping, extraSelections) { 18450 let selections = conc(event.selectionsAfter.length ? event.selectionsAfter.map(s => s.map(mapping)) : none$1, extraSelections); 18451 // Change-less events don't store mappings (they are always the last event in a branch) 18452 if (!event.changes) 18453 return HistEvent.selection(selections); 18454 let mappedChanges = event.changes.map(mapping), before = mapping.mapDesc(event.changes, true); 18455 let fullMapping = event.mapped ? event.mapped.composeDesc(before) : before;
18456 return new HistEvent(mappedChanges, StateEffect.mapEffects(event.effects, mapping), fullMapping, event.startSelection.map(before), selections); 18457} 18458const joinableUserEvent = /^(input\.type|delete)($|\.)/; 18459class HistoryState { 18460 constructor(done, undone, prevTime = 0, prevUserEvent = undefined) { 18461 this.done = done; 18462 this.undone = undone; 18463 this.prevTime = prevTime; 18464 this.prevUserEvent = prevUserEvent; 18465 } 18466 isolate() { 18467 return this.prevTime ? new HistoryState(this.done, this.undone) : this; 18468 } 18469 addChanges(event, time, userEvent, newGroupDelay, maxLen) { 18470 let done = this.done, lastEvent = done[done.length - 1]; 18471 if (lastEvent && lastEvent.changes && !lastEvent.changes.empty && event.changes && 18472 (!userEvent || joinableUserEvent.test(userEvent)) && 18473 ((!lastEvent.selectionsAfter.length && 18474 time - this.prevTime < newGroupDelay && 18475 isAdjacent(lastEvent.changes, event.changes)) || 18476 // For compose (but not compose.start) events, always join with previous event 18477 userEvent == "input.type.compose")) { 18478 done = updateBranch(done, done.length - 1, maxLen, new HistEvent(event.changes.compose(lastEvent.changes), conc(event.effects, lastEvent.effects), lastEvent.mapped, lastEvent.startSelection, none$1)); 18479 } 18480 else { 18481 done = updateBranch(done, done.length, maxLen, event); 18482 } 18483 return new HistoryState(done, none$1, time, userEvent); 18484 } 18485 addSelection(selection, time, userEvent, newGroupDelay) { 18486 let last = this.done.length ? this.done[this.done.length - 1].selectionsAfter : none$1; 18487 if (last.length > 0 && 18488 time - this.prevTime < newGroupDelay && 18489 userEvent == this.prevUserEvent && userEvent && /^select($|\.)/.test(userEvent) && 18490 eqSelectionShape(last[last.length - 1], selection)) 18491 return this; 18492 return new HistoryState(addSelection(this.done, selection), this.undone, time, userEvent); 18493 } 18494 addMapping(mapping) { 18495 return new HistoryState(addMappingToBranch(this.done, mapping), addMappingToBranch(this.undone, mapping), this.prevTime, this.prevUserEvent); 18496 } 18497 pop(side, state, selection) { 18498 let branch = side == 0 /* BranchName.Done */ ? this.done : this.undone; 18499 if (branch.length == 0) 18500 return null; 18501 let event = branch[branch.length - 1]; 18502 if (selection && event.selectionsAfter.length) { 18503 return state.update({ 18504 selection: event.selectionsAfter[event.selectionsAfter.length - 1], 18505 annotations: fromHistory.of({ side, rest: popSelection(branch) }), 18506 userEvent: side == 0 /* BranchName.Done */ ? "select.undo" : "select.redo", 18507 scrollIntoView: true 18508 }); 18509 } 18510 else if (!event.changes) { 18511 return null; 18512 } 18513 else { 18514 let rest = branch.length == 1 ? none$1 : branch.slice(0, branch.length - 1); 18515 if (event.mapped) 18516 rest = addMappingToBranch(rest, event.mapped); 18517 return state.update({ 18518 changes: event.changes, 18519 selection: event.startSelection, 18520 effects: event.effects, 18521 annotations: fromHistory.of({ side, rest }), 18522 filter: false, 18523 userEvent: side == 0 /* BranchName.Done */ ? "undo" : "redo", 18524 scrollIntoView: true 18525 }); 18526 } 18527 } 18528} 18529HistoryState.empty = /*@__PURE__*/new HistoryState(none$1, none$1); 18530/** 18531Default key bindings for the undo history. 18532 18533- Mod-z: [`undo`](https://codemirror.net/6/docs/ref/#commands.undo). 18534- Mod-y (Mod-Shift-z on macOS) + Ctrl-Shift-z on Linux: [`redo`](https://codemirror.net/6/docs/ref/#commands.redo). 18535- Mod-u: [`undoSelection`](https://codemirror.net/6/docs/ref/#commands.undoSelection). 18536- Alt-u (Mod-Shift-u on macOS): [`redoSelection`](https://codemirror.net/6/docs/ref/#commands.redoSelection). 18537*/ 18538const historyKeymap = [ 18539 { key: "Mod-z", run: undo, preventDefault: true },
vendor: 12,410 bytes, lines 18540-18854
18540 { key: "Mod-y", mac: "Mod-Shift-z", run: redo, preventDefault: true }, 18541 { linux: "Ctrl-Shift-z", run: redo, preventDefault: true }, 18542 { key: "Mod-u", run: undoSelection, preventDefault: true }, 18543 { key: "Alt-u", mac: "Mod-Shift-u", run: redoSelection, preventDefault: true } 18544]; 18545 18546function updateSel(sel, by) { 18547 return EditorSelection.create(sel.ranges.map(by), sel.mainIndex); 18548} 18549function setSel(state, selection) { 18550 return state.update({ selection, scrollIntoView: true, userEvent: "select" }); 18551} 18552function moveSel({ state, dispatch }, how) { 18553 let selection = updateSel(state.selection, how); 18554 if (selection.eq(state.selection)) 18555 return false; 18556 dispatch(setSel(state, selection)); 18557 return true; 18558} 18559function rangeEnd(range, forward) { 18560 return EditorSelection.cursor(forward ? range.to : range.from); 18561} 18562function cursorByChar(view, forward) { 18563 return moveSel(view, range => range.empty ? view.moveByChar(range, forward) : rangeEnd(range, forward)); 18564} 18565function ltrAtCursor(view) { 18566 return view.textDirectionAt(view.state.selection.main.head) == Direction.LTR; 18567} 18568/** 18569Move the selection one character to the left (which is backward in 18570left-to-right text, forward in right-to-left text). 18571*/ 18572const cursorCharLeft = view => cursorByChar(view, !ltrAtCursor(view)); 18573/** 18574Move the selection one character to the right. 18575*/ 18576const cursorCharRight = view => cursorByChar(view, ltrAtCursor(view)); 18577function cursorByGroup(view, forward) { 18578 return moveSel(view, range => range.empty ? view.moveByGroup(range, forward) : rangeEnd(range, forward)); 18579} 18580/** 18581Move the selection to the left across one group of word or 18582non-word (but also non-space) characters. 18583*/ 18584const cursorGroupLeft = view => cursorByGroup(view, !ltrAtCursor(view)); 18585/** 18586Move the selection one group to the right. 18587*/ 18588const cursorGroupRight = view => cursorByGroup(view, ltrAtCursor(view)); 18589function interestingNode(state, node, bracketProp) { 18590 if (node.type.prop(bracketProp)) 18591 return true; 18592 let len = node.to - node.from; 18593 return len && (len > 2 || /[^\s,.;:]/.test(state.sliceDoc(node.from, node.to))) || node.firstChild; 18594} 18595function moveBySyntax(state, start, forward) { 18596 let pos = syntaxTree(state).resolveInner(start.head); 18597 let bracketProp = forward ? NodeProp.closedBy : NodeProp.openedBy; 18598 // Scan forward through child nodes to see if there's an interesting 18599 // node ahead. 18600 for (let at = start.head;;) { 18601 let next = forward ? pos.childAfter(at) : pos.childBefore(at); 18602 if (!next) 18603 break; 18604 if (interestingNode(state, next, bracketProp)) 18605 pos = next; 18606 else 18607 at = forward ? next.to : next.from; 18608 } 18609 let bracket = pos.type.prop(bracketProp), match, newPos; 18610 if (bracket && (match = forward ? matchBrackets(state, pos.from, 1) : matchBrackets(state, pos.to, -1)) && match.matched) 18611 newPos = forward ? match.end.to : match.end.from; 18612 else 18613 newPos = forward ? pos.to : pos.from; 18614 return EditorSelection.cursor(newPos, forward ? -1 : 1); 18615} 18616/** 18617Move the cursor over the next syntactic element to the left. 18618*/ 18619const cursorSyntaxLeft = view => moveSel(view, range => moveBySyntax(view.state, range, !ltrAtCursor(view))); 18620/** 18621Move the cursor over the next syntactic element to the right. 18622*/ 18623const cursorSyntaxRight = view => moveSel(view, range => moveBySyntax(view.state, range, ltrAtCursor(view))); 18624function cursorByLine(view, forward) { 18625 return moveSel(view, range => { 18626 if (!range.empty) 18627 return rangeEnd(range, forward); 18628 let moved = view.moveVertically(range, forward); 18629 return moved.head != range.head ? moved : view.moveToLineBoundary(range, forward); 18630 }); 18631} 18632/** 18633Move the selection one line up. 18634*/ 18635const cursorLineUp = view => cursorByLine(view, false); 18636/** 18637Move the selection one line down. 18638*/ 18639const cursorLineDown = view => cursorByLine(view, true); 18640function pageHeight(view) { 18641 return Math.max(view.defaultLineHeight, Math.min(view.dom.clientHeight, innerHeight) - 5); 18642} 18643function cursorByPage(view, forward) { 18644 let { state } = view, selection = updateSel(state.selection, range => { 18645 return range.empty ? view.moveVertically(range, forward, pageHeight(view)) : rangeEnd(range, forward); 18646 }); 18647 if (selection.eq(state.selection)) 18648 return false; 18649 let startPos = view.coordsAtPos(state.selection.main.head); 18650 let scrollRect = view.scrollDOM.getBoundingClientRect(); 18651 let effect; 18652 if (startPos && startPos.top > scrollRect.top && startPos.bottom < scrollRect.bottom && 18653 startPos.top - scrollRect.top <= view.scrollDOM.scrollHeight - view.scrollDOM.scrollTop - view.scrollDOM.clientHeight) 18654 effect = EditorView.scrollIntoView(selection.main.head, { y: "start", yMargin: startPos.top - scrollRect.top }); 18655 view.dispatch(setSel(state, selection), { effects: effect }); 18656 return true; 18657} 18658/** 18659Move the selection one page up. 18660*/ 18661const cursorPageUp = view => cursorByPage(view, false); 18662/** 18663Move the selection one page down. 18664*/ 18665const cursorPageDown = view => cursorByPage(view, true); 18666function moveByLineBoundary(view, start, forward) { 18667 let line = view.lineBlockAt(start.head), moved = view.moveToLineBoundary(start, forward); 18668 if (moved.head == start.head && moved.head != (forward ? line.to : line.from)) 18669 moved = view.moveToLineBoundary(start, forward, false); 18670 if (!forward && moved.head == line.from && line.length) { 18671 let space = /^\s*/.exec(view.state.sliceDoc(line.from, Math.min(line.from + 100, line.to)))[0].length; 18672 if (space && start.head != line.from + space) 18673 moved = EditorSelection.cursor(line.from + space); 18674 } 18675 return moved; 18676} 18677/** 18678Move the selection to the next line wrap point, or to the end of 18679the line if there isn't one left on this line. 18680*/ 18681const cursorLineBoundaryForward = view => moveSel(view, range => moveByLineBoundary(view, range, true)); 18682/** 18683Move the selection to previous line wrap point, or failing that to 18684the start of the line. If the line is indented, and the cursor 18685isn't already at the end of the indentation, this will move to the 18686end of the indentation instead of the start of the line. 18687*/ 18688const cursorLineBoundaryBackward = view => moveSel(view, range => moveByLineBoundary(view, range, false)); 18689/** 18690Move the selection one line wrap point to the left. 18691*/ 18692const cursorLineBoundaryLeft = view => moveSel(view, range => moveByLineBoundary(view, range, !ltrAtCursor(view))); 18693/** 18694Move the selection one line wrap point to the right. 18695*/ 18696const cursorLineBoundaryRight = view => moveSel(view, range => moveByLineBoundary(view, range, ltrAtCursor(view))); 18697/** 18698Move the selection to the start of the line. 18699*/ 18700const cursorLineStart = view => moveSel(view, range => EditorSelection.cursor(view.lineBlockAt(range.head).from, 1)); 18701/** 18702Move the selection to the end of the line. 18703*/ 18704const cursorLineEnd = view => moveSel(view, range => EditorSelection.cursor(view.lineBlockAt(range.head).to, -1)); 18705function toMatchingBracket(state, dispatch, extend) { 18706 let found = false, selection = updateSel(state.selection, range => { 18707 let matching = matchBrackets(state, range.head, -1) 18708 || matchBrackets(state, range.head, 1) 18709 || (range.head > 0 && matchBrackets(state, range.head - 1, 1)) 18710 || (range.head < state.doc.length && matchBrackets(state, range.head + 1, -1)); 18711 if (!matching || !matching.end) 18712 return range; 18713 found = true; 18714 let head = matching.start.from == range.head ? matching.end.to : matching.end.from; 18715 return extend ? EditorSelection.range(range.anchor, head) : EditorSelection.cursor(head); 18716 }); 18717 if (!found) 18718 return false; 18719 dispatch(setSel(state, selection)); 18720 return true; 18721} 18722/** 18723Move the selection to the bracket matching the one it is currently 18724on, if any. 18725*/ 18726const cursorMatchingBracket = ({ state, dispatch }) => toMatchingBracket(state, dispatch, false); 18727function extendSel(view, how) { 18728 let selection = updateSel(view.state.selection, range => { 18729 let head = how(range); 18730 return EditorSelection.range(range.anchor, head.head, head.goalColumn); 18731 }); 18732 if (selection.eq(view.state.selection)) 18733 return false; 18734 view.dispatch(setSel(view.state, selection)); 18735 return true; 18736} 18737function selectByChar(view, forward) { 18738 return extendSel(view, range => view.moveByChar(range, forward)); 18739} 18740/** 18741Move the selection head one character to the left, while leaving 18742the anchor in place. 18743*/ 18744const selectCharLeft = view => selectByChar(view, !ltrAtCursor(view)); 18745/** 18746Move the selection head one character to the right. 18747*/ 18748const selectCharRight = view => selectByChar(view, ltrAtCursor(view)); 18749function selectByGroup(view, forward) { 18750 return extendSel(view, range => view.moveByGroup(range, forward)); 18751} 18752/** 18753Move the selection head one [group](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) to 18754the left. 18755*/ 18756const selectGroupLeft = view => selectByGroup(view, !ltrAtCursor(view)); 18757/** 18758Move the selection head one group to the right. 18759*/ 18760const selectGroupRight = view => selectByGroup(view, ltrAtCursor(view)); 18761/** 18762Move the selection head over the next syntactic element to the left. 18763*/ 18764const selectSyntaxLeft = view => extendSel(view, range => moveBySyntax(view.state, range, !ltrAtCursor(view))); 18765/** 18766Move the selection head over the next syntactic element to the right. 18767*/ 18768const selectSyntaxRight = view => extendSel(view, range => moveBySyntax(view.state, range, ltrAtCursor(view))); 18769function selectByLine(view, forward) { 18770 return extendSel(view, range => view.moveVertically(range, forward)); 18771} 18772/** 18773Move the selection head one line up. 18774*/ 18775const selectLineUp = view => selectByLine(view, false); 18776/** 18777Move the selection head one line down. 18778*/ 18779const selectLineDown = view => selectByLine(view, true); 18780function selectByPage(view, forward) { 18781 return extendSel(view, range => view.moveVertically(range, forward, pageHeight(view))); 18782} 18783/** 18784Move the selection head one page up. 18785*/ 18786const selectPageUp = view => selectByPage(view, false); 18787/** 18788Move the selection head one page down. 18789*/ 18790const selectPageDown = view => selectByPage(view, true); 18791/** 18792Move the selection head to the next line boundary. 18793*/ 18794const selectLineBoundaryForward = view => extendSel(view, range => moveByLineBoundary(view, range, true)); 18795/** 18796Move the selection head to the previous line boundary. 18797*/ 18798const selectLineBoundaryBackward = view => extendSel(view, range => moveByLineBoundary(view, range, false)); 18799/** 18800Move the selection head one line boundary to the left. 18801*/ 18802const selectLineBoundaryLeft = view => extendSel(view, range => moveByLineBoundary(view, range, !ltrAtCursor(view))); 18803/** 18804Move the selection head one line boundary to the right. 18805*/ 18806const selectLineBoundaryRight = view => extendSel(view, range => moveByLineBoundary(view, range, ltrAtCursor(view))); 18807/** 18808Move the selection head to the start of the line. 18809*/ 18810const selectLineStart = view => extendSel(view, range => EditorSelection.cursor(view.lineBlockAt(range.head).from)); 18811/** 18812Move the selection head to the end of the line. 18813*/ 18814const selectLineEnd = view => extendSel(view, range => EditorSelection.cursor(view.lineBlockAt(range.head).to)); 18815/** 18816Move the selection to the start of the document. 18817*/ 18818const cursorDocStart = ({ state, dispatch }) => { 18819 dispatch(setSel(state, { anchor: 0 })); 18820 return true; 18821}; 18822/** 18823Move the selection to the end of the document. 18824*/ 18825const cursorDocEnd = ({ state, dispatch }) => { 18826 dispatch(setSel(state, { anchor: state.doc.length })); 18827 return true; 18828}; 18829/** 18830Move the selection head to the start of the document. 18831*/ 18832const selectDocStart = ({ state, dispatch }) => { 18833 dispatch(setSel(state, { anchor: state.selection.main.anchor, head: 0 })); 18834 return true; 18835}; 18836/** 18837Move the selection head to the end of the document. 18838*/ 18839const selectDocEnd = ({ state, dispatch }) => { 18840 dispatch(setSel(state, { anchor: state.selection.main.anchor, head: state.doc.length })); 18841 return true; 18842}; 18843/** 18844Select the entire document. 18845*/ 18846const selectAll = ({ state, dispatch }) => { 18847 dispatch(state.update({ selection: { anchor: 0, head: state.doc.length }, userEvent: "select" })); 18848 return true; 18849}; 18850/** 18851Expand the selection to cover entire lines. 18852*/ 18853const selectLine = ({ state, dispatch }) => { 18854 let ranges = selectedLineBlocks(state).map(({ from, to }) => EditorSelection.range(from, Math.min(to + 1, state.doc.length)));
18855 dispatch(state.update({ selection: EditorSelection.create(ranges), userEvent: "select" })); 18856 return true; 18857}; 18858/** 18859Select the next syntactic construct that is larger than the 18860selection. Note that this will only work insofar as the language 18861[provider](https://codemirror.net/6/docs/ref/#language.language) you use builds up a full 18862syntax tree. 18863*/ 18864const selectParentSyntax = ({ state, dispatch }) => { 18865 let selection = updateSel(state.selection, range => { 18866 var _a; 18867 let context = syntaxTree(state).resolveInner(range.head, 1); 18868 while (!((context.from < range.from && context.to >= range.to) || 18869 (context.to > range.to && context.from <= range.from) || 18870 !((_a = context.parent) === null || _a === void 0 ? void 0 : _a.parent))) 18871 context = context.parent; 18872 return EditorSelection.range(context.to, context.from); 18873 }); 18874 dispatch(setSel(state, selection)); 18875 return true; 18876}; 18877/** 18878Simplify the current selection. When multiple ranges are selected, 18879reduce it to its main range. Otherwise, if the selection is 18880non-empty, convert it to a cursor selection. 18881*/ 18882const simplifySelection = ({ state, dispatch }) => {
18883 let cur = state.selection, selection = null; 18884 if (cur.ranges.length > 1) 18885 selection = EditorSelection.create([cur.main]); 18886 else if (!cur.main.empty) 18887 selection = EditorSelection.create([EditorSelection.cursor(cur.main.head)]); 18888 if (!selection) 18889 return false; 18890 dispatch(setSel(state, selection)); 18891 return true; 18892}; 18893function deleteBy(target, by) { 18894 if (target.state.readOnly) 18895 return false; 18896 let event = "delete.selection", { state } = target; 18897 let changes = state.changeByRange(range => { 18898 let { from, to } = range; 18899 if (from == to) { 18900 let towards = by(from); 18901 if (towards < from) { 18902 event = "delete.backward"; 18903 towards = skipAtomic(target, towards, false); 18904 } 18905 else if (towards > from) { 18906 event = "delete.forward"; 18907 towards = skipAtomic(target, towards, true); 18908 } 18909 from = Math.min(from, towards); 18910 to = Math.max(to, towards); 18911 } 18912 else { 18913 from = skipAtomic(target, from, false); 18914 to = skipAtomic(target, to, true); 18915 } 18916 return from == to ? { range } : { changes: { from, to }, range: EditorSelection.cursor(from) }; 18917 }); 18918 if (changes.changes.empty) 18919 return false; 18920 target.dispatch(state.update(changes, { 18921 scrollIntoView: true, 18922 userEvent: event, 18923 effects: event == "delete.selection" ? EditorView.announce.of(state.phrase("Selection deleted")) : undefined 18924 })); 18925 return true; 18926} 18927function skipAtomic(target, pos, forward) { 18928 if (target instanceof EditorView) 18929 for (let ranges of target.state.facet(EditorView.atomicRanges).map(f => f(target))) 18930 ranges.between(pos, pos, (from, to) => { 18931 if (from < pos && to > pos) 18932 pos = forward ? to : from; 18933 }); 18934 return pos; 18935} 18936const deleteByChar = (target, forward) => deleteBy(target, pos => { 18937 let { state } = target, line = state.doc.lineAt(pos), before, targetPos; 18938 if (!forward && pos > line.from && pos < line.from + 200 && 18939 !/[^ \t]/.test(before = line.text.slice(0, pos - line.from))) { 18940 if (before[before.length - 1] == "\t") 18941 return pos - 1; 18942 let col = countColumn(before, state.tabSize), drop = col % getIndentUnit(state) || getIndentUnit(state); 18943 for (let i = 0; i < drop && before[before.length - 1 - i] == " "; i++) 18944 pos--; 18945 targetPos = pos; 18946 } 18947 else { 18948 targetPos = findClusterBreak(line.text, pos - line.from, forward, forward) + line.from; 18949 if (targetPos == pos && line.number != (forward ? state.doc.lines : 1)) 18950 targetPos += forward ? 1 : -1; 18951 } 18952 return targetPos; 18953}); 18954/** 18955Delete the selection, or, for cursor selections, the character 18956before the cursor. 18957*/ 18958const deleteCharBackward = view => deleteByChar(view, false); 18959/** 18960Delete the selection or the character after the cursor. 18961*/ 18962const deleteCharForward = view => deleteByChar(view, true); 18963const deleteByGroup = (target, forward) => deleteBy(target, start => { 18964 let pos = start, { state } = target, line = state.doc.lineAt(pos); 18965 let categorize = state.charCategorizer(pos); 18966 for (let cat = null;;) { 18967 if (pos == (forward ? line.to : line.from)) { 18968 if (pos == start && line.number != (forward ? state.doc.lines : 1)) 18969 pos += forward ? 1 : -1; 18970 break; 18971 } 18972 let next = findClusterBreak(line.text, pos - line.from, forward) + line.from; 18973 let nextChar = line.text.slice(Math.min(pos, next) - line.from, Math.max(pos, next) - line.from); 18974 let nextCat = categorize(nextChar); 18975 if (cat != null && nextCat != cat) 18976 break; 18977 if (nextChar != " " || pos != start) 18978 cat = nextCat; 18979 pos = next; 18980 } 18981 return pos; 18982}); 18983/** 18984Delete the selection or backward until the end of the next 18985[group](https://codemirror.net/6/docs/ref/#view.EditorView.moveByGroup), only skipping groups of 18986whitespace when they consist of a single space. 18987*/ 18988const deleteGroupBackward = target => deleteByGroup(target, false); 18989/** 18990Delete the selection or forward until the end of the next group. 18991*/ 18992const deleteGroupForward = target => deleteByGroup(target, true); 18993/** 18994Delete the selection, or, if it is a cursor selection, delete to 18995the end of the line. If the cursor is directly at the end of the 18996line, delete the line break after it. 18997*/ 18998const deleteToLineEnd = view => deleteBy(view, pos => { 18999 let lineEnd = view.lineBlockAt(pos).to; 19000 return pos < lineEnd ? lineEnd : Math.min(view.state.doc.length, pos + 1); 19001}); 19002/** 19003Delete the selection, or, if it is a cursor selection, delete to 19004the start of the line. If the cursor is directly at the start of the 19005line, delete the line break before it. 19006*/ 19007const deleteToLineStart = view => deleteBy(view, pos => { 19008 let lineStart = view.lineBlockAt(pos).from; 19009 return pos > lineStart ? lineStart : Math.max(0, pos - 1); 19010}); 19011/** 19012Replace each selection range with a line break, leaving the cursor 19013on the line before the break. 19014*/ 19015const splitLine = ({ state, dispatch }) => { 19016 if (state.readOnly) 19017 return false;
vendor: 4,380 bytes, lines 19018-19127
19018 let changes = state.changeByRange(range => { 19019 return { changes: { from: range.from, to: range.to, insert: Text.of(["", ""]) }, 19020 range: EditorSelection.cursor(range.from) }; 19021 }); 19022 dispatch(state.update(changes, { scrollIntoView: true, userEvent: "input" })); 19023 return true; 19024}; 19025/** 19026Flip the characters before and after the cursor(s). 19027*/ 19028const transposeChars = ({ state, dispatch }) => { 19029 if (state.readOnly) 19030 return false; 19031 let changes = state.changeByRange(range => { 19032 if (!range.empty || range.from == 0 || range.from == state.doc.length) 19033 return { range }; 19034 let pos = range.from, line = state.doc.lineAt(pos); 19035 let from = pos == line.from ? pos - 1 : findClusterBreak(line.text, pos - line.from, false) + line.from; 19036 let to = pos == line.to ? pos + 1 : findClusterBreak(line.text, pos - line.from, true) + line.from; 19037 return { changes: { from, to, insert: state.doc.slice(pos, to).append(state.doc.slice(from, pos)) }, 19038 range: EditorSelection.cursor(to) }; 19039 }); 19040 if (changes.changes.empty) 19041 return false; 19042 dispatch(state.update(changes, { scrollIntoView: true, userEvent: "move.character" })); 19043 return true; 19044}; 19045function selectedLineBlocks(state) { 19046 let blocks = [], upto = -1; 19047 for (let range of state.selection.ranges) { 19048 let startLine = state.doc.lineAt(range.from), endLine = state.doc.lineAt(range.to); 19049 if (!range.empty && range.to == endLine.from) 19050 endLine = state.doc.lineAt(range.to - 1); 19051 if (upto >= startLine.number) { 19052 let prev = blocks[blocks.length - 1]; 19053 prev.to = endLine.to; 19054 prev.ranges.push(range); 19055 } 19056 else { 19057 blocks.push({ from: startLine.from, to: endLine.to, ranges: [range] }); 19058 } 19059 upto = endLine.number + 1; 19060 } 19061 return blocks; 19062} 19063function moveLine(state, dispatch, forward) { 19064 if (state.readOnly) 19065 return false; 19066 let changes = [], ranges = []; 19067 for (let block of selectedLineBlocks(state)) { 19068 if (forward ? block.to == state.doc.length : block.from == 0) 19069 continue; 19070 let nextLine = state.doc.lineAt(forward ? block.to + 1 : block.from - 1); 19071 let size = nextLine.length + 1; 19072 if (forward) { 19073 changes.push({ from: block.to, to: nextLine.to }, { from: block.from, insert: nextLine.text + state.lineBreak }); 19074 for (let r of block.ranges) 19075 ranges.push(EditorSelection.range(Math.min(state.doc.length, r.anchor + size), Math.min(state.doc.length, r.head + size))); 19076 } 19077 else { 19078 changes.push({ from: nextLine.from, to: block.from }, { from: block.to, insert: state.lineBreak + nextLine.text }); 19079 for (let r of block.ranges) 19080 ranges.push(EditorSelection.range(r.anchor - size, r.head - size)); 19081 } 19082 } 19083 if (!changes.length) 19084 return false; 19085 dispatch(state.update({ 19086 changes, 19087 scrollIntoView: true, 19088 selection: EditorSelection.create(ranges, state.selection.mainIndex), 19089 userEvent: "move.line" 19090 })); 19091 return true; 19092} 19093/** 19094Move the selected lines up one line. 19095*/ 19096const moveLineUp = ({ state, dispatch }) => moveLine(state, dispatch, false); 19097/** 19098Move the selected lines down one line. 19099*/ 19100const moveLineDown = ({ state, dispatch }) => moveLine(state, dispatch, true); 19101function copyLine(state, dispatch, forward) { 19102 if (state.readOnly) 19103 return false; 19104 let changes = []; 19105 for (let block of selectedLineBlocks(state)) { 19106 if (forward) 19107 changes.push({ from: block.from, insert: state.doc.slice(block.from, block.to) + state.lineBreak }); 19108 else 19109 changes.push({ from: block.to, insert: state.lineBreak + state.doc.slice(block.from, block.to) }); 19110 } 19111 dispatch(state.update({ changes, scrollIntoView: true, userEvent: "input.copyline" })); 19112 return true; 19113} 19114/** 19115Create a copy of the selected lines. Keep the selection in the top copy. 19116*/ 19117const copyLineUp = ({ state, dispatch }) => copyLine(state, dispatch, false); 19118/** 19119Create a copy of the selected lines. Keep the selection in the bottom copy. 19120*/ 19121const copyLineDown = ({ state, dispatch }) => copyLine(state, dispatch, true); 19122/** 19123Delete selected lines. 19124*/ 19125const deleteLine = view => { 19126 if (view.state.readOnly) 19127 return false;
19128 let { state } = view, changes = state.changes(selectedLineBlocks(state).map(({ from, to }) => { 19129 if (from > 0) 19130 from--; 19131 else if (to < state.doc.length) 19132 to++; 19133 return { from, to }; 19134 })); 19135 let selection = updateSel(state.selection, range => view.moveVertically(range, true)).map(changes); 19136 view.dispatch({ changes, selection, scrollIntoView: true, userEvent: "delete.line" }); 19137 return true; 19138}; 19139function isBetweenBrackets(state, pos) { 19140 if (/\(\)|\[\]|\{\}/.test(state.sliceDoc(pos - 1, pos + 1))) 19141 return { from: pos, to: pos }; 19142 let context = syntaxTree(state).resolveInner(pos); 19143 let before = context.childBefore(pos), after = context.childAfter(pos), closedBy; 19144 if (before && after && before.to <= pos && after.from >= pos && 19145 (closedBy = before.type.prop(NodeProp.closedBy)) && closedBy.indexOf(after.name) > -1 && 19146 state.doc.lineAt(before.to).from == state.doc.lineAt(after.from).from) 19147 return { from: before.to, to: after.from }; 19148 return null; 19149} 19150/** 19151Replace the selection with a newline and indent the newly created 19152line(s). If the current line consists only of whitespace, this 19153will also delete that whitespace. When the cursor is between 19154matching brackets, an additional newline will be inserted after 19155the cursor. 19156*/ 19157const insertNewlineAndIndent = /*@__PURE__*/newlineAndIndent(false); 19158/** 19159Create a blank, indented line below the current line. 19160*/ 19161const insertBlankLine = /*@__PURE__*/newlineAndIndent(true); 19162function newlineAndIndent(atEof) { 19163 return ({ state, dispatch }) => { 19164 if (state.readOnly) 19165 return false; 19166 let changes = state.changeByRange(range => { 19167 let { from, to } = range, line = state.doc.lineAt(from); 19168 let explode = !atEof && from == to && isBetweenBrackets(state, from); 19169 if (atEof) 19170 from = to = (to <= line.to ? line : state.doc.lineAt(to)).to; 19171 let cx = new IndentContext(state, { simulateBreak: from, simulateDoubleBreak: !!explode }); 19172 let indent = getIndentation(cx, from); 19173 if (indent == null) 19174 indent = /^\s*/.exec(state.doc.lineAt(from).text)[0].length; 19175 while (to < line.to && /\s/.test(line.text[to - line.from])) 19176 to++; 19177 if (explode) 19178 ({ from, to } = explode); 19179 else if (from > line.from && from < line.from + 100 && !/\S/.test(line.text.slice(0, from))) 19180 from = line.from; 19181 let insert = ["", indentString(state, indent)]; 19182 if (explode)
vendor: 6,093 bytes, lines 19183-19301
19183 insert.push(indentString(state, cx.lineIndent(line.from, -1))); 19184 return { changes: { from, to, insert: Text.of(insert) }, 19185 range: EditorSelection.cursor(from + 1 + insert[1].length) }; 19186 }); 19187 dispatch(state.update(changes, { scrollIntoView: true, userEvent: "input" })); 19188 return true; 19189 }; 19190} 19191function changeBySelectedLine(state, f) { 19192 let atLine = -1; 19193 return state.changeByRange(range => { 19194 let changes = []; 19195 for (let pos = range.from; pos <= range.to;) { 19196 let line = state.doc.lineAt(pos); 19197 if (line.number > atLine && (range.empty || range.to > line.from)) { 19198 f(line, changes, range); 19199 atLine = line.number; 19200 } 19201 pos = line.to + 1; 19202 } 19203 let changeSet = state.changes(changes); 19204 return { changes, 19205 range: EditorSelection.range(changeSet.mapPos(range.anchor, 1), changeSet.mapPos(range.head, 1)) }; 19206 }); 19207} 19208/** 19209Auto-indent the selected lines. This uses the [indentation service 19210facet](https://codemirror.net/6/docs/ref/#language.indentService) as source for auto-indent 19211information. 19212*/ 19213const indentSelection = ({ state, dispatch }) => { 19214 if (state.readOnly) 19215 return false; 19216 let updated = Object.create(null); 19217 let context = new IndentContext(state, { overrideIndentation: start => { 19218 let found = updated[start]; 19219 return found == null ? -1 : found; 19220 } }); 19221 let changes = changeBySelectedLine(state, (line, changes, range) => { 19222 let indent = getIndentation(context, line.from); 19223 if (indent == null) 19224 return; 19225 if (!/\S/.test(line.text)) 19226 indent = 0; 19227 let cur = /^\s*/.exec(line.text)[0]; 19228 let norm = indentString(state, indent); 19229 if (cur != norm || range.from < line.from + cur.length) { 19230 updated[line.from] = indent; 19231 changes.push({ from: line.from, to: line.from + cur.length, insert: norm }); 19232 } 19233 }); 19234 if (!changes.changes.empty) 19235 dispatch(state.update(changes, { userEvent: "indent" })); 19236 return true; 19237}; 19238/** 19239Add a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation to all selected 19240lines. 19241*/ 19242const indentMore = ({ state, dispatch }) => { 19243 if (state.readOnly) 19244 return false; 19245 dispatch(state.update(changeBySelectedLine(state, (line, changes) => { 19246 changes.push({ from: line.from, insert: state.facet(indentUnit) }); 19247 }), { userEvent: "input.indent" })); 19248 return true; 19249}; 19250/** 19251Remove a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation from all 19252selected lines. 19253*/ 19254const indentLess = ({ state, dispatch }) => { 19255 if (state.readOnly) 19256 return false; 19257 dispatch(state.update(changeBySelectedLine(state, (line, changes) => { 19258 let space = /^\s*/.exec(line.text)[0]; 19259 if (!space) 19260 return; 19261 let col = countColumn(space, state.tabSize), keep = 0; 19262 let insert = indentString(state, Math.max(0, col - getIndentUnit(state))); 19263 while (keep < space.length && keep < insert.length && space.charCodeAt(keep) == insert.charCodeAt(keep)) 19264 keep++; 19265 changes.push({ from: line.from + keep, to: line.from + space.length, insert: insert.slice(keep) }); 19266 }), { userEvent: "delete.dedent" })); 19267 return true; 19268}; 19269/** 19270Array of key bindings containing the Emacs-style bindings that are 19271available on macOS by default. 19272 19273 - Ctrl-b: [`cursorCharLeft`](https://codemirror.net/6/docs/ref/#commands.cursorCharLeft) ([`selectCharLeft`](https://codemirror.net/6/docs/ref/#commands.selectCharLeft) with Shift) 19274 - Ctrl-f: [`cursorCharRight`](https://codemirror.net/6/docs/ref/#commands.cursorCharRight) ([`selectCharRight`](https://codemirror.net/6/docs/ref/#commands.selectCharRight) with Shift) 19275 - Ctrl-p: [`cursorLineUp`](https://codemirror.net/6/docs/ref/#commands.cursorLineUp) ([`selectLineUp`](https://codemirror.net/6/docs/ref/#commands.selectLineUp) with Shift) 19276 - Ctrl-n: [`cursorLineDown`](https://codemirror.net/6/docs/ref/#commands.cursorLineDown) ([`selectLineDown`](https://codemirror.net/6/docs/ref/#commands.selectLineDown) with Shift) 19277 - Ctrl-a: [`cursorLineStart`](https://codemirror.net/6/docs/ref/#commands.cursorLineStart) ([`selectLineStart`](https://codemirror.net/6/docs/ref/#commands.selectLineStart) with Shift) 19278 - Ctrl-e: [`cursorLineEnd`](https://codemirror.net/6/docs/ref/#commands.cursorLineEnd) ([`selectLineEnd`](https://codemirror.net/6/docs/ref/#commands.selectLineEnd) with Shift) 19279 - Ctrl-d: [`deleteCharForward`](https://codemirror.net/6/docs/ref/#commands.deleteCharForward) 19280 - Ctrl-h: [`deleteCharBackward`](https://codemirror.net/6/docs/ref/#commands.deleteCharBackward) 19281 - Ctrl-k: [`deleteToLineEnd`](https://codemirror.net/6/docs/ref/#commands.deleteToLineEnd) 19282 - Ctrl-Alt-h: [`deleteGroupBackward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupBackward) 19283 - Ctrl-o: [`splitLine`](https://codemirror.net/6/docs/ref/#commands.splitLine) 19284 - Ctrl-t: [`transposeChars`](https://codemirror.net/6/docs/ref/#commands.transposeChars) 19285 - Ctrl-v: [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) 19286 - Alt-v: [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) 19287*/ 19288const emacsStyleKeymap = [ 19289 { key: "Ctrl-b", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, 19290 { key: "Ctrl-f", run: cursorCharRight, shift: selectCharRight }, 19291 { key: "Ctrl-p", run: cursorLineUp, shift: selectLineUp }, 19292 { key: "Ctrl-n", run: cursorLineDown, shift: selectLineDown }, 19293 { key: "Ctrl-a", run: cursorLineStart, shift: selectLineStart }, 19294 { key: "Ctrl-e", run: cursorLineEnd, shift: selectLineEnd }, 19295 { key: "Ctrl-d", run: deleteCharForward }, 19296 { key: "Ctrl-h", run: deleteCharBackward }, 19297 { key: "Ctrl-k", run: deleteToLineEnd }, 19298 { key: "Ctrl-Alt-h", run: deleteGroupBackward }, 19299 { key: "Ctrl-o", run: splitLine }, 19300 { key: "Ctrl-t", run: transposeChars }, 19301 { key: "Ctrl-v", run: cursorPageDown },
19302]; 19303/** 19304An array of key bindings closely sticking to platform-standard or 19305widely used bindings. (This includes the bindings from 19306[`emacsStyleKeymap`](https://codemirror.net/6/docs/ref/#commands.emacsStyleKeymap), with their `key` 19307property changed to `mac`.) 19308 19309 - ArrowLeft: [`cursorCharLeft`](https://codemirror.net/6/docs/ref/#commands.cursorCharLeft) ([`selectCharLeft`](https://codemirror.net/6/docs/ref/#commands.selectCharLeft) with Shift) 19310 - ArrowRight: [`cursorCharRight`](https://codemirror.net/6/docs/ref/#commands.cursorCharRight) ([`selectCharRight`](https://codemirror.net/6/docs/ref/#commands.selectCharRight) with Shift) 19311 - Ctrl-ArrowLeft (Alt-ArrowLeft on macOS): [`cursorGroupLeft`](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) ([`selectGroupLeft`](https://codemirror.net/6/docs/ref/#commands.selectGroupLeft) with Shift) 19312 - Ctrl-ArrowRight (Alt-ArrowRight on macOS): [`cursorGroupRight`](https://codemirror.net/6/docs/ref/#commands.cursorGroupRight) ([`selectGroupRight`](https://codemirror.net/6/docs/ref/#commands.selectGroupRight) with Shift) 19313 - Cmd-ArrowLeft (on macOS): [`cursorLineStart`](https://codemirror.net/6/docs/ref/#commands.cursorLineStart) ([`selectLineStart`](https://codemirror.net/6/docs/ref/#commands.selectLineStart) with Shift) 19314 - Cmd-ArrowRight (on macOS): [`cursorLineEnd`](https://codemirror.net/6/docs/ref/#commands.cursorLineEnd) ([`selectLineEnd`](https://codemirror.net/6/docs/ref/#commands.selectLineEnd) with Shift) 19315 - ArrowUp: [`cursorLineUp`](https://codemirror.net/6/docs/ref/#commands.cursorLineUp) ([`selectLineUp`](https://codemirror.net/6/docs/ref/#commands.selectLineUp) with Shift) 19316 - ArrowDown: [`cursorLineDown`](https://codemirror.net/6/docs/ref/#commands.cursorLineDown) ([`selectLineDown`](https://codemirror.net/6/docs/ref/#commands.selectLineDown) with Shift) 19317 - Cmd-ArrowUp (on macOS): [`cursorDocStart`](https://codemirror.net/6/docs/ref/#commands.cursorDocStart) ([`selectDocStart`](https://codemirror.net/6/docs/ref/#commands.selectDocStart) with Shift) 19318 - Cmd-ArrowDown (on macOS): [`cursorDocEnd`](https://codemirror.net/6/docs/ref/#commands.cursorDocEnd) ([`selectDocEnd`](https://codemirror.net/6/docs/ref/#commands.selectDocEnd) with Shift) 19319 - Ctrl-ArrowUp (on macOS): [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) ([`selectPageUp`](https://codemirror.net/6/docs/ref/#commands.selectPageUp) with Shift) 19320 - Ctrl-ArrowDown (on macOS): [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) ([`selectPageDown`](https://codemirror.net/6/docs/ref/#commands.selectPageDown) with Shift) 19321 - PageUp: [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) ([`selectPageUp`](https://codemirror.net/6/docs/ref/#commands.selectPageUp) with Shift) 19322 - PageDown: [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) ([`selectPageDown`](https://codemirror.net/6/docs/ref/#commands.selectPageDown) with Shift) 19323 - Home: [`cursorLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.cursorLineBoundaryBackward) ([`selectLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.selectLineBoundaryBackward) with Shift) 19324 - End: [`cursorLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.cursorLineBoundaryForward) ([`selectLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.selectLineBoundaryForward) with Shift) 19325 - Ctrl-Home (Cmd-Home on macOS): [`cursorDocStart`](https://codemirror.net/6/docs/ref/#commands.cursorDocStart) ([`selectDocStart`](https://codemirror.net/6/docs/ref/#commands.selectDocStart) with Shift) 19326 - Ctrl-End (Cmd-Home on macOS): [`cursorDocEnd`](https://codemirror.net/6/docs/ref/#commands.cursorDocEnd) ([`selectDocEnd`](https://codemirror.net/6/docs/ref/#commands.selectDocEnd) with Shift) 19327 - Enter: [`insertNewlineAndIndent`](https://codemirror.net/6/docs/ref/#commands.insertNewlineAndIndent) 19328 - Ctrl-a (Cmd-a on macOS): [`selectAll`](https://codemirror.net/6/docs/ref/#commands.selectAll) 19329 - Backspace: [`deleteCharBackward`](https://codemirror.net/6/docs/ref/#commands.deleteCharBackward) 19330 - Delete: [`deleteCharForward`](https://codemirror.net/6/docs/ref/#commands.deleteCharForward) 19331 - Ctrl-Backspace (Alt-Backspace on macOS): [`deleteGroupBackward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupBackward) 19332 - Ctrl-Delete (Alt-Delete on macOS): [`deleteGroupForward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupForward) 19333 - Cmd-Backspace (macOS): [`deleteToLineStart`](https://codemirror.net/6/docs/ref/#commands.deleteToLineStart). 19334 - Cmd-Delete (macOS): [`deleteToLineEnd`](https://codemirror.net/6/docs/ref/#commands.deleteToLineEnd). 19335*/ 19336const standardKeymap = /*@__PURE__*/[ 19337 { key: "ArrowLeft", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, 19338 { key: "Mod-ArrowLeft", mac: "Alt-ArrowLeft", run: cursorGroupLeft, shift: selectGroupLeft, preventDefault: true }, 19339 { mac: "Cmd-ArrowLeft", run: cursorLineBoundaryLeft, shift: selectLineBoundaryLeft, preventDefault: true }, 19340 { key: "ArrowRight", run: cursorCharRight, shift: selectCharRight, preventDefault: true }, 19341 { key: "Mod-ArrowRight", mac: "Alt-ArrowRight", run: cursorGroupRight, shift: selectGroupRight, preventDefault: true }, 19342 { mac: "Cmd-ArrowRight", run: cursorLineBoundaryRight, shift: selectLineBoundaryRight, preventDefault: true }, 19343 { key: "ArrowUp", run: cursorLineUp, shift: selectLineUp, preventDefault: true }, 19344 { mac: "Cmd-ArrowUp", run: cursorDocStart, shift: selectDocStart }, 19345 { mac: "Ctrl-ArrowUp", run: cursorPageUp, shift: selectPageUp }, 19346 { key: "ArrowDown", run: cursorLineDown, shift: selectLineDown, preventDefault: true }, 19347 { mac: "Cmd-ArrowDown", run: cursorDocEnd, shift: selectDocEnd }, 19348 { mac: "Ctrl-ArrowDown", run: cursorPageDown, shift: selectPageDown },
19349 { key: "PageUp", run: cursorPageUp, shift: selectPageUp }, 19350 { key: "PageDown", run: cursorPageDown, shift: selectPageDown }, 19351 { key: "Home", run: cursorLineBoundaryBackward, shift: selectLineBoundaryBackward, preventDefault: true }, 19352 { key: "Mod-Home", run: cursorDocStart, shift: selectDocStart }, 19353 { key: "End", run: cursorLineBoundaryForward, shift: selectLineBoundaryForward, preventDefault: true }, 19354 { key: "Mod-End", run: cursorDocEnd, shift: selectDocEnd }, 19355 { key: "Enter", run: insertNewlineAndIndent }, 19356 { key: "Mod-a", run: selectAll }, 19357 { key: "Backspace", run: deleteCharBackward, shift: deleteCharBackward }, 19358 { key: "Delete", run: deleteCharForward }, 19359 { key: "Mod-Backspace", mac: "Alt-Backspace", run: deleteGroupBackward }, 19360 { key: "Mod-Delete", mac: "Alt-Delete", run: deleteGroupForward }, 19361 { mac: "Mod-Backspace", run: deleteToLineStart }, 19362 { mac: "Mod-Delete", run: deleteToLineEnd } 19363].concat(/*@__PURE__*/emacsStyleKeymap.map(b => ({ mac: b.key, run: b.run, shift: b.shift }))); 19364/** 19365The default keymap. Includes all bindings from 19366[`standardKeymap`](https://codemirror.net/6/docs/ref/#commands.standardKeymap) plus the following: 19367 19368- Alt-ArrowLeft (Ctrl-ArrowLeft on macOS): [`cursorSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxLeft) ([`selectSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxLeft) with Shift) 19369- Alt-ArrowRight (Ctrl-ArrowRight on macOS): [`cursorSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxRight) ([`selectSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxRight) with Shift) 19370- Alt-ArrowUp: [`moveLineUp`](https://codemirror.net/6/docs/ref/#commands.moveLineUp) 19371- Alt-ArrowDown: [`moveLineDown`](https://codemirror.net/6/docs/ref/#commands.moveLineDown) 19372- Shift-Alt-ArrowUp: [`copyLineUp`](https://codemirror.net/6/docs/ref/#commands.copyLineUp) 19373- Shift-Alt-ArrowDown: [`copyLineDown`](https://codemirror.net/6/docs/ref/#commands.copyLineDown) 19374- Escape: [`simplifySelection`](https://codemirror.net/6/docs/ref/#commands.simplifySelection) 19375- Ctrl-Enter (Comd-Enter on macOS): [`insertBlankLine`](https://codemirror.net/6/docs/ref/#commands.insertBlankLine) 19376- Alt-l (Ctrl-l on macOS): [`selectLine`](https://codemirror.net/6/docs/ref/#commands.selectLine) 19377- Ctrl-i (Cmd-i on macOS): [`selectParentSyntax`](https://codemirror.net/6/docs/ref/#commands.selectParentSyntax) 19378- Ctrl-[ (Cmd-[ on macOS): [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess) 19379- Ctrl-] (Cmd-] on macOS): [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) 19380- Ctrl-Alt-\\ (Cmd-Alt-\\ on macOS): [`indentSelection`](https://codemirror.net/6/docs/ref/#commands.indentSelection) 19381- Shift-Ctrl-k (Shift-Cmd-k on macOS): [`deleteLine`](https://codemirror.net/6/docs/ref/#commands.deleteLine) 19382- Shift-Ctrl-\\ (Shift-Cmd-\\ on macOS): [`cursorMatchingBracket`](https://codemirror.net/6/docs/ref/#commands.cursorMatchingBracket) 19383- Ctrl-/ (Cmd-/ on macOS): [`toggleComment`](https://codemirror.net/6/docs/ref/#commands.toggleComment). 19384- Shift-Alt-a: [`toggleBlockComment`](https://codemirror.net/6/docs/ref/#commands.toggleBlockComment). 19385*/ 19386const defaultKeymap = /*@__PURE__*/[ 19387 { key: "Alt-ArrowLeft", mac: "Ctrl-ArrowLeft", run: cursorSyntaxLeft, shift: selectSyntaxLeft }, 19388 { key: "Alt-ArrowRight", mac: "Ctrl-ArrowRight", run: cursorSyntaxRight, shift: selectSyntaxRight }, 19389 { key: "Alt-ArrowUp", run: moveLineUp }, 19390 { key: "Shift-Alt-ArrowUp", run: copyLineUp }, 19391 { key: "Alt-ArrowDown", run: moveLineDown }, 19392 { key: "Shift-Alt-ArrowDown", run: copyLineDown }, 19393 { key: "Escape", run: simplifySelection }, 19394 { key: "Mod-Enter", run: insertBlankLine }, 19395 { key: "Alt-l", mac: "Ctrl-l", run: selectLine }, 19396 { key: "Mod-i", run: selectParentSyntax, preventDefault: true }, 19397 { key: "Mod-[", run: indentLess }, 19398 { key: "Mod-]", run: indentMore }, 19399 { key: "Mod-Alt-\\", run: indentSelection }, 19400 { key: "Shift-Mod-k", run: deleteLine }, 19401 { key: "Shift-Mod-\\", run: cursorMatchingBracket }, 19402 { key: "Mod-/", run: toggleComment }, 19403 { key: "Alt-A", run: toggleBlockComment } 19404].concat(standardKeymap); 19405/** 19406A binding that binds Tab to [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) and 19407Shift-Tab to [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess). 19408Please see the [Tab example](../../examples/tab/) before using 19409this. 19410*/ 19411const indentWithTab = { key: "Tab", run: indentMore, shift: indentLess }; 19412 19413const base00$1 = '#2E3235', base01$1 = '#DDDDDD', base02$1 = '#B9D2FF', base03$1 = '#b0b0b0', base05$1 = '#e0e0e0', base06$1 = '#808080', base07$1 = '#000000', base08$1 = '#A54543', base09$1 = '#fc6d24', base0A$1 = '#fda331', base0B = '#8abeb7', base0C$1 = '#b5bd68', base0D$1 = '#6fb3d2', base0E$1 = '#cc99cc', base0F$1 = '#6987AF';
19414const invalid$1 = base09$1, darkBackground$1 = '#292d30', highlightBackground$1 = base02$1 + '30', background$1 = base00$1, tooltipBackground$1 = base01$1, selection$1 = '#202325', cursor$1 = base01$1; 19415/** 19416The editor theme styles for Basic Dark. 19417*/ 19418const basicDarkTheme = /*@__PURE__*/EditorView.theme({ 19419 '&': { 19420 color: base01$1, 19421 backgroundColor: background$1 19422 }, 19423 '.cm-content': { 19424 caretColor: cursor$1 19425 }, 19426 '.cm-cursor, .cm-dropCursor': { borderLeftColor: cursor$1 }, 19427 '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': { backgroundColor: selection$1 }, 19428 '.cm-panels': { backgroundColor: darkBackground$1, color: base03$1 }, 19429 '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' }, 19430 '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' }, 19431 '.cm-searchMatch': { 19432 backgroundColor: base02$1, 19433 outline: `1px solid ${base03$1}`, 19434 color: base07$1 19435 }, 19436 '.cm-searchMatch.cm-searchMatch-selected': { 19437 backgroundColor: base05$1, 19438 color: base07$1 19439 },
19440 '.cm-activeLine': { backgroundColor: highlightBackground$1 }, 19441 '.cm-selectionMatch': { backgroundColor: highlightBackground$1 }, 19442 '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { 19443 outline: `1px solid ${base03$1}` 19444 }, 19445 '&.cm-focused .cm-matchingBracket': { 19446 backgroundColor: base02$1, 19447 color: base07$1 19448 }, 19449 '.cm-gutters': { 19450 borderRight: `1px solid #ffffff10`, 19451 color: base06$1, 19452 backgroundColor: darkBackground$1 19453 }, 19454 '.cm-activeLineGutter': { 19455 backgroundColor: highlightBackground$1 19456 }, 19457 '.cm-foldPlaceholder': { 19458 backgroundColor: 'transparent', 19459 border: 'none', 19460 color: base02$1 19461 }, 19462 '.cm-tooltip': { 19463 border: 'none', 19464 backgroundColor: tooltipBackground$1 19465 }, 19466 '.cm-tooltip .cm-tooltip-arrow:before': { 19467 borderTopColor: 'transparent', 19468 borderBottomColor: 'transparent' 19469 }, 19470 '.cm-tooltip .cm-tooltip-arrow:after': { 19471 borderTopColor: tooltipBackground$1, 19472 borderBottomColor: tooltipBackground$1 19473 }, 19474 '.cm-tooltip-autocomplete': { 19475 '& > ul > li[aria-selected]': {
19476 backgroundColor: highlightBackground$1, 19477 color: base03$1 19478 } 19479 } 19480}, { dark: true }); 19481/** 19482The highlighting style for code in the Basic Light theme. 19483*/ 19484const basicDarkHighlightStyle = /*@__PURE__*/HighlightStyle.define([ 19485 { tag: tags.keyword, color: base0A$1 }, 19486 { 19487 tag: [tags.name, tags.deleted, tags.character, tags.propertyName, tags.macroName], 19488 color: base0C$1 19489 }, 19490 { tag: [tags.variableName], color: base0D$1 }, 19491 { tag: [/*@__PURE__*/tags.function(tags.variableName)], color: base0A$1 }, 19492 { tag: [tags.labelName], color: base09$1 }, 19493 { 19494 tag: [tags.color, /*@__PURE__*/tags.constant(tags.name), /*@__PURE__*/tags.standard(tags.name)], 19495 color: base0A$1 19496 }, 19497 { tag: [/*@__PURE__*/tags.definition(tags.name), tags.separator], color: base0E$1 }, 19498 { tag: [tags.brace], color: base0E$1 }, 19499 { 19500 tag: [tags.annotation], 19501 color: invalid$1 19502 }, 19503 { 19504 tag: [tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace], 19505 color: base0A$1 19506 }, 19507 { 19508 tag: [tags.typeName, tags.className], 19509 color: base0D$1 19510 }, 19511 { 19512 tag: [tags.operator, tags.operatorKeyword], 19513 color: base0E$1 19514 }, 19515 { 19516 tag: [tags.tagName], 19517 color: base0A$1 19518 }, 19519 { 19520 tag: [tags.squareBracket], 19521 color: base0E$1 19522 }, 19523 { 19524 tag: [tags.angleBracket], 19525 color: base0E$1 19526 }, 19527 { 19528 tag: [tags.attributeName], 19529 color: base0D$1 19530 }, 19531 { 19532 tag: [tags.regexp], 19533 color: base0A$1 19534 }, 19535 { 19536 tag: [tags.quote], 19537 color: base01$1 19538 }, 19539 { tag: [tags.string], color: base0C$1 }, 19540 { 19541 tag: tags.link, 19542 color: base0F$1, 19543 textDecoration: 'underline', 19544 textUnderlinePosition: 'under' 19545 }, 19546 { 19547 tag: [tags.url, tags.escape, /*@__PURE__*/tags.special(tags.string)], 19548 color: base0B 19549 }, 19550 { tag: [tags.meta], color: base08$1 }, 19551 { tag: [tags.comment], color: base06$1, fontStyle: 'italic' }, 19552 { tag: tags.monospace, color: base01$1 }, 19553 { tag: tags.strong, fontWeight: 'bold', color: base0A$1 }, 19554 { tag: tags.emphasis, fontStyle: 'italic', color: base0D$1 }, 19555 { tag: tags.strikethrough, textDecoration: 'line-through' }, 19556 { tag: tags.heading, fontWeight: 'bold', color: base01$1 }, 19557 { tag: /*@__PURE__*/tags.special(tags.heading1), fontWeight: 'bold', color: base01$1 }, 19558 { tag: tags.heading1, fontWeight: 'bold', color: base01$1 }, 19559 { 19560 tag: [tags.heading2, tags.heading3, tags.heading4], 19561 fontWeight: 'bold', 19562 color: base01$1 19563 }, 19564 { 19565 tag: [tags.heading5, tags.heading6], 19566 color: base01$1 19567 }, 19568 { tag: [tags.atom, tags.bool, /*@__PURE__*/tags.special(tags.variableName)], color: base0B }, 19569 { 19570 tag: [tags.processingInstruction, tags.inserted], 19571 color: base0B 19572 }, 19573 { 19574 tag: [tags.contentSeparator], 19575 color: base0D$1 19576 }, 19577 { tag: tags.invalid, color: base02$1, borderBottom: `1px dotted ${invalid$1}` } 19578]); 19579/** 19580Extension to enable the Basic Dark theme (both the editor theme and 19581the highlight style). 19582*/ 19583const basicDark = [ 19584 basicDarkTheme, 19585 /*@__PURE__*/syntaxHighlighting(basicDarkHighlightStyle) 19586]; 19587 19588// Colors from https://www.nordtheme.com/docs/colors-and-palettes 19589// Polar Night 19590const base00 = '#2e3440', // black 19591base01 = '#3b4252', // dark grey 19592base02 = '#434c5e', base03 = '#4c566a'; // grey 19593// Snow Storm 19594const base05 = '#e5e9f0', // off white 19595base06 = '#eceff4'; // white 19596// Frost 19597const base07 = '#8fbcbb', // moss green 19598base08 = '#88c0d0', // ice blue 19599base09 = '#81a1c1', // water blue 19600base0A = '#5e81ac'; // deep blue 19601// Aurora 19602const base0b = '#bf616a', // red 19603base0C = '#d08770', // orange 19604base0D = '#ebcb8b', // yellow 19605base0E = '#a3be8c', // green 19606base0F = '#b48ead'; // purple 19607const invalid = '#d30102', darkBackground = base06, highlightBackgroun
19607d = darkBackground, background = '#ffffff', tooltipBackground = base01, selection = darkBackground, cursor = base01; 19608/** 19609The editor theme styles for Basic Light. 19610*/ 19611const basicLightTheme = /*@__PURE__*/EditorView.theme({ 19612 '&': { 19613 color: base00, 19614 backgroundColor: background 19615 }, 19616 '.cm-content': { 19617 caretColor: cursor 19618 }, 19619 '.cm-cursor, .cm-dropCursor': { borderLeftColor: cursor }, 19620 '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': { backgroundColor: selection }, 19621 '.cm-panels': { backgroundColor: darkBackground, color: base03 }, 19622 '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' }, 19623 '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' }, 19624 '.cm-searchMatch': { 19625 backgroundColor: '#72a1ff59', 19626 outline: `1px solid ${base03}` 19627 }, 19628 '.cm-searchMatch.cm-searchMatch-selected': { 19629 backgroundColor: base05 19630 }, 19631 '.cm-activeLine': { backgroundColor: highlightBackground }, 19632 '.cm-selectionMatch': { backgroundColor: base05 }, 19633 '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { 19634 outline: `1px solid ${base03}` 19635 }, 19636 '&.cm-focused .cm-matchingBracket': { 19637 backgroundColor: base06 19638 }, 19639 '.cm-gutters': { 19640 backgroundColor: base06, 19641 color: base00, 19642 border: 'none' 19643 }, 19644 '.cm-activeLineGutter': {
19645 backgroundColor: highlightBackground 19646 }, 19647 '.cm-foldPlaceholder': { 19648 backgroundColor: 'transparent', 19649 border: 'none', 19650 color: '#ddd' 19651 }, 19652 '.cm-tooltip': { 19653 border: 'none', 19654 backgroundColor: tooltipBackground 19655 }, 19656 '.cm-tooltip .cm-tooltip-arrow:before': { 19657 borderTopColor: 'transparent', 19658 borderBottomColor: 'transparent' 19659 }, 19660 '.cm-tooltip .cm-tooltip-arrow:after': { 19661 borderTopColor: tooltipBackground, 19662 borderBottomColor: tooltipBackground 19663 }, 19664 '.cm-tooltip-autocomplete': { 19665 '& > ul > li[aria-selected]': { 19666 backgroundColor: highlightBackground, 19667 color: base03 19668 } 19669 } 19670}, { dark: false }); 19671/** 19672The highlighting style for code in the Basic Light theme. 19673*/ 19674const basicLightHighlightStyle = /*@__PURE__*/HighlightStyle.define([ 19675 { tag: tags.keyword, color: base0A }, 19676 { 19677 tag: [tags.name, tags.deleted, tags.character, tags.propertyName, tags.macroName], 19678 color: base0C 19679 }, 19680 { tag: [tags.variableName], color: base0C }, 19681 { tag: [/*@__PURE__*/tags.function(tags.variableName)], color: base0A }, 19682 { tag: [tags.labelName], color: base09 }, 19683 { 19684 tag: [tags.color, /*@__PURE__*/tags.constant(tags.name), /*@__PURE__*/tags.standard(tags.name)], 19685 color: base0A 19686 }, 19687 { tag: [/*@__PURE__*/tags.definition(tags.name), tags.separator], color: base0E }, 19688 { tag: [tags.brace], color: base07 }, 19689 { 19690 tag: [tags.annotation], 19691 color: invalid 19692 }, 19693 { 19694 tag: [tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace], 19695 color: base08 19696 }, 19697 { 19698 tag: [tags.typeName, tags.className], 19699 color: base0D 19700 }, 19701 { 19702 tag: [tags.operator, tags.operatorKeyword], 19703 color: base0E 19704 }, 19705 { 19706 tag: [tags.tagName], 19707 color: base0F 19708 }, 19709 { 19710 tag: [tags.squareBracket], 19711 color: base0b 19712 }, 19713 { 19714 tag: [tags.angleBracket], 19715 color: base0C 19716 }, 19717 { 19718 tag: [tags.attributeName], 19719 color: base0D 19720 }, 19721 { 19722 tag: [tags.regexp], 19723 color: base0A 19724 }, 19725 { 19726 tag: [tags.quote], 19727 color: base01 19728 }, 19729 { tag: [tags.string], color: base0C }, 19730 { 19731 tag: tags.link, 19732 color: base07, 19733 textDecoration: 'underline', 19734 textUnderlinePosition: 'under' 19735 }, 19736 { 19737 tag: [tags.url, tags.escape, /*@__PURE__*/tags.special(tags.string)], 19738 color: base0C 19739 }, 19740 { tag: [tags.meta], color: base08 }, 19741 { tag: [tags.comment], color: base02, fontStyle: 'italic' }, 19742 { tag: tags.strong, fontWeight: 'bold', color: base0A }, 19743 { tag: tags.emphasis, fontStyle: 'italic', color: base0A }, 19744 { tag: tags.strikethrough, textDecoration: 'line-through' }, 19745 { tag: tags.heading, fontWeight: 'bold', color: base0A }, 19746 { tag: /*@__PURE__*/tags.special(tags.heading1), fontWeight: 'bold', color: base0A }, 19747 { tag: tags.heading1, fontWeight: 'bold', color: base0A }, 19748 { 19749 tag: [tags.heading2, tags.heading3, tags.heading4], 19750 fontWeight: 'bold', 19751 color: base0A 19752 }, 19753 { 19754 tag: [tags.heading5, tags.heading6], 19755 color: base0A 19756 }, 19757 { tag: [tags.atom, tags.bool, /*@__PURE__*/tags.special(tags.variableName)], color: base0C }, 19758 { 19759 tag: [tags.processingInstruction, tags.inserted], 19760 color: base07 19761 }, 19762 { 19763 tag: [tags.contentSeparator], 19764 color: base0D 19765 }, 19766 { tag: tags.invalid, color: base02, borderBottom: `1px dotted ${invalid}` } 19767]); 19768/** 19769Extension to enable the Basic Light theme (both the editor theme and 19770the highlight style). 19771*/ 19772const basicLight = [ 19773 basicLightTheme, 19774 /*@__PURE__*/syntaxHighlighting(basicLightHighlightStyle) 19775]; 19776 19777function toSet(chars) { 19778 let flat = Object.keys(chars).join(""); 19779 let words = /\w/.test(flat); 19780 if (words) 19781 flat = flat.replace(/\w/g, ""); 19782 return `[${words ? "\\w" : ""}${flat.replace(/[^\w\s]/g, "\\$&")}]`; 19783} 19784function prefixMatch(options) { 19785 let first = Object.create(null), rest = Object.create(null); 19786 for (let { label } of options) { 19787 first[label[0]] = true; 19788 for (let i = 1; i < label.length; i++) 19789 rest[label[i]] = true; 19790 } 19791 let source = toSet(first) + toSet(rest) + "*$"; 19792 return [new RegExp("^" + source), new RegExp(source)]; 19793} 19794/** 19795Given a a fixed array of options, return an autocompleter that 19796completes them. 19797*/ 19798function completeFromList(list) { 19799 let options = list.map(o => typeof o == "string" ? { label: o } : o); 19800 let [validFor, match] = options.every(o => /^\w+$/.test(o.label)) ? [/\w*$/, /\w+$/] : prefixMatch(options); 19801 return (context) => { 19802 let token = context.matchBefore(match); 19803 return token || context.explicit ? { from: token ? token.from : context.pos, options, validFor } : null; 19804 }; 19805} 19806/** 19807Wrap the given completion source so that it will not fire when the 19808cursor is in a syntax node with one of the given names. 19809*/ 19810function ifNotIn(nodes, source) { 19811 return (context) => { 19812 for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) 19813 if (nodes.indexOf(pos.name) > -1) 19814 return null; 19815 return source(context); 19816 }; 19817} 19818class Option { 19819 constructor(completion, source, match) { 19820 this.completion = completion; 19821 this.source = source; 19822 this.match = match; 19823 } 19824} 19825function cur(state) { return state.selection.main.head; } 19826/** 19827Helper function that returns a transaction spec which inserts a 19828completion's text in the main selection range, and any other 19829selection range that has the same text in front of it. 19830*/ 19831function insertCompletionText(state, text, from, to) { 19832 return Object.assign(Object.assign({}, state.changeByRange(range => { 19833 if (range == state.selection.main) 19834 return { 19835 changes: { from: from, to: to, insert: text }, 19836 range: EditorSelection.cursor(from + text.length) 19837 }; 19838 let len = to - from; 19839 if (!range.empty || 19840 len && state.sliceDoc(range.from - len, range.from) != state.sliceDoc(from, to)) 19841 return { range }; 19842 return { 19843 changes: { from: range.from - len, to: range.from, insert: text }, 19844 range: EditorSelection.cursor(range.from - len + text.length) 19845 }; 19846 })), { userEvent: "input.complete" }); 19847} 19848function applyCompletion(view, option) { 19849 const apply = option.completion.apply || option.completion.label; 19850 let result = option.source; 19851 if (typeof apply == "string") 19852 view.dispatch(insertCompletionText(view.state, apply, result.from, result.to)); 19853 else 19854 apply(view, option.completion, result.from, result.to); 19855} 19856const SourceCache = /*@__PURE__*/new WeakMap(); 19857function asSource(source) { 19858 if (!Array.isArray(source)) 19859 return source; 19860 let known = SourceCache.get(source); 19861 if (!known) 19862 SourceCache.set(source, known = completeFromList(source)); 19863 return known; 19864} 19865 19866// A pattern matcher for fuzzy completion matching. Create an instance 19867// once for a pattern, and then use that to match any number of 19868// completions. 19869class FuzzyMatcher { 19870 constructor(pattern) { 19871 this.pattern = pattern; 19872 this.chars = []; 19873 this.folded = []; 19874 // Buffers reused by calls to `match` to track matched character 19875 // positions. 19876 this.any = []; 19877 this.precise = []; 19878 this.byWord = []; 19879 for (let p = 0; p < pattern.length;) { 19880 let char = codePointAt(pattern, p), size = codePointSize(char); 19881 this.chars.push(char); 19882 let part = pattern.slice(p, p + size), upper = part.toUpperCase(); 19883 this.folded.push(codePointAt(upper == part ? part.toLowerCase() : upper, 0)); 19884 p += size; 19885 } 19886 this.astral = pattern.length != this.chars.length; 19887 } 19888 // Matches a given word (completion) against the pattern (input). 19889 // Will return null for no match, and otherwise an array that starts 19890 // with the match score, followed by any number of `from, to` pairs 19891 // indicating the matched parts of `word`. 19892 // 19893 // The score is a number that is more negative the worse the match 19894 // is. See `Penalty` above. 19895 match(word) { 19896 if (this.pattern.length == 0) 19897 return [0]; 19898 if (word.length < this.pattern.length) 19899 return null; 19900 let { chars, folded, any, precise, byWord } = this; 19901 // For single-character queries, only match when they occur right 19902 // at the start 19903 if (chars.length == 1) { 19904 let first = codePointAt(word, 0); 19905 return first == chars[0] ? [0, 0, codePointSize(first)] 19906 : first == folded[0] ? [-200 /* Penalty.CaseFold */, 0, codePointSize(first)] : null; 19907 } 19908 let direct = word.indexOf(this.pattern); 19909 if (direct == 0) 19910 return [0, 0, this.pattern.length]; 19911 let len = chars.length, anyTo = 0; 19912 if (direct < 0) { 19913 for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) { 19914 let next = codePointAt(word, i); 19915 if (next == chars[anyTo] || next == folded[anyTo]) 19916 any[anyTo++] = i; 19917 i += codePointSize(next); 19918 } 19919 // No match, exit immediately 19920 if (anyTo < len) 19921 return null; 19922 } 19923 // This tracks the extent of the precise (non-folded, not 19924 // necessarily adjacent) match 19925 let preciseTo = 0; 19926 // Tracks whether there is a match that hits only characters that 19927 // appear to be starting words. `byWordFolded` is set to true when 19928 // a case folded character is encountered in such a match
19929 let byWordTo = 0, byWordFolded = false; 19930 // If we've found a partial adjacent match, these track its state 19931 let adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1; 19932 let hasLower = /[a-z]/.test(word), wordAdjacent = true; 19933 // Go over the option's text, scanning for the various kinds of matches 19934 for (let i = 0, e = Math.min(word.length, 200), prevType = 0 /* Tp.NonWord */; i < e && byWordTo < len;) { 19935 let next = codePointAt(word, i); 19936 if (direct < 0) { 19937 if (preciseTo < len && next == chars[preciseTo]) 19938 precise[preciseTo++] = i; 19939 if (adjacentTo < len) { 19940 if (next == chars[adjacentTo] || next == folded[adjacentTo]) { 19941 if (adjacentTo == 0) 19942 adjacentStart = i; 19943 adjacentEnd = i + 1; 19944 adjacentTo++; 19945 } 19946 else { 19947 adjacentTo = 0; 19948 } 19949 } 19950 } 19951 let ch, type = next < 0xff 19952 ? (next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 /* Tp.Lower */ : next >= 65 && next <= 90 ? 1 /* Tp.Upper */ : 0 /* Tp.NonWord */) 19953 : ((ch = fromCodePoint(next)) != ch.toLowerCase() ? 1 /* Tp.Upper */ : ch != ch.toUpperCase() ? 2 /* Tp.Lower */ : 0 /* Tp.NonWord */); 19954 if (!i || type == 1 /* Tp.Upper */ && hasLower || prevType == 0 /* Tp.NonWord */ && type != 0 /* Tp.NonWord */) { 19955 if (chars[byWordTo] == next || (folded[byWordTo] == next && (byWordFolded = true))) 19956 byWord[byWordTo++] = i; 19957 else if (byWord.length) 19958 wordAdjacent = false; 19959 } 19960 prevType = type; 19961 i += codePointSize(next); 19962 } 19963 if (byWordTo == len && byWord[0] == 0 && wordAdjacent) 19964 return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0), byWord, word); 19965 if (adjacentTo == len && adjacentStart == 0) 19966 return [-200 /* Penalty.CaseFold */ - word.length, 0, adjacentEnd]; 19967 if (direct > -1) 19968 return [-700 /* Penalty.NotStart */ - word.length, direct, direct + this.pattern.length]; 19969 if (adjacentTo == len) 19970 return [-200 /* Penalty.CaseFold */ + -700 /* Penalty.NotStart */ - word.length, adjacentStart, adjacentEnd]; 19971 if (byWordTo == len) 19972 return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0) + -700 /* Penalty.NotStart */ + 19973 (wordAdjacent ? 0 : -1100 /* Penalty.Gap */), byWord, word); 19974 return chars.length == 2 ? null : this.result((any[0] ? -700 /* Penalty.NotStart */ : 0) + -200 /* Penalty.CaseFold */ + -1100 /* Penalty.Gap */, any, word); 19975 } 19976 result(score, positions, word) { 19977 let result = [score - word.length], i = 1; 19978 for (let pos of positions) { 19979 let to = pos + (this.astral ? codePointSize(codePointAt(word, pos)) : 1); 19980 if (i > 1 && result[i - 1] == pos) 19981 result[i - 1] = to; 19982 else { 19983 result[i++] = pos; 19984 result[i++] = to; 19985 } 19986 } 19987 return result; 19988 } 19989} 19990 19991const completionConfig = /*@__PURE__*/Facet.define({ 19992 combine(configs) { 19993 return combineConfig(configs, { 19994 activateOnTyping: true, 19995 selectOnOpen: true, 19996 override: null, 19997 closeOnBlur: true, 19998 maxRenderedOptions: 100, 19999 defaultKeymap: true, 20000 optionClass: () => "", 20001 aboveCursor: false, 20002 icons: true, 20003 addToOptions: [], 20004 compareCompletions: (a, b) => a.label.localeCompare(b.label), 20005 interactionDelay: 75 20006 }, { 20007 defaultKeymap: (a, b) => a && b, 20008 closeOnBlur: (a, b) => a && b, 20009 icons: (a, b) => a && b, 20010 optionClass: (a, b) => c => joinClass(a(c), b(c)), 20011 addToOptions: (a, b) =>
20011 a.concat(b) 20012 }); 20013 } 20014}); 20015function joinClass(a, b) { 20016 return a ? b ? a + " " + b : a : b; 20017} 20018 20019function optionContent(config) { 20020 let content = config.addToOptions.slice(); 20021 if (config.icons) 20022 content.push({ 20023 render(completion) { 20024 let icon = document.createElement("div"); 20025 icon.classList.add("cm-completionIcon"); 20026 if (completion.type) 20027 icon.classList.add(...completion.type.split(/\s+/g).map(cls => "cm-completionIcon-" + cls)); 20028 icon.setAttribute("aria-hidden", "true"); 20029 return icon; 20030 }, 20031 position: 20 20032 }); 20033 content.push({ 20034 render(completion, _s, match) { 20035 let labelElt = document.createElement("span"); 20036 labelElt.className = "cm-completionLabel"; 20037 let { label } = completion, off = 0; 20038 for (let j = 1; j < match.length;) { 20039 let from = match[j++], to = match[j++]; 20040 if (from > off) 20041 labelElt.appendChild(document.createTextNode(label.slice(off, from))); 20042 let span = labelElt.appendChild(document.createElement("span")); 20043 span.appendChild(document.createTextNode(label.slice(from, to))); 20044 span.className = "cm-completionMatchedText"; 20045 off = to; 20046 } 20047 if (off < label.length) 20048 labelElt.appendChild(document.createTextNode(label.slice(off))); 20049 return labelElt; 20050 }, 20051 position: 50 20052 }, { 20053 render(completion) { 20054 if (!completion.detail) 20055 return null; 20056 let detailElt = document.createElement("span"); 20057 detailElt.className = "cm-completionDetail"; 20058 detailElt.textContent = completion.detail; 20059 return detailElt; 20060 }, 20061 position: 80 20062 }); 20063 return content.sort((a, b) => a.position - b.position).map(a => a.render); 20064} 20065function rangeAroundSelected(total, selected, max) { 20066 if (total <= max) 20067 return { from: 0, to: total }; 20068 if (selected < 0) 20069 selected = 0; 20070 if (selected <= (total >> 1)) { 20071 let off = Math.floor(selected / max); 20072 return { from: off * max, to: (off + 1) * max }; 20073 } 20074 let off = Math.floor((total - selected) / max); 20075 return { from: total - (off + 1) * max, to: total - off * max }; 20076} 20077class CompletionTooltip { 20078 constructor(view, stateField) { 20079 this.view = view; 20080 this.stateField = stateField; 20081 this.info = null; 20082 this.placeInfo = { 20083 read: () => this.measureInfo(), 20084 write: (pos) => this.positionInfo(pos), 20085 key: this 20086 }; 20087 let cState = view.state.field(stateField); 20088 let { options, selected } = cState.open; 20089 let config = view.state.facet(completionConfig); 20090 this.optionContent = optionContent(config); 20091 this.optionClass = config.optionClass; 20092 this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions); 20093 this.dom = document.createElement("div"); 20094 this.dom.className = "cm-tooltip-autocomplete"; 20095 this.dom.addEventListener("mousedown", (e) => { 20096 for (let dom = e.target, match; dom && dom != this.dom; dom = dom.parentNode) { 20097 if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) { 20098 applyCompletion(view, options[+match[1]]); 20099 e.preventDefault(); 20100 return; 20101 } 20102 } 20103 }); 20104 this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range)); 20105 this.list.addEventListener("scroll", () => { 20106 if (this.info) 20107 this.view.requestMeasure(this.placeInfo); 20108 }); 20109 } 20110 mount() { this.updateSel(); } 20111 update(update) { 20112 if (update.state.field(this.stateField) != update.startState.field(this.stateField)) 20113 this.updateSel(); 20114 } 20115 positioned() { 20116 if (this.info) 20117 this.view.requestMeasure(this.placeInfo); 20118 } 20119 updateSel() { 20120 let cState = this.view.state.field(this.stateField), open = cState.open; 20121 if (open.selected > -1 && open.selected < this.range.from || open.selected >= this.range.to) {
20122 this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions); 20123 this.list.remove(); 20124 this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range)); 20125 this.list.addEventListener("scroll", () => { 20126 if (this.info) 20127 this.view.requestMeasure(this.placeInfo); 20128 }); 20129 } 20130 if (this.updateSelectedOption(open.selected)) { 20131 if (this.info) { 20132 this.info.remove(); 20133 this.info = null; 20134 } 20135 let { completion } = open.options[open.selected]; 20136 let { info } = completion; 20137 if (!info) 20138 return; 20139 let infoResult = typeof info === 'string' ? document.createTextNode(info) : info(completion); 20140 if (!infoResult) 20141 return; 20142 if ('then' in infoResult) { 20143 infoResult.then(node => { 20144 if (node && this.view.state.field(this.stateField, false) == cState) 20145 this.addInfoPane(node); 20146 }).catch(e => logException(this.view.state, e, "completion info")); 20147 } 20148 else { 20149 this.addInfoPane(infoResult); 20150 } 20151 } 20152 } 20153 addInfoPane(content) { 20154 let dom = this.info = document.createElement("div"); 20155 dom.className = "cm-tooltip cm-completionInfo"; 20156 dom.appendChild(content); 20157 this.dom.appendChild(dom); 20158 this.view.requestMeasure(this.placeInfo); 20159 } 20160 updateSelectedOption(selected) { 20161 let set = null; 20162 for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) { 20163 if (i == selected) { 20164 if (!opt.hasAttribute("aria-selected")) { 20165 opt.setAttribute("aria-selected", "true"); 20166 set = opt; 20167 } 20168 } 20169 else { 20170 if (opt.hasAttribute("aria-selected")) 20171 opt.removeAttribute("aria-selected"); 20172 } 20173 } 20174 if (set) 20175 scrollIntoView(this.list, set); 20176 return set; 20177 } 20178 measureInfo() { 20179 let sel = this.dom.querySelector("[aria-selected]"); 20180 if (!sel || !this.info) 20181 return null; 20182 let win = this.dom.ownerDocument.defaultView || window; 20183 let listRect = this.dom.getBoundingClientRect(); 20184 let infoRect = this.info.getBoundingClientRect(); 20185 let selRect = sel.getBoundingClientRect(); 20186 if (selRect.top > Math.min(win.innerHeight, listRect.bottom) - 10 || selRect.bottom < Math.max(0, listRect.top) + 10) 20187 return null; 20188 let rtl = this.view.textDirection == Direction.RTL, left = rtl, narrow = false, maxWidth; 20189 let top = "", bottom = ""; 20190 let spaceLeft = listRect.left, spaceRight = win.innerWidth - listRect.right; 20191 if (left && spaceLeft < Math.min(infoRect.width, spaceRight)) 20192 left = false; 20193 else if (!left && spaceRight < Math.min(infoRect.width, spaceLeft)) 20194 left = true; 20195 if (infoRect.width <= (left ? spaceLeft : spaceRight)) { 20196 top = (Math.max(0, Math.min(selRect.top, win.innerHeight - infoRect.height)) - listRect.top) + "px"; 20197 maxWidth = Math.min(400 /* Info.Width */, left ? spaceLeft : spaceRight) + "px"; 20198 } 20199 else { 20200 narrow = true; 20201 maxWidth = Math.min(400 /* Info.Width */, (rtl ? listRect.right : win.innerWidth - listRect.left) - 30 /* Info.Margin */) + "px"; 20202 let spaceBelow = win.innerHeight - listRect.bottom; 20203 if (spaceBelow >= infoRect.height || spaceBelow > listRect.top) // Below the completion 20204 top = (selRect.bottom - listRect.top) + "px"; 20205 else // Above it 20206 bottom = (listRect.bottom - selRect.top) + "px"; 20207 } 20208 return { 20209 top, bottom, maxWidth, 20210 class: narrow ? (rtl ? "left-narrow" : "right-narrow") : left ? "left" : "right", 20211 }; 20212 } 20213 positionInfo(pos) { 20214 if (this.info) { 20215 if (pos) { 20216 this.info.style.top = pos.top; 20217 this.info.style.bottom = pos.bottom; 20218 this.info.style.maxWidth = pos.maxWidth; 20219 this.info.className = "cm-tooltip cm-completionInfo cm-completionInfo-"
20219+ pos.class; 20220 } 20221 else { 20222 this.info.style.top = "-1e6px"; 20223 } 20224 } 20225 } 20226 createListBox(options, id, range) { 20227 const ul = document.createElement("ul"); 20228 ul.id = id; 20229 ul.setAttribute("role", "listbox"); 20230 ul.setAttribute("aria-expanded", "true"); 20231 ul.setAttribute("aria-label", this.view.state.phrase("Completions")); 20232 for (let i = range.from; i < range.to; i++) { 20233 let { completion, match } = options[i]; 20234 const li = ul.appendChild(document.createElement("li")); 20235 li.id = id + "-" + i; 20236 li.setAttribute("role", "option"); 20237 let cls = this.optionClass(completion); 20238 if (cls) 20239 li.className = cls; 20240 for (let source of this.optionContent) { 20241 let node = source(completion, this.view.state, match); 20242 if (node) 20243 li.appendChild(node); 20244 } 20245 } 20246 if (range.from) 20247 ul.classList.add("cm-completionListIncompleteTop"); 20248 if (range.to < options.length) 20249 ul.classList.add("cm-completionListIncompleteBottom"); 20250 return ul; 20251 } 20252} 20253// We allocate a new function instance every time the completion 20254// changes to force redrawing/repositioning of the tooltip 20255function completionTooltip(stateField) { 20256 return (view) => new CompletionTooltip(view, stateField); 20257} 20258function scrollIntoView(container, element) { 20259 let parent = container.getBoundingClientRect(); 20260 let self = element.getBoundingClientRect(); 20261 if (self.top < parent.top) 20262 container.scrollTop -= parent.top - self.top; 20263 else if (self.bottom > parent.bottom) 20264 container.scrollTop += self.bottom - parent.bottom; 20265} 20266 20267// Used to pick a preferred option when two options with the same 20268// label occur in the result. 20269function score(option) { 20270 return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + 20271 (option.type ? 1 : 0); 20272} 20273function sortOptions(active, state) { 20274 let options = [], i = 0; 20275 for (let a of active) 20276 if (a.hasResult()) { 20277 if (a.result.filter === false) { 20278 let getMatch = a.result.getMatch; 20279 for (let option of a.result.options) { 20280 let match = [1e9 - i++]; 20281 if (getMatch) 20282 for (let n of getMatch(option)) 20283 match.push(n); 20284 options.push(new Option(option, a, match)); 20285 } 20286 } 20287 else { 20288 let matcher = new FuzzyMatcher(state.sliceDoc(a.from, a.to)), match; 20289 for (let option of a.result.options) 20290 if (match = matcher.match(option.label)) { 20291 if (option.boost != null) 20292 match[0] += option.boost; 20293 options.push(new Option(option, a, match)); 20294 } 20295 } 20296 } 20297 let result = [], prev = null; 20298 let compare = state.facet(completionConfig).compareCompletions; 20299 for (let opt of options.sort((a, b) => (b.match[0] - a.match[0]) || compare(a.completion, b.completion))) { 20300 if (!prev || prev.label != opt.completion.label || prev.detail != opt.completion.detail || 20301 (prev.type != null && opt.completion.type != null && prev.type != opt.completion.type) || 20302 prev.apply != opt.completion.apply) 20303 result.push(opt); 20304 else if (score(opt.completion) > score(prev)) 20305 result[result.length - 1] = opt; 20306 prev = opt.completion; 20307 } 20308 return result; 20309} 20310class CompletionDialog { 20311 constructor(options, attrs, tooltip, timestamp, selected) { 20312 this.options = options; 20313 this.attrs = attrs; 20314 this.tooltip = tooltip; 20315 this.timestamp = timestamp; 20316 this.selected = selected; 20317 } 20318 setSelected(selected, id) { 20319 return selected == this.selected || selected >= this.options.length ? this 20320 : new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected); 20321 } 20322 static build(active, state, id, prev, conf) { 20323 let options = sortOptions(active, state); 20324 if (!options.length) 20325 return null; 20326 let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1; 20327 if (prev && prev.selected != selected && prev.selected != -1) { 20328 let selectedValue = prev.options[prev.selected].completion; 20329 for (let i = 0; i < options.length; i++) 20330 if (options[i].completion == selectedValue) { 20331 selected = i; 20332 break; 20333 } 20334 } 20335 return new CompletionDialog(options, makeAttrs(id, selected), { 20336 pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8), 20337 create: completionTooltip(completionState), 20338 above: conf.aboveCursor, 20339 }, prev ? prev.timestamp : Date.now(), selected); 20340 } 20341 map(changes) { 20342 return new CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected); 20343 } 20344} 20345class CompletionState { 20346 constructor(active, id, open) { 20347 this.active = active; 20348 this.id = id; 20349 this.open = open; 20350 } 20351 static start() { 20352 return new CompletionState(none, "cm-ac-" + Math.floor(Math.random() * 2e6).toString(36), null); 20353 } 20354 update(tr) { 20355 let { state } = tr, conf = state.facet(completionConfig); 20356 let sources = conf.override || 20357 state.languageDataAt("autocomplete", cur(state)).map(asSource); 20358 let active = sources.map(source => { 20359 let value = this.active.find(s => s.source == source) || 20360 new ActiveSource(source, this.active.some(a => a.state != 0 /* State.Inactive */) ? 1 /* State.Pending */ : 0 /* State.Inactive */); 20361 return value.update(tr, conf); 20362 }); 20363 if (active.length == this.active.length && active.every((a, i) => a == this.active[i])) 20364 active = this.active; 20365 let open = tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || 20366 !sameResults(active, this.active) ? CompletionDialog.build(active, state, this.id, this.open, conf) 20367 : this.open && tr.docChanged ? this.open.map(tr.changes) : this.open; 20368 if (!open && active.every(a => a.state != 1 /* State.Pending */) && active.some(a => a.hasResult())) 20369 active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* State.Inactive */) : a); 20370 for (let effect of tr.effects) 20371 if (effect.is(setSelectedEffect)) 20372 open = open && open.setSelected(effect.value, this.id); 20373 return active == this.active && open == this.open ? this
20373: new CompletionState(active, this.id, open); 20374 } 20375 get tooltip() { return this.open ? this.open.tooltip : null; } 20376 get attrs() { return this.open ? this.open.attrs : baseAttrs; } 20377} 20378function sameResults(a, b) { 20379 if (a == b) 20380 return true; 20381 for (let iA = 0, iB = 0;;) { 20382 while (iA < a.length && !a[iA].hasResult) 20383 iA++; 20384 while (iB < b.length && !b[iB].hasResult) 20385 iB++; 20386 let endA = iA == a.length, endB = iB == b.length; 20387 if (endA || endB) 20388 return endA == endB; 20389 if (a[iA++].result != b[iB++].result) 20390 return false; 20391 } 20392} 20393const baseAttrs = { 20394 "aria-autocomplete": "list" 20395}; 20396function makeAttrs(id, selected) { 20397 let result = { 20398 "aria-autocomplete": "list", 20399 "aria-haspopup": "listbox", 20400 "aria-controls": id 20401 }; 20402 if (selected > -1) 20403 result["aria-activedescendant"] = id + "-" + selected; 20404 return result; 20405} 20406const none = []; 20407function getUserEvent(tr) { 20408 return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null; 20409} 20410class ActiveSource { 20411 constructor(source, state, explicitPos = -1) { 20412 this.source = source; 20413 this.state = state; 20414 this.explicitPos = explicitPos; 20415 } 20416 hasResult() { return false; } 20417 update(tr, conf) { 20418 let event = getUserEvent(tr), value = this; 20419 if (event) 20420 value = value.handleUserEvent(tr, event, conf); 20421 else if (tr.docChanged) 20422 value = value.handleChange(tr); 20423 else if (tr.selection && value.state != 0 /* State.Inactive */) 20424 value = new ActiveSource(value.source, 0 /* State.Inactive */); 20425 for (let effect of tr.effects) { 20426 if (effect.is(startCompletionEffect)) 20427 value = new ActiveSource(value.source, 1 /* State.Pending */, effect.value ? cur(tr.state) : -1); 20428 else if (effect.is(closeCompletionEffect)) 20429 value = new ActiveSource(value.source, 0 /* State.Inactive */); 20430 else if (effect.is(setActiveEffect)) 20431 for (let active of effect.value) 20432 if (active.source == value.source) 20433 value = active; 20434 } 20435 return value; 20436 } 20437 handleUserEvent(tr, type, conf) { 20438 return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* State.Pending */); 20439 } 20440 handleChange(tr) { 20441 return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes); 20442 } 20443 map(changes) { 20444 return changes.empty || this.explicitPos < 0 ? this : new ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos)); 20445 } 20446} 20447const startCompletionEffect = /*@__PURE__*/StateEffect.define(); 20448const closeCompletionEffect = /*@__PURE__*/StateEffect.define(); 20449const setActiveEffect = /*@__PURE__*/StateEffect.define({ 20450 map(sources, mapping) { return sources.map(s => s.map(mapping)); } 20451}); 20452const setSelectedEffect = /*@__PURE__*/StateEffect.define(); 20453const completionState = /*@__PURE__*/StateField.define({ 20454 create() { return CompletionState.start(); }, 20455 update(value, tr) { return value.update(tr); }, 20456 provide: f => [ 20457 showTooltip.from(f, val => val.tooltip), 20458 EditorView.contentAttributes.from(f, state => state.attrs) 20459 ] 20460}); 20461 20462/** 20463Returns a command that moves the completion selection forward or 20464backward by the given amount. 20465*/ 20466function moveCompletionSelection(forward, by = "option") { 20467 return (view) => { 20468 let cState = view.state.field(completionState, false); 20469 if (!cState || !cState.open || 20470 Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay) 20471 return false; 20472 let step = 1, tooltip; 20473 if (by == "page" && (tooltip = getTooltip(view, cState.open.tooltip))) 20474 step = Math.max(2, Math.floor(tooltip.dom.offsetHeight / 20475 tooltip.dom.querySelector("li").offsetHeight) - 1); 20476 let { length } = cState.open.options; 20477 let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1; 20478 if (selected < 0) 20479 selected = by == "page" ? 0 : length - 1; 20480 else if (selected >= length) 20481 selected = by == "page" ? length - 1 : 0; 20482 view.dispatch({ effects: setSelectedEffect.of(selected) }); 20483 return true; 20484 }; 20485} 20486/** 20487Accept the current completion. 20488*/ 20489const acceptCompletion = (view) => {
20490 let cState = view.state.field(completionState, false); 20491 if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 || 20492 Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay) 20493 return false; 20494 applyCompletion(view, cState.open.options[cState.open.selected]); 20495 return true; 20496}; 20497/** 20498Explicitly start autocompletion. 20499*/ 20500const startCompletion = (view) => { 20501 let cState = view.state.field(completionState, false); 20502 if (!cState) 20503 return false; 20504 view.dispatch({ effects: startCompletionEffect.of(true) }); 20505 return true; 20506}; 20507/** 20508Close the currently active completion. 20509*/ 20510const closeCompletion = (view) => { 20511 let cState = view.state.field(completionState, false); 20512 if (!cState || !cState.active.some(a => a.state != 0 /* State.Inactive */)) 20513 return false; 20514 view.dispatch({ effects: closeCompletionEffect.of(null) }); 20515 return true; 20516}; 20517 20518const baseTheme$1 = /*@__PURE__*/EditorView.baseTheme({ 20519 ".cm-tooltip.cm-tooltip-autocomplete": { 20520 "& > ul": { 20521 fontFamily: "monospace", 20522 whiteSpace: "nowrap", 20523 overflow: "hidden auto", 20524 maxWidth_fallback: "700px", 20525 maxWidth: "min(700px, 95vw)", 20526 minWidth: "250px", 20527 maxHeight: "10em", 20528 listStyle: "none", 20529 margin: 0, 20530 padding: 0, 20531 "& > li": { 20532 overflowX: "hidden", 20533 textOverflow: "ellipsis", 20534 cursor: "pointer", 20535 padding: "1px 3px", 20536 lineHeight: 1.2 20537 }, 20538 } 20539 }, 20540 "&light .cm-tooltip-autocomplete ul li[aria-selected]": { 20541 background: "#17c", 20542 color: "white", 20543 }, 20544 "&dark .cm-tooltip-autocomplete ul li[aria-selected]": { 20545 background: "#347", 20546 color: "white", 20547 }, 20548 ".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": { 20549 content: '"···"', 20550 opacity: 0.5, 20551 display: "block", 20552 textAlign: "center" 20553 }, 20554 ".cm-tooltip.cm-completionInfo": { 20555 position: "absolute", 20556 padding: "3px 9px", 20557 width: "max-content", 20558 maxWidth: `${400 /* Info.Width */}px`, 20559 boxSizing: "border-box" 20560 }, 20561 ".cm-completionInfo.cm-completionInfo-left": { right: "100%" }, 20562 ".cm-completionInfo.cm-completionInfo-right": { left: "100%" }, 20563 ".cm-completionInfo.cm-completionInfo-left-narrow": { right: `${30 /* Info.Margin */}px` }, 20564 ".cm-completionInfo.cm-completionInfo-right-narrow": { left: `${30 /* Info.Margin */}px` }, 20565 "&light .cm-snippetField": { backgroundColor: "#00000022" }, 20566 "&dark .cm-snippetField": { backgroundColor: "#ffffff22" }, 20567 ".cm-snippetFieldPosition": { 20568 verticalAlign: "text-top", 20569 width: 0, 20570 height: "1.15em", 20571 display: "inline-block", 20572 margin: "0 -0.7px -.7em", 20573 borderLeft: "1.4px dotted #888" 20574 }, 20575 ".cm-completionMatchedText": { 20576 textDecoration: "underline" 20577 }, 20578 ".cm-completionDetail": { 20579 marginLeft: "0.5em", 20580 fontStyle: "italic" 20581 }, 20582 ".cm-completionIcon": { 20583 fontSize: "90%", 20584 width: ".8em", 20585 display: "inline-block", 20586 textAlign: "center", 20587 paddingRight: ".6em", 20588 opacity: "0.6" 20589 }, 20590 ".cm-completionIcon-function, .cm-completionIcon-method": { 20591 "&:after": { content: "'Æ'" } 20592 }, 20593 ".cm-completionIcon-class": { 20594 "&:after": { content: "'â'" } 20595 }, 20596 ".cm-completionIcon-interface": { 20597 "&:after": { content: "'â'" } 20598 }, 20599 ".cm-completionIcon-variable": { 20600 "&:after": { content: "'ð¥'" } 20601 }, 20602 ".cm-completionIcon-constant": { 20603 "&:after": { content: "'ð¶'" } 20604 }, 20605 ".cm-completionIcon-type": { 20606 "&:after": { content: "'ð¡'" } 20607 }, 20608 ".cm-completionIcon-enum": { 20609 "&:after": { content: "'âª'" } 20610 }, 20611 ".cm-completionIcon-property": { 20612 "&:after": { content: "'â¡'" } 20613 }, 20614 ".cm-completionIcon-keyword": { 20615 "&:after": { content: "'ð\uFE0E'" } // Disable emoji rendering 20616 }, 20617 ".cm-completionIcon-namespace": { 20618 "&:after": { content: "'â¢'" } 20619 }, 20620 ".cm-completionIcon-text": { 20621 "&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" } 20622 } 20623}); 20624 20625class FieldPos { 20626 constructor(field, line, from, to) { 20627 this.field = field; 20628 this.line = line; 20629 this.from = from; 20630 this.to = to; 20631 } 20632} 20633class FieldRange { 20634 constructor(field, from, to) { 20635 this.field = field; 20636 this.from = from; 20637 this.to = to; 20638 } 20639 map(changes) { 20640 let from = changes.mapPos(this.from, -1, MapMode.TrackDel); 20641 let to = changes.mapPos(this.to, 1, MapMode.TrackDel); 20642 return from == null || to == null ? null : new FieldRange(this.field, from, to); 20643 } 20644} 20645class Snippet { 20646 constructor(lines, fieldPositions) { 20647 this.lines = lines; 20648 this.fieldPositions = fieldPositions; 20649 } 20650 instantiate(state, pos) { 20651 let text = [], lineStart = [pos]; 20652 let lineObj = state.doc.lineAt(pos), baseIndent = /^\s*/.exec(lineObj.text)[0]; 20653 for (let line of this.lines) { 20654 if (text.length) { 20655 let indent = baseIndent, tabs = /^\t*/.exec(line)[0].length; 20656 for (let i = 0; i < tabs; i++) 20657 indent += state.facet(indentUnit); 20658 lineStart.push(pos + indent.length - tabs); 20659 line = indent + line.slice(tabs); 20660 } 20661 text.push(line); 20662 pos += line.length + 1; 20663 } 20664 let ranges = this.fieldPositions.map(pos => new FieldRange(pos.field, lineStart[pos.line] + pos.from, lineStart[pos.line] + pos.to)); 20665 return { text, ranges }; 20666 } 20667 static parse(template) { 20668 let fields = []; 20669 let lines = [], positions = [], m; 20670 for (let line of template.split(/\r\n?|\n/)) { 20671 while (m = /[#$]\{(?:(\d+)(?::([^}]*))?|([^}]*))\}/.exec(line)) { 20672 let seq = m[1] ? +m[1] : null, name = m[2] || m[3] || "", found = -1; 20673 for (let i = 0; i < fields.length; i++) { 20674 if (seq != null ? fields[i].seq == seq : name ? fields[i].name == name : false) 20675 found = i; 20676 } 20677 if (found < 0) { 20678 let i = 0; 20679 while (i < fields.length && (seq == null || (fields[i].seq != null && fields[i].seq < seq))) 20680 i++; 20681 fields.splice(i, 0, { seq, name }); 20682 found = i; 20683 for (let pos of positions) 20684 if (pos.field >
20684= found) 20685 pos.field++; 20686 } 20687 positions.push(new FieldPos(found, lines.length, m.index, m.index + name.length)); 20688 line = line.slice(0, m.index) + name + line.slice(m.index + m[0].length); 20689 } 20690 for (let esc; esc = /([$#])\\{/.exec(line);) { 20691 line = line.slice(0, esc.index) + esc[1] + "{" + line.slice(esc.index + esc[0].length); 20692 for (let pos of positions) 20693 if (pos.line == lines.length && pos.from > esc.index) { 20694 pos.from--; 20695 pos.to--; 20696 } 20697 } 20698 lines.push(line); 20699 } 20700 return new Snippet(lines, positions); 20701 } 20702} 20703let fieldMarker = /*@__PURE__*/Decoration.widget({ widget: /*@__PURE__*/new class extends WidgetType { 20704 toDOM() { 20705 let span = document.createElement("span"); 20706 span.className = "cm-snippetFieldPosition"; 20707 return span; 20708 } 20709 ignoreEvent() { return false; } 20710 } }); 20711let fieldRange = /*@__PURE__*/Decoration.mark({ class: "cm-snippetField" }); 20712class ActiveSnippet { 20713 constructor(ranges, active) { 20714 this.ranges = ranges; 20715 this.active = active; 20716 this.deco = Decoration.set(ranges.map(r => (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to))); 20717 } 20718 map(changes) { 20719 let ranges = []; 20720 for (let r of this.ranges) { 20721 let mapped = r.map(changes); 20722 if (!mapped) 20723 return null; 20724 ranges.push(mapped); 20725 } 20726 return new ActiveSnippet(ranges, this.active); 20727 } 20728 selectionInsideField(sel) { 20729 return sel.ranges.every(range => this.ranges.some(r => r.field == this.active && r.from <= range.from && r.to >= range.to)); 20730 } 20731} 20732const setActive = /*@__PURE__*/StateEffect.define({ 20733 map(value, changes) { return value && value.map(changes); } 20734}); 20735const moveToField = /*@__PURE__*/StateEffect.define(); 20736const snippetState = /*@__PURE__*/StateField.define({ 20737 create() { return null; }, 20738 update(value, tr) { 20739 for (let effect of tr.effects) { 20740 if (effect.is(setActive)) 20741 return effect.value; 20742 if (effect.is(moveToField) && value) 20743 return new ActiveSnippet(value.ranges, effect.value); 20744 } 20745 if (value && tr.docChanged) 20746 value = value.map(tr.changes); 20747 if (value && tr.selection && !value.selectionInsideField(tr.selection)) 20748 value = null; 20749 return value; 20750 }, 20751 provide: f => EditorView.decorations.from(f, val => val ? val.deco : Decoration.none) 20752}); 20753function fieldSelection(ranges, field) { 20754 return EditorSelection.create(ranges.filter(r => r.field == field).map(r => EditorSelection.range(r.from, r.to))); 20755} 20756/** 20757Convert a snippet template to a function that can 20758[apply](https://codemirror.net/6/docs/ref/#autocomplete.Completion.apply) it. Snippets are written 20759using syntax like this: 20760 20761 "for (let ${index} = 0; ${index} < ${end}; ${index}++) {\n\t${}\n}" 20762 20763Each `${}` placeholder (you may also use `#{}`) indicates a field 20764that the user can fill in. Its name, if any, will be the default 20765content for the field. 20766 20767When the snippet is activated by calling the returned function, 20768the code is inserted at the given position. Newlines in the 20769template are indented by the indentation of the start line, plus 20770one [indent unit](https://codemirror.net/6/docs/ref/#language.indentUnit) per tab character after 20771the newline. 20772 20773On activation, (all instances of) the first field are selected. 20774The user can move between fields with Tab and Shift-Tab as long as 20775the fields are active. Moving to the last field or moving the 20776cursor out of the current field deactivates the fields. 20777 20778The order of fields defaults to textual order, but you can add 20779numbers to placeholders (`${1}` or `${1:defaultText}`) to provide 20780a custom order. 20781 20782To include a literal `${` or `#{` in your template, put a 20783backslash after the dollar or hash and before the brace (`$\\{`). 20784This will be removed and the sequence will not be interpreted as a 20785placeholder. 20786*/ 20787function snippet(template) { 20788 let snippet = Snippet.parse(template); 20789 return (editor, _completion, from, to) => { 20790 let { text, ranges } = snippet.instantiate(editor.state, from); 20791 let spec = { 20792 changes: { from, to, insert: Text.of(text) }, 20793 scrollIntoView: true 20794 }; 20795 if (ranges.length) 20796 spec.selection = fieldSelection(ranges, 0); 20797 if (ranges.length > 1) { 20798 let active = new ActiveSnippet(ranges, 0); 20799 let effects = spec.effects = [setActive.of(active)]; 20800 if (editor.state.field(snippetState, false) === undefined)
vendor: 1,880 bytes, lines 20801-20850
20801 effects.push(StateEffect.appendConfig.of([snippetState, addSnippetKeymap, snippetPointerHandler, baseTheme$1])); 20802 } 20803 editor.dispatch(editor.state.update(spec)); 20804 }; 20805} 20806function moveField(dir) { 20807 return ({ state, dispatch }) => { 20808 let active = state.field(snippetState, false); 20809 if (!active || dir < 0 && active.active == 0) 20810 return false; 20811 let next = active.active + dir, last = dir > 0 && !active.ranges.some(r => r.field == next + dir); 20812 dispatch(state.update({ 20813 selection: fieldSelection(active.ranges, next), 20814 effects: setActive.of(last ? null : new ActiveSnippet(active.ranges, next)) 20815 })); 20816 return true; 20817 }; 20818} 20819/** 20820A command that clears the active snippet, if any. 20821*/ 20822const clearSnippet = ({ state, dispatch }) => { 20823 let active = state.field(snippetState, false); 20824 if (!active) 20825 return false; 20826 dispatch(state.update({ effects: setActive.of(null) })); 20827 return true; 20828}; 20829/** 20830Move to the next snippet field, if available. 20831*/ 20832const nextSnippetField = /*@__PURE__*/moveField(1); 20833/** 20834Move to the previous snippet field, if available. 20835*/ 20836const prevSnippetField = /*@__PURE__*/moveField(-1); 20837const defaultSnippetKeymap = [ 20838 { key: "Tab", run: nextSnippetField, shift: prevSnippetField }, 20839 { key: "Escape", run: clearSnippet } 20840]; 20841/** 20842A facet that can be used to configure the key bindings used by 20843snippets. The default binds Tab to 20844[`nextSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.nextSnippetField), Shift-Tab to 20845[`prevSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.prevSnippetField), and Escape 20846to [`clearSnippet`](https://codemirror.net/6/docs/ref/#autocomplete.clearSnippet). 20847*/ 20848const snippetKeymap = /*@__PURE__*/Facet.define({ 20849 combine(maps) { return maps.length ? maps[0] : defaultSnippetKeymap; } 20850});
20851const addSnippetKeymap = /*@__PURE__*/Prec.highest(/*@__PURE__*/keymap.compute([snippetKeymap], state => state.facet(snippetKeymap))); 20852/** 20853Create a completion from a snippet. Returns an object with the 20854properties from `completion`, plus an `apply` function that 20855applies the snippet. 20856*/ 20857function snippetCompletion(template, completion) { 20858 return Object.assign(Object.assign({}, completion), { apply: snippet(template) }); 20859} 20860const snippetPointerHandler = /*@__PURE__*/EditorView.domEventHandlers({ 20861 mousedown(event, view) { 20862 let active = view.state.field(snippetState, false), pos; 20863 if (!active || (pos = view.posAtCoords({ x: event.clientX, y: event.clientY })) == null) 20864 return false; 20865 let match = active.ranges.find(r => r.from <= pos && r.to >= pos); 20866 if (!match || match.field == active.active) 20867 return false; 20868 view.dispatch({ 20869 selection: fieldSelection(active.ranges, match.field), 20870 effects: setActive.of(active.ranges.some(r => r.field > match.field) ? new ActiveSnippet(active.ranges, match.field) : null) 20871 }); 20872 return true; 20873 } 20874}); 20875 20876const defaults = { 20877 brackets: ["(", "[", "{", "'", '"'], 20878 before: ")]}:;>", 20879 stringPrefixes: [] 20880}; 20881const closeBracketEffect = /*@__PURE__*/StateEffect.define({ 20882 map(value, mapping) { 20883 let mapped = mapping.mapPos(value, -1, MapMode.TrackAfter); 20884 return mapped == null ? undefined : mapped; 20885 } 20886}); 20887const skipBracketEffect = /*@__PURE__*/StateEffect.define({ 20888 map(value, mapping) { return mapping.mapPos(value); } 20889}); 20890const closedBracket = /*@__PURE__*/new class extends RangeValue { 20891}; 20892closedBracket.startSide = 1; 20893closedBracket.endSide = -1; 20894const bracketState = /*@__PURE__*/StateField.define({ 20895 create() { return RangeSet.empty; }, 20896 update(value, tr) { 20897 if (tr.selection) { 20898 let lineStart = tr.state.doc.lineAt(tr.selection.main.head).from; 20899 let prevLineStart = tr.startState.doc.lineAt(tr.startState.selection.main.head).from; 20900 if (lineStart != tr.changes.mapPos(prevLineStart, -1)) 20901 value = RangeSet.empty; 20902 } 20903 value = value.map(tr.changes); 20904 for (let effect of tr.effects) { 20905 if (effect.is(closeBracketEffect)) 20906 value = value.update({ add: [closedBracket.range(effect.value, effect.value + 1)] }); 20907 else if (effect.is(skipBracketEffect)) 20908 value = value.update({ filter: from => from != effect.value }); 20909 } 20910 return value; 20911 } 20912}); 20913/** 20914Extension to enable bracket-closing behavior. When a closeable 20915bracket is typed, its closing bracket is immediately inserted 20916after the cursor. When closing a bracket directly in front of a 20917closing bracket inserted by the extension, the cursor moves over 20918that bracket. 20919*/ 20920function closeBrackets() { 20921 return [inputHandler, bracketState]; 20922} 20923const definedClosing = "()[]{}<>"; 20924function closing(ch) { 20925 for (let i = 0; i < definedClosing.length; i += 2) 20926 if (definedClosing.charCodeAt(i) == ch) 20927 return definedClosing.charAt(i + 1); 20928 return fromCodePoint(ch < 128 ? ch : ch + 1); 20929} 20930function config(state, pos) { 20931 return state.languageDataAt("closeBrackets", pos)[0] || defaults; 20932} 20933const android = typeof navigator == "object" && /*@__PURE__*//Android\b/.test(navigator.userAgent); 20934const inputHandler = /*@__PURE__*/EditorView.inputHandler.of((view, from, to, insert) => { 20935 if ((android ? view.composing : view.compositionStarted) || view.state.readOnly) 20936 return false; 20937 let sel = view.state.selection.main; 20938 if (insert.length > 2 || insert.length == 2 && codePointSize(codePointAt(insert, 0)) == 1 || 20939 from != sel.from || to != sel.to) 20940 return false; 20941 let tr = insertBracket(view.state, insert); 20942 if (!tr) 20943 return false; 20944 view.dispatch(tr); 20945 return true; 20946}); 20947/** 20948Command that implements deleting a pair of matching brackets when 20949the cursor is between them. 20950*/ 20951const deleteBracketPair = ({ state, dispatch }) => { 20952 if (state.readOnly) 20953 return false;
20954 let conf = config(state, state.selection.main.head); 20955 let tokens = conf.brackets || defaults.brackets; 20956 let dont = null, changes = state.changeByRange(range => { 20957 if (range.empty) { 20958 let before = prevChar(state.doc, range.head); 20959 for (let token of tokens) { 20960 if (token == before && nextChar(state.doc, range.head) == closing(codePointAt(token, 0))) 20961 return { changes: { from: range.head - token.length, to: range.head + token.length }, 20962 range: EditorSelection.cursor(range.head - token.length) }; 20963 } 20964 } 20965 return { range: dont = range }; 20966 }); 20967 if (!dont) 20968 dispatch(state.update(changes, { scrollIntoView: true, userEvent: "delete.backward" })); 20969 return !dont; 20970}; 20971/** 20972Close-brackets related key bindings. Binds Backspace to 20973[`deleteBracketPair`](https://codemirror.net/6/docs/ref/#autocomplete.deleteBracketPair). 20974*/ 20975const closeBracketsKeymap = [ 20976 { key: "Backspace", run: deleteBracketPair } 20977]; 20978/** 20979Implements the extension's behavior on text insertion. If the 20980given string counts as a bracket in the language around the 20981selection, and replacing the selection with it requires custom 20982behavior (inserting a closing version or skipping past a 20983previously-closed bracket), this function returns a transaction 20984representing that custom behavior. (You only need this if you want 20985to programmatically insert bracketsâthe 20986[`closeBrackets`](https://codemirror.net/6/docs/ref/#autocomplete.closeBrackets) extension will 20987take care of running this for user input.) 20988*/ 20989function insertBracket(state, bracket) { 20990 let conf = config(state, state.selection.main.head); 20991 let tokens = conf.brackets || defaults.brackets; 20992 for (let tok of tokens) { 20993 let closed = closing(codePointAt(tok, 0)); 20994 if (bracket == tok) 20995 return closed == tok ? handleSame(state, tok, tokens.indexOf(tok + tok + tok) > -1, conf) 20996 : handleOpen(state, tok, closed, conf.before || defaults.before); 20997 if (bracket == closed && closedBracketAt(state, state.selection.main.from)) 20998 return handleClose(state, tok, closed); 20999 } 21000 return null; 21001} 21002function closedBracketAt(state, pos) { 21003 let found = false; 21004 state.field(bracketState).between(0, state.doc.length, from => { 21005 if (from == pos) 21006 found = true; 21007 }); 21008 return found; 21009} 21010function nextChar(doc, pos) { 21011 let next = doc.sliceString(pos, pos + 2); 21012 return next.slice(0, codePointSize(codePointAt(next, 0))); 21013} 21014function prevChar(doc, pos) { 21015 let prev = doc.sliceString(pos - 2, pos); 21016 return codePointSize(codePointAt(prev, 0)) == prev.length ? prev : prev.slice(1); 21017} 21018function handleOpen(state, open, close, closeBefore) { 21019 let dont = null, changes = state.changeByRange(range => { 21020 if (!range.empty) 21021 return { changes: [{ insert: open, from: range.from }, { insert: close, from: range.to }], 21022 effects: closeBracketEffect.of(range.to + open.length), 21023 range: EditorSelection.range(range.anchor + open.length, range.head + open.length) }; 21024 let next = nextChar(state.doc, range.head); 21025 if (!next || /\s/.test(next) || closeBefore.indexOf(next) > -1) 21026 return { changes: { insert: open + close, from: range.head }, 21027 effects: closeBracketEffect.of(range.head + open.length), 21028 range: EditorSelection.cursor(range.head + open.length) }; 21029 return { range: dont = range }; 21030 }); 21031 return dont ? null : state.update(changes, { 21032 scrollIntoView: true, 21033 userEvent: "input.type" 21034 }); 21035} 21036function handleClose(state, _open, close) { 21037 let dont = null, moved = state.selection.ranges.map(range => { 21038 if (range.empty && nextChar(state.doc, range.head) == close) 21039 return EditorSelection.cursor(range.head + close.length); 21040 return dont = range; 21041 }); 21042 return dont ? null : state.update({ 21043 selection: EditorSelection.create(moved, state.selection.mainIndex), 21044 scrollIntoView: true, 21045 effects: state.selection.ranges.map(({ from }) => skipBracketEffect.of(from)) 21046 }); 21047} 21048// Handles cases where the open and close token are the same, and 21049// possibly triple quotes (as in `"""abc"""`-style quoting). 21050function handleSame(state, token, allowTriple, config) { 21051 let stringPrefixes = config.stringPrefixes || defaults.stringPrefixes; 21052 let dont = null, changes = state.changeByRange(range => { 21053 if (!range.empty) 21054 return { changes: [{ insert: token, from: range.from }, { insert: token, from: range.to }], 21055 effects: closeBracketEffect.of(range.to + token.length), 21056 range: EditorSelection.range(range.anchor + token.length, range.head + token.length) }; 21057 let pos = range.head, next = nextChar(state.doc, pos), start; 21058 if (next == token) { 21059 if (nodeStart(state, pos)) { 21060 return { changes: { insert: token + token, from: pos }, 21061 effects: closeBracketEffect.of(pos + token.length), 21062 range: EditorSelection.cursor(pos + token.length) }; 21063 } 21064 else if (closedBracketAt(state, pos)) { 21065 let isTriple = allowTriple && state.sliceDoc(pos, pos + token.length * 3) == token + token + token; 21066 return { range: EditorSelection.cursor(pos + token.length * (isTriple ? 3 : 1)), 21067 effects: skipBracketEffect.of(pos) }; 21068 } 21069 } 21070 else if (allowTriple && state.sliceDoc(pos - 2 * token.length, pos) == token + token && 21071 (start = canStartStringAt(state, pos - 2 * token.length, stringPrefixes
vendor: 2,044 bytes, lines 21071-21116
21071)) > -1 && 21072 nodeStart(state, start)) { 21073 return { changes: { insert: token + token + token + token, from: pos }, 21074 effects: closeBracketEffect.of(pos + token.length), 21075 range: EditorSelection.cursor(pos + token.length) }; 21076 } 21077 else if (state.charCategorizer(pos)(next) != CharCategory.Word) { 21078 if (canStartStringAt(state, pos, stringPrefixes) > -1 && !probablyInString(state, pos, token, stringPrefixes)) 21079 return { changes: { insert: token + token, from: pos }, 21080 effects: closeBracketEffect.of(pos + token.length), 21081 range: EditorSelection.cursor(pos + token.length) }; 21082 } 21083 return { range: dont = range }; 21084 }); 21085 return dont ? null : state.update(changes, { 21086 scrollIntoView: true, 21087 userEvent: "input.type" 21088 }); 21089} 21090function nodeStart(state, pos) { 21091 let tree = syntaxTree(state).resolveInner(pos + 1); 21092 return tree.parent && tree.from == pos; 21093} 21094function probablyInString(state, pos, quoteToken, prefixes) { 21095 let node = syntaxTree(state).resolveInner(pos, -1); 21096 let maxPrefix = prefixes.reduce((m, p) => Math.max(m, p.length), 0); 21097 for (let i = 0; i < 5; i++) { 21098 let start = state.sliceDoc(node.from, Math.min(node.to, node.from + quoteToken.length + maxPrefix)); 21099 let quotePos = start.indexOf(quoteToken); 21100 if (!quotePos || quotePos > -1 && prefixes.indexOf(start.slice(0, quotePos)) > -1) { 21101 let first = node.firstChild; 21102 while (first && first.from == node.from && first.to - first.from > quoteToken.length + quotePos) { 21103 if (state.sliceDoc(first.to - quoteToken.length, first.to) == quoteToken) 21104 return false; 21105 first = first.firstChild; 21106 } 21107 return true; 21108 } 21109 let parent = node.to == pos && node.parent; 21110 if (!parent) 21111 break; 21112 node = parent; 21113 } 21114 return false; 21115} 21116function canStartStringAt(state, pos, prefixes) {
21117 let charCat = state.charCategorizer(pos); 21118 if (charCat(state.sliceDoc(pos - 1, pos)) != CharCategory.Word) 21119 return pos; 21120 for (let prefix of prefixes) { 21121 let start = pos - prefix.length; 21122 if (state.sliceDoc(start, pos) == prefix && charCat(state.sliceDoc(start - 1, start)) != CharCategory.Word) 21123 return start; 21124 } 21125 return -1; 21126} 21127/** 21128Basic keybindings for autocompletion. 21129 21130 - Ctrl-Space: [`startCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.startCompletion) 21131 - Escape: [`closeCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.closeCompletion) 21132 - ArrowDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true)` 21133 - ArrowUp: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(false)` 21134 - PageDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true, "page")` 21135 - PageDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true, "page")` 21136 - Enter: [`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion) 21137*/ 21138const completionKeymap = [ 21139 { key: "Ctrl-Space", run: startCompletion }, 21140 { key: "Escape", run: closeCompletion }, 21141 { key: "ArrowDown", run: /*@__PURE__*/moveCompletionSelection(true) }, 21142 { key: "ArrowUp", run: /*@__PURE__*/moveCompletionSelection(false) }, 21143 { key: "PageDown", run: /*@__PURE__*/moveCompletionSelection(true, "page") }, 21144 { key: "PageUp", run: /*@__PURE__*/moveCompletionSelection(false, "page") }, 21145 { key: "Enter", run: acceptCompletion } 21146]; 21147 21148function crelt() { 21149 var elt = arguments[0]; 21150 if (typeof elt == "string") elt = document.createElement(elt); 21151 var i = 1, next = arguments[1]; 21152 if (next && typeof next == "object" && next.nodeType == null && !Array.isArray(next)) { 21153 for (var name in next) if (Object.prototype.hasOwnProperty.call(next, name)) { 21154 var value = next[name]; 21155 if (typeof value == "string") elt.setAttribute(name, value); 21156 else if (value != null) elt[name] = value; 21157 } 21158 i++; 21159 } 21160 for (; i < arguments.length; i++) add(elt, arguments[i]); 21161 return elt 21162} 21163 21164function add(elt, child) { 21165 if (typeof child == "string") { 21166 elt.appendChild(document.createTextNode(child)); 21167 } else if (child == null) ; else if (child.nodeType != null) { 21168 elt.appendChild(child); 21169 } else if (Array.isArray(child)) { 21170 for (var i = 0; i < child.length; i++) add(elt, child[i]); 21171 } else { 21172 throw new RangeError("Unsupported child node: " + child) 21173 } 21174} 21175 21176class SelectedDiagnostic { 21177 constructor(from, to, diagnostic) { 21178 this.from = from; 21179 this.to = to; 21180 this.diagnostic = diagnostic; 21181 } 21182} 21183class LintState { 21184 constructor(diagnostics, panel, selected) { 21185 this.diagnostics = diagnostics; 21186 this.panel = panel; 21187 this.selected = selected; 21188 } 21189 static init(diagnostics, panel, state) { 21190 // Filter the list of diagnostics for which to create markers 21191 let markedDiagnostics = diagnostics; 21192 let diagnosticFilter = state.facet(lintConfig).markerFilter; 21193 if (diagnosticFilter) 21194 markedDiagnostics = diagnosticFilter(markedDiagnostics); 21195 let ranges = Decoration.set(markedDiagnostics.map((d) => { 21196 // For zero-length ranges or ranges covering only a line break, create a widget 21197 return d.from == d.to || (d.from == d.to - 1 && state.doc.lineAt(d.from).to == d.from) 21198 ? Decoration.widget({ 21199 widget: new DiagnosticWidget(d), 21200 diagnostic: d 21201 }).range(d.from) 21202 : Decoration.mark({ 21203 attributes: { class: "cm-lintRange cm-lintRange-" + d.severity }, 21204 diagnostic: d 21205 }).range(d.from, d.to); 21206 }), true); 21207 return new LintState(ranges, panel, findDiagnostic(ranges)); 21208 } 21209} 21210function findDiagnostic(diagnostics, diagnostic = null, after = 0) { 21211 let found = null; 21212 diagnostics.between(after, 1e9, (from, to, { spec }) => { 21213 if (diagnostic && spec.diagnostic != diagnostic) 21214 return; 21215 found = new SelectedDiagnostic(from, to, spec.diagnostic); 21216 return false;
21217 }); 21218 return found; 21219} 21220function hideTooltip(tr, tooltip) { 21221 return !!(tr.effects.some(e => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(tooltip.pos)); 21222} 21223function maybeEnableLint(state, effects) { 21224 return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of([ 21225 lintState, 21226 EditorView.decorations.compute([lintState], state => { 21227 let { selected, panel } = state.field(lintState); 21228 return !selected || !panel || selected.from == selected.to ? Decoration.none : Decoration.set([ 21229 activeMark.range(selected.from, selected.to) 21230 ]); 21231 }), 21232 hoverTooltip(lintTooltip, { hideOn: hideTooltip }), 21233 baseTheme 21234 ])); 21235} 21236/** 21237Returns a transaction spec which updates the current set of 21238diagnostics, and enables the lint extension if if wasn't already 21239active. 21240*/ 21241function setDiagnostics(state, diagnostics) { 21242 return { 21243 effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)]) 21244 }; 21245} 21246/** 21247The state effect that updates the set of active diagnostics. Can 21248be useful when writing an extension that needs to track these. 21249*/ 21250const setDiagnosticsEffect = /*@__PURE__*/StateEffect.define(); 21251const togglePanel = /*@__PURE__*/StateEffect.define(); 21252const movePanelSelection = /*@__PURE__*/StateEffect.define(); 21253const lintState = /*@__PURE__*/StateField.define({ 21254 create() { 21255 return new LintState(Decoration.none, null, null); 21256 }, 21257 update(value, tr) { 21258 if (tr.docChanged) { 21259 let mapped = value.diagnostics.map(tr.changes), selected = null; 21260 if (value.selected) { 21261 let selPos = tr.changes.mapPos(value.selected.from, 1); 21262 selected = findDiagnostic(mapped, value.selected.diagnostic, selPos) || findDiagnostic(mapped, null, selPos); 21263 } 21264 value = new LintState(mapped, value.panel, selected); 21265 } 21266 for (let effect of tr.effects) { 21267 if (effect.is(setDiagnosticsEffect)) { 21268 value = LintState.init(effect.value, value.panel, tr.state); 21269 } 21270 else if (effect.is(togglePanel)) { 21271 value = new LintState(value.diagnostics, effect.value ? LintPanel.open : null, value.selected); 21272 } 21273 else if (effect.is(movePanelSelection)) { 21274 value = new LintState(value.diagnostics, value.panel, effect.value); 21275 } 21276 } 21277 return value; 21278 }, 21279 provide: f => [showPanel.from(f, val => val.panel), 21280 EditorView.decorations.from(f, s => s.diagnostics)] 21281}); 21282const activeMark = /*@__PURE__*/Decoration.mark({ class: "cm-lintRange cm-lintRange-active" }); 21283function lintTooltip(view, pos, side) { 21284 let { diagnostics } = view.state.field(lintState); 21285 let found = [], stackStart = 2e8, stackEnd = 0; 21286 diagnostics.between(pos - (side < 0 ? 1 : 0), pos + (side > 0 ? 1 : 0), (from, to, { spec }) => { 21287 if (pos >= from && pos <= to && 21288 (from == to || ((pos > from || side > 0) && (pos < to || side < 0)))) { 21289 found.push(spec.diagnostic); 21290 stackStart = Math.min(from, stackStart); 21291 stackEnd = Math.max(to, stackEnd); 21292 } 21293 }); 21294 let diagnosticFilter = view.state.facet(lintConfig).tooltipFilter; 21295 if (diagnosticFilter) 21296 found = diagnosticFilter(found); 21297 if (!found.length) 21298 return null; 21299 return { 21300 pos: stackStart, 21301 end: stackEnd, 21302 above: view.state.doc.lineAt(stackStart).to < stackEnd, 21303 create() { 21304 return { dom: diagnosticsTooltip(view, found) }; 21305 } 21306 }; 21307} 21308function diagnosticsTooltip(view, diagnostics) { 21309 return crelt("ul", { class: "cm-tooltip-lint" }, diagnostics.map(d => renderDiagnostic(view, d, false))); 21310} 21311/** 21312Command to open and focus the lint panel. 21313*/ 21314const openLintPanel = (view) => { 21315 let field = view.state.field(lintState, false); 21316 if (!field || !field.panel) 21317 view.dispatch({ effects: maybeEnableLint(view.state, [togglePanel.of(true)]) }); 21318 let panel = getPanel(view, LintPanel.open); 21319 if (panel) 21320 panel.dom.querySelector(".cm-panel-lint ul").focus(); 21321 return true; 21322}; 21323/** 21324Command to close the lint panel, when open. 21325*/ 21326const closeLintPanel = (view) => { 21327 let field = view.state.field(lintState, false); 21328 if (!field || !field.panel) 21329 return false;
21330 view.dispatch({ effects: togglePanel.of(false) }); 21331 return true; 21332}; 21333/** 21334Move the selection to the next diagnostic. 21335*/ 21336const nextDiagnostic = (view) => { 21337 let field = view.state.field(lintState, false); 21338 if (!field) 21339 return false; 21340 let sel = view.state.selection.main, next = field.diagnostics.iter(sel.to + 1); 21341 if (!next.value) { 21342 next = field.diagnostics.iter(0); 21343 if (!next.value || next.from == sel.from && next.to == sel.to) 21344 return false; 21345 } 21346 view.dispatch({ selection: { anchor: next.from, head: next.to }, scrollIntoView: true }); 21347 return true; 21348}; 21349/** 21350A set of default key bindings for the lint functionality. 21351 21352- Ctrl-Shift-m (Cmd-Shift-m on macOS): [`openLintPanel`](https://codemirror.net/6/docs/ref/#lint.openLintPanel) 21353- F8: [`nextDiagnostic`](https://codemirror.net/6/docs/ref/#lint.nextDiagnostic) 21354*/ 21355const lintKeymap = [ 21356 { key: "Mod-Shift-m", run: openLintPanel }, 21357 { key: "F8", run: nextDiagnostic } 21358]; 21359const lintPlugin = /*@__PURE__*/ViewPlugin.fromClass(class { 21360 constructor(view) { 21361 this.view = view; 21362 this.timeout = -1; 21363 this.set = true; 21364 let { delay } = view.state.facet(lintConfig); 21365 this.lintTime = Date.now() + delay; 21366 this.run = this.run.bind(this); 21367 this.timeout = setTimeout(this.run, delay); 21368 } 21369 run() { 21370 let now = Date.now(); 21371 if (now < this.lintTime - 10) { 21372 setTimeout(this.run, this.lintTime - now); 21373 } 21374 else { 21375 this.set = false; 21376 let { state } = this.view, { sources } = state.facet(lintConfig); 21377 Promise.all(sources.map(source => Promise.resolve(source(this.view)))).then(annotations => { 21378 let all = annotations.reduce((a, b) => a.concat(b)); 21379 if (this.view.state.doc == state.doc) 21380 this.view.dispatch(setDiagnostics(this.view.state, all)); 21381 }, error => { logException(this.view.state, error); }); 21382 } 21383 } 21384 update(update) { 21385 let config = update.state.facet(lintConfig); 21386 if (update.docChanged || config != update.startState.facet(lintConfig)) { 21387 this.lintTime = Date.now() + config.delay; 21388 if (!this.set) { 21389 this.set = true; 21390 this.timeout = setTimeout(this.run, config.delay); 21391 } 21392 } 21393 } 21394 force() { 21395 if (this.set) { 21396 this.lintTime = Date.now(); 21397 this.run(); 21398 } 21399 } 21400 destroy() { 21401 clearTimeout(this.timeout); 21402 } 21403}); 21404const lintConfig = /*@__PURE__*/Facet.define({ 21405 combine(input) { 21406 return Object.assign({ sources: input.map(i => i.source) }, combineConfig(input.map(i => i.config), { 21407 delay: 750, 21408 markerFilter: null, 21409 tooltipFilter: null 21410 })); 21411 }, 21412 enables: lintPlugin 21413}); 21414function assignKeys(actions) { 21415 let assigned = []; 21416 if (actions) 21417 actions: for (let { name } of actions) { 21418 for (let i = 0; i < name.length; i++) { 21419 let ch = name[i]; 21420 if (/[a-zA-Z]/.test(ch) && !assigned.some(c => c.toLowerCase() == ch.toLowerCase())) { 21421 assigned.push(ch); 21422 continue actions; 21423 } 21424 } 21425 assigned.push(""); 21426 } 21427 return assigned; 21428} 21429function renderDiagnostic(view, diagnostic, inPanel) { 21430 var _a; 21431 let keys = inPanel ? assignKeys(diagnostic.actions) : []; 21432 return crelt("li", { class: "cm-diagnostic cm-diagnostic-" + diagnostic.severity }, crelt("span", { class: "cm-diagnosticText" }, diagnostic.renderMessage ? diagnostic.renderMessage() : diagnostic.message), (_a = diagnostic.actions) === null || _a === void 0 ? void 0 : _a.map((action, i) => { 21433 let click = (e) => { 21434 e.preventDefault(); 21435 let found = findDiagnostic(view.state.field(lintState).diagnostics, diagnostic); 21436 if (found) 21437 action.apply(view, found.from, found.to); 21438 }; 21439 let { name } = action, keyIndex = keys[i] ? name.indexOf(keys[i]) : -1; 21440 let nameElt = keyIndex < 0 ? name : [name.slice(0, keyIndex), 21441 crelt("u", name.slice(keyIndex, keyIndex + 1)), 21442 name.slice(keyIndex + 1)]; 21443 return crelt("button", { 21444 type: "button", 21445 class: "cm-diagnosticAction", 21446 onclick: click, 21447 onmousedown: click, 21448 "aria-label": ` Action: ${name}${keyIndex < 0 ? "" : ` (access key "${keys[i]})"`}.` 21449 }, nameElt); 21450 }), diagnostic.source && crelt("div", { class: "cm-diagnosticSource" }, diagnostic.source)); 21451} 21452class DiagnosticWidget extends WidgetType { 21453 constructor(diagnostic) { 21454 super(); 21455 this.diagnostic = diagnostic; 21456 } 21457 eq(other) { return other.diagnostic == this.diagnostic; } 21458 toDOM() { 21459 return crelt("span", { class: "cm-lintPoint cm-lintPoint-" + this.diagnostic.severity }); 21460 } 21461} 21462class PanelItem { 21463 constructor(view, diagnostic) { 21464 this.diagnostic = diagnostic; 21465 this.id = "item_" + Math.floor(Math.random() * 0xffffffff).toString(16);
vendor: 7,048 bytes, lines 21466-21646
21466 this.dom = renderDiagnostic(view, diagnostic, true); 21467 this.dom.id = this.id; 21468 this.dom.setAttribute("role", "option"); 21469 } 21470} 21471class LintPanel { 21472 constructor(view) { 21473 this.view = view; 21474 this.items = []; 21475 let onkeydown = (event) => { 21476 if (event.keyCode == 27) { // Escape 21477 closeLintPanel(this.view); 21478 this.view.focus(); 21479 } 21480 else if (event.keyCode == 38 || event.keyCode == 33) { // ArrowUp, PageUp 21481 this.moveSelection((this.selectedIndex - 1 + this.items.length) % this.items.length); 21482 } 21483 else if (event.keyCode == 40 || event.keyCode == 34) { // ArrowDown, PageDown 21484 this.moveSelection((this.selectedIndex + 1) % this.items.length); 21485 } 21486 else if (event.keyCode == 36) { // Home 21487 this.moveSelection(0); 21488 } 21489 else if (event.keyCode == 35) { // End 21490 this.moveSelection(this.items.length - 1); 21491 } 21492 else if (event.keyCode == 13) { // Enter 21493 this.view.focus(); 21494 } 21495 else if (event.keyCode >= 65 && event.keyCode <= 90 && this.selectedIndex >= 0) { // A-Z 21496 let { diagnostic } = this.items[this.selectedIndex], keys = assignKeys(diagnostic.actions); 21497 for (let i = 0; i < keys.length; i++) 21498 if (keys[i].toUpperCase().charCodeAt(0) == event.keyCode) { 21499 let found = findDiagnostic(this.view.state.field(lintState).diagnostics, diagnostic); 21500 if (found) 21501 diagnostic.actions[i].apply(view, found.from, found.to); 21502 } 21503 } 21504 else { 21505 return; 21506 } 21507 event.preventDefault(); 21508 }; 21509 let onclick = (event) => { 21510 for (let i = 0; i < this.items.length; i++) { 21511 if (this.items[i].dom.contains(event.target)) 21512 this.moveSelection(i); 21513 } 21514 }; 21515 this.list = crelt("ul", { 21516 tabIndex: 0, 21517 role: "listbox", 21518 "aria-label": this.view.state.phrase("Diagnostics"), 21519 onkeydown, 21520 onclick 21521 }); 21522 this.dom = crelt("div", { class: "cm-panel-lint" }, this.list, crelt("button", { 21523 type: "button", 21524 name: "close", 21525 "aria-label": this.view.state.phrase("close"), 21526 onclick: () => closeLintPanel(this.view) 21527 }, "Ã")); 21528 this.update(); 21529 } 21530 get selectedIndex() { 21531 let selected = this.view.state.field(lintState).selected; 21532 if (!selected) 21533 return -1; 21534 for (let i = 0; i < this.items.length; i++) 21535 if (this.items[i].diagnostic == selected.diagnostic) 21536 return i; 21537 return -1; 21538 } 21539 update() { 21540 let { diagnostics, selected } = this.view.state.field(lintState); 21541 let i = 0, needsSync = false, newSelectedItem = null; 21542 diagnostics.between(0, this.view.state.doc.length, (_start, _end, { spec }) => { 21543 let found = -1, item; 21544 for (let j = i; j < this.items.length; j++) 21545 if (this.items[j].diagnostic == spec.diagnostic) { 21546 found = j; 21547 break; 21548 } 21549 if (found < 0) { 21550 item = new PanelItem(this.view, spec.diagnostic); 21551 this.items.splice(i, 0, item); 21552 needsSync = true; 21553 } 21554 else { 21555 item = this.items[found]; 21556 if (found > i) { 21557 this.items.splice(i, found - i); 21558 needsSync = true; 21559 } 21560 } 21561 if (selected && item.diagnostic == selected.diagnostic) { 21562 if (!item.dom.hasAttribute("aria-selected")) { 21563 item.dom.setAttribute("aria-selected", "true"); 21564 newSelectedItem = item; 21565 } 21566 } 21567 else if (item.dom.hasAttribute("aria-selected")) { 21568 item.dom.removeAttribute("aria-selected"); 21569 } 21570 i++; 21571 }); 21572 while (i < this.items.length && !(this.items.length == 1 && this.items[0].diagnostic.from < 0)) { 21573 needsSync = true; 21574 this.items.pop(); 21575 } 21576 if (this.items.length == 0) { 21577 this.items.push(new PanelItem(this.view, { 21578 from: -1, to: -1, 21579 severity: "info", 21580 message: this.view.state.phrase("No diagnostics") 21581 })); 21582 needsSync = true; 21583 } 21584 if (newSelectedItem) { 21585 this.list.setAttribute("aria-activedescendant", newSelectedItem.id); 21586 this.view.requestMeasure({ 21587 key: this, 21588 read: () => ({ sel: newSelectedItem.dom.getBoundingClientRect(), panel: this.list.getBoundingClientRect() }), 21589 write: ({ sel, panel }) => { 21590 if (sel.top < panel.top) 21591 this.list.scrollTop -= panel.top - sel.top; 21592 else if (sel.bottom > panel.bottom) 21593 this.list.scrollTop += sel.bottom - panel.bottom; 21594 } 21595 }); 21596 } 21597 else if (this.selectedIndex < 0) { 21598 this.list.removeAttribute("aria-activedescendant"); 21599 } 21600 if (needsSync) 21601 this.sync(); 21602 } 21603 sync() { 21604 let domPos = this.list.firstChild; 21605 function rm() { 21606 let prev = domPos; 21607 domPos = prev.nextSibling; 21608 prev.remove(); 21609 } 21610 for (let item of this.items) { 21611 if (item.dom.parentNode == this.list) { 21612 while (domPos != item.dom) 21613 rm(); 21614 domPos = item.dom.nextSibling; 21615 } 21616 else { 21617 this.list.insertBefore(item.dom, domPos); 21618 } 21619 } 21620 while (domPos) 21621 rm(); 21622 } 21623 moveSelection(selectedIndex) { 21624 if (this.selectedIndex < 0) 21625 return; 21626 let field = this.view.state.field(lintState); 21627 let selection = findDiagnostic(field.diagnostics, this.items[selectedIndex].diagnostic); 21628 if (!selection) 21629 return; 21630 this.view.dispatch({ 21631 selection: { anchor: selection.from, head: selection.to }, 21632 scrollIntoView: true, 21633 effects: movePanelSelection.of(selection) 21634 }); 21635 } 21636 static open(view) { return new LintPanel(view); } 21637} 21638function svg(content, attrs = `viewBox="0 0 40 40"`) { 21639 return `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" ${attrs}>${encodeURIComponent(content)}</svg>')`; 21640} 21641function underline(color) { 21642 return svg(`<path d="m0 2.5 l2 -1.5 l1 0 l2 1.5 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>`, `width="6" height="3"`); 21643} 21644const baseTheme = /*@__PURE__*/EditorView.baseTheme({ 21645 ".cm-diagnostic": { 21646 padding: "3px 6px 3px 8px",
21647 marginLeft: "-1px", 21648 display: "block", 21649 whiteSpace: "pre-wrap" 21650 }, 21651 ".cm-diagnostic-error": { borderLeft: "5px solid #d11" }, 21652 ".cm-diagnostic-warning": { borderLeft: "5px solid orange" }, 21653 ".cm-diagnostic-info": { borderLeft: "5px solid #999" }, 21654 ".cm-diagnosticAction": { 21655 font: "inherit", 21656 border: "none", 21657 padding: "2px 4px", 21658 backgroundColor: "#444", 21659 color: "white", 21660 borderRadius: "3px", 21661 marginLeft: "8px" 21662 }, 21663 ".cm-diagnosticSource": { 21664 fontSize: "70%", 21665 opacity: .7 21666 }, 21667 ".cm-lintRange": { 21668 backgroundPosition: "left bottom", 21669 backgroundRepeat: "repeat-x", 21670 paddingBottom: "0.7px", 21671 }, 21672 ".cm-lintRange-error": { backgroundImage: /*@__PURE__*/underline("#d11") }, 21673 ".cm-lintRange-warning": { backgroundImage: /*@__PURE__*/underline("orange") }, 21674 ".cm-lintRange-info": { backgroundImage: /*@__PURE__*/underline("#999") }, 21675 ".cm-lintRange-active": { backgroundColor: "#ffdd9980" }, 21676 ".cm-tooltip-lint": { 21677 padding: 0, 21678 margin: 0 21679 }, 21680 ".cm-lintPoint": { 21681 position: "relative", 21682 "&:after": { 21683 content: '""', 21684 position: "absolute", 21685 bottom: 0, 21686 left: "-2px", 21687 borderLeft: "3px solid transparent", 21688 borderRight: "3px solid transparent", 21689 borderBottom: "4px solid #d11" 21690 } 21691 }, 21692 ".cm-lintPoint-warning": { 21693 "&:after": { borderBottomColor: "orange" } 21694 }, 21695 ".cm-lintPoint-info": { 21696 "&:after": { borderBottomColor: "#999" } 21697 }, 21698 ".cm-panel.cm-panel-lint": { 21699 position: "relative", 21700 "& ul": { 21701 maxHeight: "100px", 21702 overflowY: "auto", 21703 "& [aria-selected]": { 21704 backgroundColor: "#ddd", 21705 "& u": { textDecoration: "underline" } 21706 }, 21707 "&:focus [aria-selected]": { 21708 background_fallback: "#bdf", 21709 backgroundColor: "Highlight", 21710 color_fallback: "white", 21711 color: "HighlightText" 21712 }, 21713 "& u": { textDecoration: "none" }, 21714 padding: 0, 21715 margin: 0 21716 }, 21717 "& [name=close]": { 21718 position: "absolute", 21719 top: "0", 21720 right: "2px", 21721 background: "inherit", 21722 border: "none", 21723 font: "inherit", 21724 padding: 0, 21725 margin: 0 21726 } 21727 } 21728}); 21729 21730const basicSetup = /* @__PURE__ */ (() => [ 21731 lineNumbers(), 21732 highlightSpecialChars(), 21733 history(), 21734 foldGutter(), 21735 drawSelection(), 21736 EditorState.allowMultipleSelections.of(true), 21737 indentOnInput(), 21738 syntaxHighlighting(defaultHighlightStyle, { fallback: true }), 21739 closeBrackets(), 21740 rectangularSelection(), 21741 crosshairCursor(), 21742 keymap.of([ 21743 ...closeBracketsKeymap, 21744 ...defaultKeymap, 21745 ...historyKeymap, 21746 ...foldKeymap, 21747 ...completionKeymap, 21748 ...lintKeymap 21749 ]) 21750])(); 21751 21752const sql_dialects = [ 21753 "standardSQL", 21754 "msSQL", 21755 "mySQL", 21756 "mariaDB", 21757 "sqlite", 21758 "cassandra", 21759 "plSQL", 21760 "hive", 21761 "pgSQL", 21762 "gql", 21763 "gpSQL", 21764 "sparkSQL", 21765 "esper" 21766]; 21767const lang_map = { 21768 python: () => __vitePreload(() => import('./index-d9bc3f51.js'),true?["./index-d9bc3f51.js","./index-be014d45.js","./index-12d4b00b.js","./index-34709fe9.css","./Button-c2bc75a7.js","./Index-9d23d982.js","./Index-bca1a2bf.css","./Button-2a9911a9.css","./Check-f7edb5d9.js","./Copy-a69620a8.js","./DownloadLink-df2b9666.js","./file-url-84e08b20.js","./BlockLabel-2a595353.js","./Empty-1a32f00a.js","./Example-26f7bda8.js","./Example-c56e7331.css"]:void 0,import.meta.url).then((m) => m.python()), 21769 markdown: async () => { 21770 const [md, frontmatter] = await Promise.all([ 21771 __vitePreload(() => import('./index-baf57d6c.js'),true?["./index-baf57d6c.js","./index-7eab0056.js","./index-be014d45.js","./index-297ba8f7.js","./index-12d4b00b.js","./index-34709fe9.css","./Button-c2bc75a7.js","./Index-9d23d982.js","./Index-bca1a2bf.css","./Button-2a9911a9.css","./Check-f7edb5d9.js","./Copy-a69620a8.js","./DownloadLink-df2b9666.js","./file-url-84e08b20.js","./BlockLabel-2a595353.js","./Empty-1a32f00a.js","./Example-26f7bda8.js","./Example-c56e7331.css","./index-45999c13.js"]:void 0,import.meta.url), 21772 __vitePreload(() => import('./frontmatter-0d29d42b.js'),true?["./frontmatter-0d29d42b.js","./yaml-c63fc23d.js","./index-12d4b00b.js","./index-34709fe9.css","./Button-c2bc75a7.js","./Index-9d23d982.js","./Index-bca1a2bf.css","./Button-2a9911a9.css","./Check-f7edb5d9.js","./Copy-a69620a8.js","./DownloadLink-df2b9666.js","./file-url-84e08b20.js","./BlockLabel-2a595353.js","./Empty-1a32f00a.js","./Example-26f7bda8.js","./Example-c56e7331.css"]:void 0,import.meta.url) 21773 ]); 21774 return md.markdown({ extensions: [frontmatter.frontmatter] }); 21775 }, 21776 json: () => __vitePreload(() => import('./index-075d554f.js'),true?["./index-075d554f.js","./index-be014d45.js","./index-12d4b00b.js","./index-34709fe9.css","./Button-c2bc75a7.js","./Index-9d23d982.js","./Index-bca1a2bf.css","./Button-2a9911a9.css","./Check-f7edb5d9.js","./Copy-a69620a8.js","./DownloadLink-df2b9666.js","./file-url-84e08b20.js","./BlockLabel-2a595353.js","./Empty-1a32f00a.js","./Example-26f7bda8.js","./Example-c56e7331.css"]:void 0,import.meta.url).then((m) => m.json()), 21777 html: () => __vitePreload(() => import('./index-7eab0056.js'),true?["./index-7eab0056.js","./index-be014d45.js","./index-297ba8f7.js","./index-12d4b00b.js","./index-34709fe9.css","./Button-c2bc75a7.js","./Index-9d23d982.js","./Index-bca1a2bf.css","./Button-2a9911a9.css","./Check-f7edb5d9.js","./Copy-a69620a8.js","./DownloadLink-df2b9666.js","./file-url-84e08b20.js","./BlockLabel-2a595353.js","./Empty-1a32f00a.js","./Example-26f7bda8.js","./Example-c56e7331.css","./index-45999c13.js"]:void 0,import.meta.url).then((m) => m.html()), 21778 css: () => __vitePreload(() => import('./index-297ba8f7.js'),true?["./index-297ba8f7.js","./index-be014d45.js","./index-12d4b00b.js","./index-34709fe9.css","./Button-c2bc75a7.js","./Index-9d23d982.js","./Index-bca1a2bf.css","./Button-2a9911a9.css","./Check-f7edb5d9.js","./Copy-a69620a8.js","./DownloadLink-df2b9666.js","./file-url-84e08b20.js","./BlockLabel-2a595353.js","./Empty-1a32f00a.js","./Example-26f7bda8.js","./Example-c56e7331.css"]:void 0,import.meta.url).then((m) => m.css()), 21779 javascript: () => __vitePreload(() => import('./index-45999c13.js'),true?["./index-45999c13.js","./index-be014d45.js","./index-12d4b00b.js","./index-34709fe9.css","./Button-c2bc75a7.js","./Index-9d23d982.js","./Index-bca1a2bf.css","./Button-2a9911a9.css","./Check-f7edb5d9.js","./Copy-a69620a8.js","./DownloadLink-df2b9666.js","./file-url-84e08b20.js","./BlockLabel-2a595353.js","./Empty-1a32f00a.js","./Example-26f7bda8.js","./Example-c56e7331.css"]:void 0,import.meta.url).then((m) => m.javascript()), 21780 typescript: () => __vitePreload(() => import('./index-45999c13.js'),true?["./index-45999c13.js","./index-be014d45.js","./index-12d4b00b.js","./index-34709fe9.css","./Button-c2bc75a7.js","./Index-9d23d982.js","./Index-bca1a2bf.css","./Button-2a9911a9.css","./Check-f7edb5d9.js","./Copy-a69620a8.js","./DownloadLink-df2b9666.js","./file-url-84e08b20.js","./BlockLabel-2a595353.js","./Empty-1a32f00a.js","./Example-26f7bda8.js","./Example-c56e7331.css"]:void 0,import.meta.url).then( 21781 (m) => m.javascript({ typescript: true }) 21782 ), 21783 yaml: () => __vitePreload(() => import('./yaml-c63fc23d.js'),true?[]:void 0,import.meta.url).then( 21784 (m) => StreamLanguage.define(m.yaml) 21785 ), 21786 dockerfile: () => __vitePreload(() => import('./dockerfile-9d133344.js'),true?[]:void 0,import.meta.url).then( 21787 (m) => StreamLanguage.define(m.dockerFile) 21788 ), 21789 shell: () => __vitePreload(() => import('./shell-e5115f95.js'),true?[]:void 0,import.meta.url).then( 21790 (m) => StreamLanguage.define(m.shell) 21791 ), 21792 r: () => __vitePreload(() => import('./r-ab7049f4.js'),true?[]:void 0,import.meta.url).then( 21793 (m) => StreamLanguage.define(m.r) 21794 ), 21795 sql: () => __vitePreload(() => import('./sql-5a527ddd.js'),true?[]:void 0,import.meta.url).then( 21796 (m) => StreamLanguage.define(m.standardSQL) 21797 ), 21798 ...Object.fromEntries( 21799 sql_dialects.map((dialect) => [ 21800 "sql-" + dialect, 21801 () => __vitePreload(() => import('./sql-5a527ddd.js'),true?[]:void 0,import.meta.url).then( 21802 (m) => StreamLanguage.define(m[dialect]) 21803 ) 21804 ]) 21805 ) 21806};
21807const alias_map = { 21808 py: "python", 21809 md: "markdown", 21810 js: "javascript", 21811 ts: "typescript", 21812 sh: "shell" 21813}; 21814async function getLanguageExtension(lang) { 21815 const _lang = lang_map[lang] || lang_map[alias_map[lang]] || void 0; 21816 if (_lang) { 21817 return _lang(); 21818 } 21819 return void 0; 21820} 21821 21822const Code_svelte_svelte_type_style_lang = ''; 21823 21824/* home/runner/work/gradio/gradio/js/code/shared/Code.svelte generated by Svelte v4.2.2 */ 21825const { 21826 SvelteComponent: SvelteComponent$4, 21827 append: append$2, 21828 attr: attr$3, 21829 binding_callbacks: binding_callbacks$1, 21830 detach: detach$4, 21831 element: element_1, 21832 init: init$4, 21833 insert: insert$4, 21834 noop, 21835 safe_not_equal: safe_not_equal$4 21836} = window.__gradio__svelte__internal; 21837const { createEventDispatcher, onMount } = window.__gradio__svelte__internal; 21838function create_fragment$4(ctx) { 21839 let div1; 21840 let div0; 21841 let div0_class_value; 21842 21843 return { 21844 c() { 21845 div1 = element_1("div"); 21846 div0 = element_1("div"); 21847 attr$3(div0, "class", div0_class_value = "codemirror-wrapper " + /*class_names*/ ctx[0] + " svelte-1sc8eck"); 21848 attr$3(div1, "class", "wrap svelte-1sc8eck"); 21849 }, 21850 m(target, anchor) { 21851 insert$4(target, div1, anchor); 21852 append$2(div1, div0); 21853 /*div0_binding*/ ctx[12](div0); 21854 }, 21855 p(ctx, [dirty]) {
21856 if (dirty & /*class_names*/ 1 && div0_class_value !== (div0_class_value = "codemirror-wrapper " + /*class_names*/ ctx[0] + " svelte-1sc8eck")) { 21857 attr$3(div0, "class", div0_class_value); 21858 } 21859 }, 21860 i: noop, 21861 o: noop, 21862 d(detaching) { 21863 if (detaching) { 21864 detach$4(div1); 21865 } 21866 21867 /*div0_binding*/ ctx[12](null); 21868 } 21869 }; 21870} 21871 21872function getGutterLineHeight(_view) { 21873 let elements = _view.dom.querySelectorAll(".cm-gutterElement"); 21874 21875 if (elements.length === 0) { 21876 return null; 21877 } 21878 21879 for (var i = 0; i < elements.length; i++) { 21880 let node = elements[i]; 21881 let height = getComputedStyle(node)?.height ?? "0px"; 21882 21883 if (height != "0px") { 21884 return height; 21885 } 21886 } 21887 21888 return null; 21889} 21890 21891function instance$4($$self, $$props, $$invalidate) { 21892 let { class_names = "" } = $$props; 21893 let { value = "" } = $$props; 21894 let { dark_mode } = $$props; 21895 let { basic = true } = $$props; 21896 let { language } = $$props; 21897 let { lines = 5 } = $$props; 21898 let { extensions = [] } = $$props; 21899 let { use_tab = true } = $$props; 21900 let { readonly = false } = $$props; 21901 let { placeholder: placeholder$1 = undefined } = $$props; 21902 const dispatch = createEventDispatcher(); 21903 let lang_extension; 21904 let element; 21905 let view; 21906 21907 async function get_lang(val) { 21908 const ext = await getLanguageExtension(val); 21909 $$invalidate(11, lang_extension = ext); 21910 } 21911 21912 function set_doc(new_doc) { 21913 if (view && new_doc !== view.state.doc.toString()) { 21914 view.dispatch({ 21915 changes: { 21916 from: 0, 21917 to: view.state.doc.length, 21918 insert: new_doc 21919 } 21920 }); 21921 } 21922 } 21923 21924 function update_lines() { 21925 if (view) { 21926 view.requestMeasure({ read: update_gutters }); 21927 } 21928 } 21929 21930 function create_editor_view() { 21931 const editorView = new EditorView({ 21932 parent: element, 21933 state: create_editor_state(value) 21934 }); 21935 21936 editorView.dom.addEventListener("focus", handle_focus, true); 21937 editorView.dom.addEventListener("blur", handle_blur, true); 21938 return editorView; 21939 } 21940 21941 function handle_focus() { 21942 dispatch("focus"); 21943 } 21944 21945 function handle_blur() { 21946 dispatch("blur"); 21947 } 21948 21949 function update_gutters(_view) { 21950 let gutters = _view.dom.querySelectorAll(".cm-gutter"); 21951 let _lines = lines + 1; 21952 let lineHeight = getGutterLineHeight(_view); 21953 21954 if (!lineHeight) { 21955 return null; 21956 } 21957 21958 for (var i = 0; i < gutters.length; i++) { 21959 let node = gutters[i]; 21960 node.style.minHeight = `calc(${lineHeight} * ${_lines})`; 21961 } 21962 21963 return null; 21964 } 21965 21966 function handle_change(vu) { 21967 if (vu.docChanged) { 21968 const doc = vu.state.doc; 21969 const text = doc.toString(); 21970 $$invalidate(2, value = text); 21971 dispatch("change", text); 21972 } 21973 21974 view.requestMeasure({ read: update_gutters }); 21975 } 21976 21977 function get_extensions() { 21978 const stateExtensions = [ 21979 ...get_base_extensions(basic, use_tab, placeholder$1, readonly, lang_extension), 21980 FontTheme, 21981 ...get_theme(), 21982 ...extensions 21983 ]; 21984 21985 return stateExtensions; 21986 } 21987 21988 const FontTheme = EditorView.theme({ 21989 "&": { 21990 fontSize: "var(--text-sm)", 21991 backgroundColor: "var(--border-color-secondary)" 21992 }, 21993 ".cm-content": { 21994 paddingTop: "5px", 21995 paddingBottom: "5px", 21996 color: "var(--body-text-color)", 21997 fontFamily: "var(--font-mono)", 21998 minHeight: "100%" 21999 }, 22000 ".cm-gutters": { 22001 marginRight: "1px", 22002 borderRight: "1px solid var(--border-color-primary)", 22003 backgroundColor: "transparent", 22004 color: "var(--body-text-color-subdued)" 22005 }, 22006 ".cm-focused": { outline: "none" }, 22007 ".cm-scroller": { height: "auto" }, 22008 ".cm-cursor": { 22009 borderLeftColor: "var(--body-text-color)" 22010 } 22011 }); 22012 22013 function create_editor_state(_value) { 22014 return EditorState.create({ 22015 doc: _value ?? undefined, 22016 extensions: get_extensions() 22017 }); 22018 } 22019 22020 function get_base_extensions(basic, use_tab, placeholder$1, readonly, lang) { 22021 const extensions = [ 22022 EditorView.editable.of(!readonly), 22023 EditorState.readOnly.of(readonly), 22024 EditorView.contentAttributes.of({ "aria-label": "Code input container" }) 22025 ]; 22026 22027 if (basic) { 22028 extensions.push(basicSetup); 22029 } 22030 22031 if (use_tab) { 22032 extensions.push(keymap.of([indentWithTab])); 22033 } 22034 22035 if (placeholder$1) { 22036 extensions.push(placeholder(placeholder$1)); 22037 } 22038 22039 if (lang) { 22040 extensions.push(lang); 22041 } 22042 22043 extensions.push(EditorView.updateListener.of(handle_change)); 22044 return extensions; 22045 } 22046 22047 function get_theme() { 22048 const extensions = []; 22049 22050 if (dark_mode) { 22051 extensions.push(basicDark); 22052 } else { 22053 extensions.push(basicLight); 22054 } 22055 22056 return extensions; 22057 } 22058 22059 function reconfigure() {
22060 view?.dispatch({ 22061 effects: StateEffect.reconfigure.of(get_extensions()) 22062 }); 22063 } 22064 22065 onMount(() => { 22066 view = create_editor_view(); 22067 return () => view?.destroy(); 22068 }); 22069 22070 function div0_binding($$value) { 22071 binding_callbacks$1[$$value ? 'unshift' : 'push'](() => { 22072 element = $$value; 22073 $$invalidate(1, element); 22074 }); 22075 } 22076 22077 $$self.$$set = $$props => { 22078 if ('class_names' in $$props) $$invalidate(0, class_names = $$props.class_names); 22079 if ('value' in $$props) $$invalidate(2, value = $$props.value); 22080 if ('dark_mode' in $$props) $$invalidate(3, dark_mode = $$props.dark_mode); 22081 if ('basic' in $$props) $$invalidate(4, basic = $$props.basic); 22082 if ('language' in $$props) $$invalidate(5, language = $$props.language); 22083 if ('lines' in $$props) $$invalidate(6, lines = $$props.lines); 22084 if ('extensions' in $$props) $$invalidate(7, extensions = $$props.extensions); 22085 if ('use_tab' in $$props) $$invalidate(8, use_tab = $$props.use_tab); 22086 if ('readonly' in $$props) $$invalidate(9, readonly = $$props.readonly); 22087 if ('placeholder' in $$props) $$invali
22087date(10, placeholder$1 = $$props.placeholder); 22088 }; 22089 22090 $$self.$$.update = () => { 22091 if ($$self.$$.dirty & /*language*/ 32) { 22092 get_lang(language); 22093 } 22094 22095 if ($$self.$$.dirty & /*lang_extension*/ 2048) { 22096 (reconfigure()); 22097 } 22098 22099 if ($$self.$$.dirty & /*value*/ 4) { 22100 set_doc(value); 22101 } 22102 }; 22103 22104 update_lines(); 22105 22106 return [ 22107 class_names, 22108 element, 22109 value, 22110 dark_mode, 22111 basic, 22112 language, 22113 lines, 22114 extensions, 22115 use_tab, 22116 readonly, 22117 placeholder$1, 22118 lang_extension, 22119 div0_binding 22120 ]; 22121} 22122 22123class Code extends SvelteComponent$4 { 22124 constructor(options) { 22125 super(); 22126 22127 init$4(this, options, instance$4, create_fragment$4, safe_not_equal$4, { 22128 class_names: 0, 22129 value: 2, 22130 dark_mode: 3, 22131 basic: 4, 22132 language: 5, 22133 lines: 6, 22134 extensions: 7, 22135 use_tab: 8, 22136 readonly: 9, 22137 placeholder: 10 22138 }); 22139 } 22140} 22141 22142const Code$1 = Code; 22143 22144const Copy_svelte_svelte_type_style_lang = ''; 22145 22146/* home/runner/work/gradio/gradio/js/code/shared/Copy.svelte generated by Svelte v4.2.2 */ 22147const { 22148 SvelteComponent: SvelteComponent$3, 22149 add_render_callback: add_render_callback$1, 22150 append: append$1, 22151 attr: attr$2, 22152 check_outros: check_outros$2, 22153 create_bidirectional_transition: create_bidirectional_transition$1, 22154 create_component: create_component$3, 22155 destroy_component: destroy_component$3, 22156 detach: detach$3, 22157 element: element$2, 22158 group_outros: group_outros$2, 22159 init: init$3, 22160 insert: insert$3, 22161 listen, 22162 mount_component: mount_component$3, 22163 safe_not_equal: safe_not_equal$3, 22164 space: space$3, 22165 toggle_class, 22166 transition_in: transition_in$3, 22167 transition_out: transition_out$3 22168} = window.__gradio__svelte__internal; 22169const { onDestroy: onDestroy$1 } = window.__gradio__svelte__internal; 22170function create_if_block$2(ctx) { 22171 let span; 22172 let check; 22173 let span_transition; 22174 let current; 22175 check = new Check({}); 22176 22177 return { 22178 c() { 22179 span = element$2("span"); 22180 create_component$3(check.$$.fragment); 22181 attr$2(span, "class", "check svelte-qi7jcw"); 22182 attr$2(span, "aria-roledescription", "Value copied"); 22183 attr$2(span, "aria-label", "Copied"); 22184 }, 22185 m(target, anchor) { 22186 insert$3(target, span, anchor); 22187 mount_component$3(check, span, null); 22188 current = true; 22189 }, 22190 i(local) { 22191 if (current) return; 22192 transition_in$3(check.$$.fragment, local); 22193 22194 if (local) { 22195 add_render_callback$1(() => { 22196 if (!current) return; 22197 if (!span_transition) span_transition = create_bidirectional_transition$1(span, fade, {}, true); 22198 span_transition.run(1); 22199 }); 22200 } 22201 22202 current = true; 22203 }, 22204 o(local) { 22205 transition_out$3(check.$$.fragment, local); 22206 22207 if (local) { 22208 if (!span_transition) span_transition = create_bidirectional_transition$1(span, fade, {}, false); 22209 span_transition.run(0); 22210 } 22211 22212 current = false; 22213 }, 22214 d(detaching) { 22215 if (detaching) { 22216 detach$3(span); 22217 } 22218 22219 destroy_component$3(check); 22220 if (detaching && span_transition) span_transition.end(); 22221 } 22222 }; 22223} 22224 22225function create_fragment$3(ctx) { 22226 let button; 22227 let copy; 22228 let t; 22229 let current; 22230 let mounted; 22231 let dispose; 22232 copy = new Copy$1({}); 22233 let if_block = /*copied*/ ctx[0] && create_if_block$2(); 22234 22235 return { 22236 c() { 22237 button = element$2("button"); 22238 create_component$3(copy.$$.fragment); 22239 t = space$3(); 22240 if (if_block) if_block.c(); 22241 attr$2(button, "title", "copy"); 22242 attr$2(button, "aria-roledescription", "Copy value"); 22243 attr$2(button, "aria-label", "Copy"); 22244 attr$2(button, "class", "svelte-qi7jcw"); 22245 toggle_class(button, "copied", /*copied*/ ctx[0]); 22246 }, 22247 m(target, anchor) { 22248 insert$3(target, button, anchor); 22249 mount_component$3(copy, button, null); 22250 append$1(button, t); 22251 if (if_block) if_block.m(button, null); 22252 current = true; 22253 22254 if (!mounted) { 22255 dispose = listen(button, "click", /*handle_copy*/ ctx[1]); 22256 mounted = true; 22257 } 22258 }, 22259 p(ctx, [dirty]) { 22260 if (/*copied*/ ctx[0]) { 22261 if (if_block) { 22262 if (dirty & /*copied*/ 1) { 22263 transition_in$3(if_block, 1); 22264 } 22265 } else { 22266 if_block = create_if_block$2(); 22267 if_block.c(); 22268 transition_in$3(if_block, 1); 22269 if_block.m(button, null); 22270 } 22271 } else if (if_block) { 22272 group_outros$2(); 22273 22274 transition_out$3(if_block, 1, 1, () => { 22275 if_block = null; 22276 }); 22277 22278 check_outros$2(); 22279 } 22280 22281 if (!current || dirty & /*copied*/ 1) { 22282 toggle_class(button, "copied", /*copied*/ ctx[0]); 22283 } 22284 }, 22285 i(local) { 22286 if (current) return; 22287 transition_in$3(copy.$$.fragment, local); 22288 transition_in$3(if_block); 22289 current = true; 22290 }, 22291 o(local) { 22292 transition_out$3(copy.$$.fragment, local); 22293 transition_out$3(if_block); 22294 current = false;
22295 }, 22296 d(detaching) { 22297 if (detaching) { 22298 detach$3(button); 22299 } 22300 22301 destroy_component$3(copy); 22302 if (if_block) if_block.d(); 22303 mounted = false; 22304 dispose(); 22305 } 22306 }; 22307} 22308 22309function instance$3($$self, $$props, $$invalidate) { 22310 let copied = false; 22311 let { value } = $$props; 22312 let timer; 22313 22314 function copy_feedback() { 22315 $$invalidate(0, copied = true); 22316 if (timer) clearTimeout(timer); 22317 22318 timer = setTimeout( 22319 () => { 22320 $$invalidate(0, copied = false); 22321 }, 22322 2000 22323 ); 22324 } 22325 22326 async function handle_copy() { 22327 if ("clipboard" in navigator) { 22328 await navigator.clipboard.writeText(value); 22329 copy_feedback(); 22330 } 22331 } 22332 22333 onDestroy$1(() => { 22334 if (timer) clearTimeout(timer); 22335 }); 22336 22337 $$self.$$set = $$props => { 22338 if ('value' in $$props) $$invalidate(2, value = $$props.value); 22339 }; 22340 22341 return [copied, handle_copy, value]; 22342} 22343 22344class Copy_1 extends SvelteComponent$3 { 22345 constructor(options) { 22346 super(); 22347 init$3(this, options, instance$3, create_fragment$3, safe_not_equal$3, { value: 2 }); 22348 } 22349} 22350 22351const Copy = Copy_1; 22352 22353const Download_svelte_svelte_type_style_lang = ''; 22354 22355/* home/runner/work/gradio/gradio/js/code/shared/Download.svelte generated by Svelte v4.2.2 */ 22356const { 22357 SvelteComponent: SvelteComponent$2, 22358 add_render_callback, 22359 attr: attr$1, 22360 check_outros: check_outros$1, 22361 create_bidirectional_transition, 22362 create_component: create_component$2, 22363 destroy_component: destroy_component$2, 22364 detach: detach$2, 22365 element: element$1, 22366 empty: empty$1, 22367 group_outros: group_outros$1, 22368 init: init$2, 22369 insert: insert$2, 22370 mount_component: mount_component$2, 22371 safe_not_equal: safe_not_equal$2, 22372 space: space$2, 22373 transition_in: transition_in$2, 22374 transition_out: transition_out$2 22375} = window.__gradio__svelte__internal; 22376const { onDestroy } = window.__gradio__svelte__internal; 22377function create_if_block$1(ctx) { 22378 let span; 22379 let check; 22380 let span_transition; 22381 let current; 22382 check = new Check({}); 22383 22384 return { 22385 c() { 22386 span = element$1("span"); 22387 create_component$2(check.$$.fragment); 22388 attr$1(span, "class", "check svelte-1vwgyfd"); 22389 }, 22390 m(target, anchor) { 22391 insert$2(target, span, anchor); 22392 mount_component$2(check, span, null); 22393 current = true; 22394 }, 22395 i(local) { 22396 if (current) return; 22397 transition_in$2(check.$$.fragment, local); 22398 22399 if (local) { 22400 add_render_callback(() => { 22401 if (!current) return; 22402 if (!span_transition) span_transition = create_bidirectional_transition(span, fade, {}, true); 22403 span_transition.run(1); 22404 }); 22405 } 22406 22407 current = true; 22408 }, 22409 o(local) { 22410 transition_out$2(check.$$.fragment, local); 22411 22412 if (local) { 22413 if (!span_transition) span_transition = create_bidirectional_transition(span, fade, {}, false); 22414 span_transition.run(0); 22415 } 22416 22417 current = false; 22418 }, 22419 d(detaching) { 22420 if (detaching) { 22421 detach$2(span); 22422 } 22423 22424 destroy_component$2(check); 22425 if (detaching && span_transition) span_transition.end(); 22426 } 22427 }; 22428} 22429 22430// (48:1) <DownloadLink download="file.{ext}" href={download_value} on:click={copy_feedback} > 22431function create_default_slot$1(ctx) { 22432 let download; 22433 let t; 22434 let if_block_anchor; 22435 let current; 22436 download = new Download$1({}); 22437 let if_block = /*copied*/ ctx[0] && create_if_block$1(); 22438 22439 return { 22440 c() { 22441 create_component$2(download.$$.fragment); 22442 t = space$2(); 22443 if (if_block) if_block.c(); 22444 if_block_anchor = empty$1(); 22445 }, 22446 m(target, anchor) { 22447 mount_component$2(download, target, anchor); 22448 insert$2(target, t, anchor); 22449 if (if_block) if_block.m(target, anchor); 22450 insert$2(target, if_block_anchor, anchor); 22451 current = true; 22452 }, 22453 p(ctx, dirty) { 22454 if (/*copied*/ ctx[0]) { 22455 if (if_block) { 22456 if (dirty & /*copied*/ 1) { 22457 transition_in$2(if_block, 1); 22458 } 22459 } else { 22460 if_block = create_if_block$1(); 22461 if_block.c(); 22462 transition_in$2(if_block, 1); 22463 if_block.m(if_block_anchor.parentNode, if_block_anchor); 22464 } 22465 } else if (if_block) { 22466 group_outros$1(); 22467 22468 transition_out$2(if_block, 1, 1, () => { 22469 if_block = null; 22470 }); 22471 22472 check_outros$1(); 22473 } 22474 }, 22475 i(local) { 22476 if (current) return; 22477 transition_in$2(download.$$.fragment, local); 22478 transition_in$2(if_block); 22479 current = true; 22480 }, 22481 o(local) { 22482 transition_out$2(download.$$.fragment, local); 22483 transition_out$2(if_block); 22484 current = false;
22485 }, 22486 d(detaching) { 22487 if (detaching) { 22488 detach$2(t); 22489 detach$2(if_block_anchor); 22490 } 22491 22492 destroy_component$2(download, detaching); 22493 if (if_block) if_block.d(detaching); 22494 } 22495 }; 22496} 22497 22498function create_fragment$2(ctx) { 22499 let div; 22500 let downloadlink; 22501 let current; 22502 22503 downloadlink = new DownloadLink({ 22504 props: { 22505 download: "file." + /*ext*/ ctx[2], 22506 href: /*download_value*/ ctx[1], 22507 $$slots: { default: [create_default_slot$1] }, 22508 $$scope: { ctx } 22509 } 22510 }); 22511 22512 downloadlink.$on("click", /*copy_feedback*/ ctx[3]); 22513 22514 return { 22515 c() { 22516 div = element$1("div"); 22517 create_component$2(downloadlink.$$.fragment); 22518 attr$1(div, "class", "container svelte-1vwgyfd"); 22519 }, 22520 m(target, anchor) { 22521 insert$2(target, div, anchor); 22522 mount_component$2(downloadlink, div, null); 22523 current = true; 22524 }, 22525 p(ctx, [dirty]) { 22526 const downloadlink_changes = {}; 22527 if (dirty & /*ext*/ 4) downloadlink_changes.download = "file." + /*ext*/ ctx[2]; 22528 if (dirty & /*download_value*/ 2) downloadlink_changes.href = /*download_value*/ ctx[1]; 22529 22530 if (dirty & /*$$scope, copied*/ 129) { 22531 downloadlink_changes.$$scope = { dirty, ctx }; 22532 } 22533 22534 downloadlink.$set(downloadlink_changes); 22535 }, 22536 i(local) { 22537 if (current) return; 22538 transition_in$2(downloadlink.$$.fragment, local); 22539 current = true; 22540 }, 22541 o(local) { 22542 transition_out$2(downloadlink.$$.fragment, local); 22543 current = false; 22544 }, 22545 d(detaching) { 22546 if (detaching) { 22547 detach$2(div); 22548 } 22549 22550 destroy_component$2(downloadlink); 22551 } 22552 }; 22553} 22554 22555function get_ext_for_type(type) { 22556 const exts = { 22557 py: "py", 22558 python: "py", 22559 md: "md", 22560 markdown: "md", 22561 json: "json", 22562 html: "html", 22563 css: "css", 22564 js: "js", 22565 javascript: "js", 22566 ts: "ts", 22567 typescript: "ts", 22568 yaml: "yaml", 22569 yml: "yml", 22570 dockerfile: "dockerfile", 22571 sh: "sh", 22572 shell: "sh", 22573 r: "r" 22574 }; 22575 22576 return exts[type] || "txt"; 22577} 22578 22579function instance$2($$self, $$props, $$invalidate) { 22580 let ext; 22581 let download_value; 22582 let { value } = $$props; 22583 let { language } = $$props; 22584 let copied = false; 22585 let timer; 22586 22587 function copy_feedback() { 22588 $$invalidate(0, copied = true); 22589 if (timer) clearTimeout(timer); 22590 22591 timer = setTimeout( 22592 () => { 22593 $$invalidate(0, copied = false); 22594 }, 22595 2000 22596 ); 22597 } 22598 22599 onDestroy(() => { 22600 if (timer) clearTimeout(timer); 22601 }); 22602 22603 $$self.$$set = $$props => {
22604 if ('value' in $$props) $$invalidate(4, value = $$props.value); 22605 if ('language' in $$props) $$invalidate(5, language = $$props.language); 22606 }; 22607 22608 $$self.$$.update = () => { 22609 if ($$self.$$.dirty & /*language*/ 32) { 22610 $$invalidate(2, ext = get_ext_for_type(language)); 22611 } 22612 22613 if ($$self.$$.dirty & /*value*/ 16) { 22614 $$invalidate(1, download_value = URL.createObjectURL(new Blob([value]))); 22615 } 22616 }; 22617 22618 return [copied, download_value, ext, copy_feedback, value, language]; 22619} 22620 22621class Download_1 extends SvelteComponent$2 { 22622 constructor(options) { 22623 super(); 22624 init$2(this, options, instance$2, create_fragment$2, safe_not_equal$2, { value: 4, language: 5 }); 22625 } 22626} 22627 22628const Download = Download_1; 22629 22630const Widgets_svelte_svelte_type_style_lang = ''; 22631 22632/* home/runner/work/gradio/gradio/js/code/shared/Widgets.svelte generated by Svelte v4.2.2 */ 22633const { 22634 SvelteComponent: SvelteComponent$1, 22635 append, 22636 attr, 22637 create_component: create_component$1, 22638 destroy_component: destroy_component$1, 22639 detach: detach$1, 22640 element, 22641 init: init$1, 22642 insert: insert$1, 22643 mount_component: mount_component$1, 22644 safe_not_equal: safe_not_equal$1, 22645 space: space$1, 22646 transition_in: transition_in$1, 22647 transition_out: transition_out$1 22648} = window.__gradio__svelte__internal; 22649function create_fragment$1(ctx) { 22650 let div; 22651 let download; 22652 let t; 22653 let copy; 22654 let current; 22655 22656 download = new Download({ 22657 props: { 22658 value: /*value*/ ctx[0], 22659 language: /*language*/ ctx[1] 22660 } 22661 }); 22662 22663 copy = new Copy({ props: { value: /*value*/ ctx[0] } }); 22664 22665 return { 22666 c() { 22667 div = element("div"); 22668 create_component$1(download.$$.fragment); 22669 t = space$1(); 22670 create_component$1(copy.$$.fragment); 22671 attr(div, "class", "svelte-1yin446"); 22672 }, 22673 m(target, anchor) { 22674 insert$1(target, div, anchor); 22675 mount_component$1(download, div, null); 22676 append(div, t); 22677 mount_component$1(copy, div, null); 22678 current = true; 22679 }, 22680 p(ctx, [dirty]) { 22681 const download_changes = {}; 22682 if (dirty & /*value*/ 1) download_changes.value = /*value*/ ctx[0]; 22683 if (dirty & /*language*/ 2) download_changes.language = /*language*/ ctx[1]; 22684 download.$set(download_changes); 22685 const copy_changes = {}; 22686 if (dirty & /*value*/ 1) copy_changes.value = /*value*/ ctx[0]; 22687 copy.$set(copy_changes); 22688 }, 22689 i(local) { 22690 if (current) return; 22691 transition_in$1(download.$$.fragment, local); 22692 transition_in$1(copy.$$.fragment, local); 22693 current = true; 22694 }, 22695 o(local) { 22696 transition_out$1(download.$$.fragment, local); 22697 transition_out$1(copy.$$.fragment, local); 22698 current = false; 22699 }, 22700 d(detaching) { 22701 if (detaching) { 22702 detach$1(div); 22703 } 22704 22705 destroy_component$1(download); 22706 destroy_component$1(copy); 22707 } 22708 }; 22709} 22710 22711function instance$1($$self, $$props, $$invalidate) { 22712 let { value } = $$props; 22713 let { language } = $$props; 22714 22715 $$self.$$set = $$props => {
22716 if ('value' in $$props) $$invalidate(0, value = $$props.value); 22717 if ('language' in $$props) $$invalidate(1, language = $$props.language); 22718 }; 22719 22720 return [value, language]; 22721} 22722 22723class Widgets extends SvelteComponent$1 { 22724 constructor(options) { 22725 super(); 22726 init$1(this, options, instance$1, create_fragment$1, safe_not_equal$1, { value: 0, language: 1 }); 22727 } 22728} 22729 22730const Widget = Widgets; 22731 22732/* home/runner/work/gradio/gradio/js/code/Index.svelte generated by Svelte v4.2.2 */ 22733const { 22734 SvelteComponent, 22735 add_flush_callback, 22736 assign, 22737 bind, 22738 binding_callbacks, 22739 check_outros, 22740 create_component, 22741 destroy_component, 22742 detach, 22743 empty, 22744 get_spread_object, 22745 get_spread_update, 22746 group_outros, 22747 init, 22748 insert, 22749 mount_component, 22750 safe_not_equal, 22751 space, 22752 transition_in, 22753 transition_out 22754} = window.__gradio__svelte__internal; 22755const { afterUpdate } = window.__gradio__svelte__internal; 22756function create_else_block(ctx) { 22757 let widget; 22758 let t; 22759 let code; 22760 let updating_value; 22761 let current; 22762 22763 widget = new Widget({ 22764 props: { 22765 language: /*language*/ ctx[2], 22766 value: /*value*/ ctx[0] 22767 } 22768 }); 22769 22770 function code_value_binding(value) { 22771 /*code_value_binding*/ ctx[15](value); 22772 } 22773 22774 let code_props = { 22775 language: /*language*/ ctx[2], 22776 lines: /*lines*/ ctx[3], 22777 dark_mode: /*dark_mode*/ ctx[12], 22778 readonly: !/*interactive*/ ctx[11] 22779 }; 22780 22781 if (/*value*/ ctx[0] !== void 0) { 22782 code_props.value = /*value*/ ctx[0]; 22783 } 22784 22785 code = new Code$1({ props: code_props }); 22786 binding_callbacks.push(() => bind(code, 'value', code_value_binding)); 22787 code.$on("blur", /*blur_handler*/ ctx[16]); 22788 code.$on("focus", /*focus_handler*/ ctx[17]); 22789 22790 return { 22791 c() { 22792 create_component(widget.$$.fragment); 22793 t = space(); 22794 create_component(code.$$.fragment); 22795 }, 22796 m(target, anchor) { 22797 mount_component(widget, target, anchor); 22798 insert(target, t, anchor); 22799 mount_component(code, target, anchor); 22800 current = true; 22801 }, 22802 p(ctx, dirty) { 22803 const widget_changes = {}; 22804 if (dirty & /*language*/ 4) widget_changes.language = /*language*/ ctx[2]; 22805 if (dirty & /*value*/ 1) widget_changes.value = /*value*/ ctx[0]; 22806 widget.$set(widget_changes); 22807 const code_changes = {}; 22808 if (dirty & /*language*/ 4) code_changes.language = /*language*/ ctx[2]; 22809 if (dirty & /*lines*/ 8) code_changes.lines = /*lines*/ ctx[3]; 22810 if (dirty & /*interactive*/ 2048) code_changes.readonly = !/*interactive*/ ctx[11]; 22811 22812 if (!updating_value && dirty & /*value*/ 1) { 22813 updating_value = true; 22814 code_changes.value = /*value*/ ctx[0]; 22815 add_flush_callback(() => updating_value = false); 22816 } 22817 22818 code.$set(code_changes); 22819 }, 22820 i(local) { 22821 if (current) return; 22822 transition_in(widget.$$.fragment, local); 22823 transition_in(code.$$.fragment, local); 22824 current = true; 22825 }, 22826 o(local) { 22827 transition_out(widget.$$.fragment, local); 22828 transition_out(code.$$.fragment, local); 22829 current = false; 22830 }, 22831 d(detaching) { 22832 if (detaching) { 22833 detach(t); 22834 } 22835 22836 destroy_component(widget, detaching); 22837 destroy_component(code, detaching); 22838 } 22839 }; 22840} 22841 22842// (57:1) {#if !value && !interactive} 22843function create_if_block(ctx) { 22844 let empty_1; 22845 let current; 22846 22847 empty_1 = new Empty({ 22848 props: { 22849 unpadded_box: true, 22850 size: "large", 22851 $$slots: { default: [create_default_slot_1] }, 22852 $$scope: { ctx } 22853 } 22854 }); 22855 22856 return { 22857 c() { 22858 create_component(empty_1.$$.fragment); 22859 }, 22860 m(target, anchor) { 22861 mount_component(empty_1, target, anchor); 22862 current = true; 22863 }, 22864 p(ctx, dirty) { 22865 const empty_1_changes = {}; 22866 22867 if (dirty & /*$$scope*/ 524288) { 22868 empty_1_changes.$$scope = { dirty, ctx }; 22869 } 22870 22871 empty_1.$set(empty_1_changes); 22872 }, 22873 i(local) { 22874 if (current) return; 22875 transition_in(empty_1.$$.fragment, local); 22876 current = true; 22877 }, 22878 o(local) { 22879 transition_out(empty_1.$$.fragment, local); 22880 current = false; 22881 }, 22882 d(detaching) { 22883 destroy_component(empty_1, detaching); 22884 } 22885 }; 22886} 22887 22888// (58:2) <Empty unpadded_box={true} size="large"> 22889function create_default_slot_1(ctx) { 22890 let codeicon; 22891 let current; 22892 codeicon = new Code$2({}); 22893 22894 return { 22895 c() { 22896 create_component(codeicon.$$.fragment); 22897 }, 22898 m(target, anchor) { 22899 mount_component(codeicon, target, anchor); 22900 current = true; 22901 }, 22902 i(local) { 22903 if (current) return; 22904 transition_in(codeicon.$$.fragment, local); 22905 current = true; 22906 }, 22907 o(local) { 22908 transition_out(codeicon.$$.fragment, local); 22909 current = false;
22910 }, 22911 d(detaching) { 22912 destroy_component(codeicon, detaching); 22913 } 22914 }; 22915} 22916 22917// (41:0) <Block variant={"solid"} padding={false} {elem_id} {elem_classes} {visible} {scale} > 22918function create_default_slot(ctx) { 22919 let statustracker; 22920 let t0; 22921 let blocklabel; 22922 let t1; 22923 let current_block_type_index; 22924 let if_block; 22925 let if_block_anchor; 22926 let current; 22927 22928 const statustracker_spread_levels = [ 22929 { autoscroll: /*gradio*/ ctx[1].autoscroll }, 22930 { i18n: /*gradio*/ ctx[1].i18n }, 22931 /*loading_status*/ ctx[9] 22932 ]; 22933 22934 let statustracker_props = {}; 22935 22936 for (let i = 0; i < statustracker_spread_levels.length; i += 1) { 22937 statustracker_props = assign(statustracker_props, statustracker_spread_levels[i]); 22938 } 22939 22940 statustracker = new Static({ props: statustracker_props }); 22941 22942 blocklabel = new BlockLabel({ 22943 props: { 22944 Icon: Code$2, 22945 show_label: /*show_label*/ ctx[8], 22946 label: /*label*/ ctx[7], 22947 float: false 22948 } 22949 }); 22950 22951 const if_block_creators = [create_if_block, create_else_block]; 22952 const if_blocks = []; 22953 22954 function select_block_type(ctx, dirty) { 22955 if (!/*value*/ ctx[0] && !/*interactive*/ ctx[11]) return 0; 22956 return 1; 22957 } 22958 22959 current_block_type_index = select_block_type(ctx); 22960 if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx); 22961 22962 return { 22963 c() { 22964 create_component(statustracker.$$.fragment); 22965 t0 = space(); 22966 create_component(blocklabel.$$.fragment); 22967 t1 = space(); 22968 if_block.c(); 22969 if_block_anchor = empty(); 22970 }, 22971 m(target, anchor) { 22972 mount_component(statustracker, target, anchor); 22973 insert(target, t0, anchor); 22974 mount_component(blocklabel, target, anchor); 22975 insert(target, t1, anchor); 22976 if_blocks[current_block_type_index].m(target, anchor); 22977 insert(target, if_block_anchor, anchor); 22978 current = true; 22979 }, 22980 p(ctx, dirty) { 22981 const statustracker_changes = (dirty & /*gradio, loading_status*/ 514) 22982 ? get_spread_update(statustracker_spread_levels, [ 22983 dirty & /*gradio*/ 2 && { autoscroll: /*gradio*/ ctx[1].autoscroll }, 22984 dirty & /*gradio*/ 2 && { i18n: /*gradio*/ ctx[1].i18n }, 22985 dirty & /*loading_status*/ 512 && get_spread_object(/*loading_status*/ ctx[9]) 22986 ]) 22987 : {}; 22988 22989 statustracker.$set(statustracker_changes); 22990 const blocklabel_changes = {}; 22991 if (dirty & /*show_label*/ 256) blocklabel_changes.show_label = /*show_label*/ ctx[8]; 22992 if (dirty & /*label*/ 128) blocklabel_changes.label = /*label*/ ctx[7]; 22993 blocklabel.$set(blocklabel_changes); 22994 let previous_block_index = current_block_type_index; 22995 current_block_type_index = select_block_type(ctx); 22996 22997 if (current_block_type_index === previous_block_index) { 22998 if_blocks[current_block_type_index].p(ctx, dirty); 22999 } else { 23000 group_outros(); 23001 23002 transition_out(if_blocks[previous_block_index], 1, 1, () => { 23003 if_blocks[previous_block_index] = null; 23004 }); 23005 23006 check_outros(); 23007 if_block = if_blocks[current_block_type_index]; 23008 23009 if (!if_block) { 23010 if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx); 23011 if_block.c(); 23012 } else { 23013 if_block.p(ctx, dirty); 23014 } 23015 23016 transition_in(if_block, 1); 23017 if_block.m(if_block_anchor.parentNode, if_block_anchor); 23018 } 23019 }, 23020 i(local) { 23021 if (current) return; 23022 transition_in(statustracker.$$.fragment, local); 23023 transition_in(blocklabel.$$.fragment, local); 23024 transition_in(if_block); 23025 current = true; 23026 }, 23027 o(local) { 23028 transition_out(statustracker.$$.fragment, local); 23029 transition_out(blocklabel.$$.fragment, local); 23030 transition_out(if_block); 23031 current = false; 23032 }, 23033 d(detaching) { 23034 if (detaching) { 23035 detach(t0); 23036 detach(t1); 23037 detach(if_block_anchor); 23038 } 23039 23040 destroy_component(statustracker, detaching); 23041 destroy_component(blocklabel, detaching); 23042 if_blocks[current_block_type_index].d(detaching); 23043 } 23044 }; 23045} 23046 23047function create_fragment(ctx) { 23048 let block; 23049 let current; 23050 23051 block = new Block({ 23052 props: { 23053 variant: "solid", 23054 padding: false, 23055 elem_id: /*elem_id*/ ctx[4], 23056 elem_classes: /*elem_classes*/ ctx[5], 23057 visible: /*visible*/ ctx[6], 23058 scale: /*scale*/ ctx[10], 23059 $$slots: { default: [create_default_slot] }, 23060 $$scope: { ctx } 23061 } 23062 }); 23063 23064 return { 23065 c() { 23066 create_component(block.$$.fragment); 23067 }, 23068 m(target, anchor) { 23069 mount_component(block, target, anchor); 23070 current = true; 23071 }, 23072 p(ctx, [dirty]) { 23073 const block_changes = {};
23074 if (dirty & /*elem_id*/ 16) block_changes.elem_id = /*elem_id*/ ctx[4]; 23075 if (dirty & /*elem_classes*/ 32) block_changes.elem_classes = /*elem_classes*/ ctx[5]; 23076 if (dirty & /*visible*/ 64) block_changes.visible = /*visible*/ ctx[6]; 23077 if (dirty & /*scale*/ 1024) block_changes.scale = /*scale*/ ctx[10]; 23078 23079 if (dirty & /*$$scope, value, interactive, language, lines, gradio, show_label, label, loading_status*/ 527247) { 23080 block_changes.$$scope = { dirty, ctx }; 23081 } 23082 23083 block.$set(block_changes); 23084 }, 23085 i(local) { 23086 if (current) return; 23087 transition_in(block.$$.fragment, local); 23088 current = true; 23089 }, 23090 o(local) { 23091 transition_out(block.$$.fragment, local); 23092 current = false; 23093 }, 23094 d(detaching) { 23095 destroy_component(block, detaching); 23096 } 23097 }; 23098} 23099 23100function instance($$self, $$props, $$invalidate) { 23101 let { gradio } = $$props; 23102 let { value = "" } = $$props; 23103 let { value_is_output = false } = $$props; 23104 let { language = "" } = $$props; 23105 let { lines = 5 } = $$props; 23106 let { target } = $$props; 23107 let { elem_id = "" } = $$props; 23108 let { elem_classes = [] } = $$props; 23109 let { visible = true } = $$props; 23110 let { label = gradio.i18n("code.code") } = $$props; 23111 let { show_label = true } = $$props; 23112 let { loading_status } = $$props; 23113 let { scale = null } = $$props; 23114 let { interactive } = $$props; 23115 let dark_mode = target.classList.contains("dark"); 23116 23117 function handle_change() { 23118 gradio.dispatch("change", value); 23119 23120 if (!value_is_output) { 23121 gradio.dispatch("input"); 23122 } 23123 } 23124 23125 afterUpdate(() => { 23126 $$invalidate(13, value_is_output = false); 23127 }); 23128 23129 function code_value_binding(value$1) { 23130 value = value$1; 23131 $$invalidate(0, value); 23132 } 23133 23134 const blur_handler = () => gradio.dispatch("blur"); 23135 const focus_handler = () => gradio.dispatch("focus"); 23136 23137 $$self.$$set = $$props => {
23138 if ('gradio' in $$props) $$invalidate(1, gradio = $$props.gradio); 23139 if ('value' in $$props) $$invalidate(0, value = $$props.value); 23140 if ('value_is_output' in $$props) $$invalidate(13, value_is_output = $$props.value_is_output); 23141 if ('language' in $$props) $$invalidate(2, language = $$props.language); 23142 if ('lines' in $$props) $$invalidate(3, lines = $$props.lines); 23143 if ('target' in $$props) $$invalidate(14, target = $$props.target); 23144 if ('elem_id' in $$props) $$invalidate(4, elem_id = $$props.elem_id); 23145 if ('elem_classes' in $$props) $$invalidate(5, elem_classes = $$props.elem_classes); 23146 if ('visible' in $$props) $$invalidate(6, visible = $$props.visible); 23147 if ('label' in $$props) $$invalidate(7, label = $$props.label); 23148 if ('show_label' in $$props) $$invalidate(8, show_label = $$props.show_label); 23149 if ('loading_status' in $$props) $$invalidate(9, loading_status = $$props.loading_status); 23150 if ('scale' in $$props) $$invalidate(10, scale = $$props.scale); 23151 if ('interactive' in $$props) $$invalidate(11, interactive = $$props.interactive); 23152 }; 23153 23154 $$self.$$.update = () => { 23155 if ($$self.$$.dirty & /*value*/ 1) { 23156 (handle_change()); 23157 } 23158 }; 23159 23160 return [ 23161 value, 23162 gradio, 23163 language, 23164 lines, 23165 elem_id, 23166 elem_classes, 23167 visible, 23168 label, 23169 show_label, 23170 loading_status, 23171 scale, 23172 interactive, 23173 dark_mode, 23174 value_is_output, 23175 target, 23176 code_value_binding, 23177 blur_handler, 23178 focus_handler 23179 ]; 23180} 23181 23182class Index extends SvelteComponent { 23183 constructor(options) { 23184 super(); 23185 23186 init(this, options, instance, create_fragment, safe_not_equal, { 23187 gradio: 1, 23188 value: 0, 23189 value_is_output: 13, 23190 language: 2, 23191 lines: 3, 23192 target: 14, 23193 elem_id: 4, 23194 elem_classes: 5, 23195 visible: 6, 23196 label: 7, 23197 show_label: 8, 23198 loading_status: 9, 23199 scale: 10, 23200 interactive: 11 23201 }); 23202 } 23203} 23204 23205const Index$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({ 23206 __proto__: null, 23207 BaseCode: Code$1, 23208 BaseCopy: Copy, 23209 BaseDownload: Download, 23210 BaseExample: Example, 23211 BaseWidget: Widget, 23212 default: Index 23213}, Symbol.toStringTag, { value: 'Module' })); 23214 23215export { sublanguageProp as A, ifNotIn as B, completeFromList as C, DefaultBufferLength as D, EditorSelection as E, Index$1 as F, IterMode as I, LRLanguage as L, NodeSet as N, Parser as P, StreamLanguage as S, Tree as T, NodeType as a, NodeProp as b, foldInside as c, delimitedIndent as d, LanguageSupport as e, foldNodeProp as f, Tag as g, syntaxTree as h, indentNodeProp as i, Prec as j, keymap as k, Language as l, defineLanguageFacet as m, languageDataProp as n, foldService as o, parseMixed as p, LanguageDescription as q, ParseContext as r, styleTags as s, tags as t, bracketMatchingHandle as u, EditorView as v, continuedIndent as w, NodeWeakMap as x, snippetCompletion as y, flatIndent as z }; 23216//# sourceMappingURL=Index-42090191.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.