Brunobkr/llama.cpp_AlgMor24_github
ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.
03k
1'use strict';2 3var sourcemapCodec = require('@jridgewell/sourcemap-codec');4 5class BitSet {6 constructor(arg) {7 this.bits = arg instanceof BitSet ? arg.bits.slice() : [];8 }9 10 add(n) {11 this.bits[n >> 5] |= 1 << (n & 31);12 }13 14 has(n) {15 return !!(this.bits[n >> 5] & (1 << (n & 31)));16 }17}18 19class Chunk {20 constructor(start, end, content) {21 this.start = start;22 this.end = end;23 this.original = content;24 25 this.intro = '';26 this.outro = '';27 28 this.content = content;29 this.storeName = false;30 this.edited = false;31 32 {33 this.previous = null;34 this.next = null;35 }36 }37 38 appendLeft(content) {39 this.outro += content;40 }41 42 appendRight(content) {43 this.intro = this.intro + content;44 }45 46 clone() {47 const chunk = new Chunk(this.start, this.end, this.original);48 49 chunk.intro = this.intro;50 chunk.outro = this.outro;51 chunk.content = this.content;52 chunk.storeName = this.storeName;53 chunk.edited = this.edited;54 55 return chunk;56 }57 58 contains(index) {59 return this.start < index && index < this.end;60 }61 62 eachNext(fn) {63 let chunk = this;64 while (chunk) {65 fn(chunk);66 chunk = chunk.next;67 }68 }69 70 eachPrevious(fn) {71 let chunk = this;72 while (chunk) {73 fn(chunk);74 chunk = chunk.previous;75 }76 }77 78 edit(content, storeName, contentOnly) {79 this.content = content;80 if (!contentOnly) {81 this.intro = '';82 this.outro = '';83 }84 this.storeName = storeName;85 86 this.edited = true;87 88 return this;89 }90 91 prependLeft(content) {92 this.outro = content + this.outro;93 }94 95 prependRight(content) {96 this.intro = content + this.intro;97 }98 99 reset() {100 this.intro = '';101 this.outro = '';102 if (this.edited) {103 this.content = this.original;104 this.storeName = false;105 this.edited = false;106 }107 }108 109 split(index) {110 const sliceIndex = index - this.start;111 112 const originalBefore = this.original.slice(0, sliceIndex);113 const originalAfter = this.original.slice(sliceIndex);114 115 this.original = originalBefore;116 117 const newChunk = new Chunk(index, this.end, originalAfter);118 newChunk.outro = this.outro;119 this.outro = '';120 121 this.end = index;122 123 if (this.edited) {124 // after split we should save the edit content record into the correct chunk125 // to make sure sourcemap correct126 // For example:127 // ' test'.trim()128 // split -> ' ' + 'test'129 // ✔️ edit -> '' + 'test'130 // ✖️ edit -> 'test' + ''131 // TODO is this block necessary?...132 newChunk.edit('', false);133 this.content = '';134 } else {135 this.content = originalBefore;136 }137 138 newChunk.next = this.next;139 if (newChunk.next) newChunk.next.previous = newChunk;140 newChunk.previous = this;141 this.next = newChunk;142 143 return newChunk;144 }145 146 toString() {147 return this.intro + this.content + this.outro;148 }149 150 trimEnd(rx) {151 this.outro = this.outro.replace(rx, '');152 if (this.outro.length) return true;153 154 const trimmed = this.content.replace(rx, '');155 156 if (trimmed.length) {157 if (trimmed !== this.content) {158 this.split(this.start + trimmed.length).edit('', undefined, true);159 if (this.edited) {160 // save the change, if it has been edited161 this.edit(trimmed, this.storeName, true);162 }163 }164 return true;165 } else {166 this.edit('', undefined, true);167 168 this.intro = this.intro.replace(rx, '');169 if (this.intro.length) return true;170 }171 }172 173 trimStart(rx) {174 this.intro = this.intro.replace(rx, '');175 if (this.intro.length) return true;176 177 const trimmed = this.content.replace(rx, '');178 179 if (trimmed.length) {180 if (trimmed !== this.content) {181 const newChunk = this.split(this.end - trimmed.length);182 if (this.edited) {183 // save the change, if it has been edited184 newChunk.edit(trimmed, this.storeName, true);185 }186 this.edit('', undefined, true);187 }188 return true;189 } else {190 this.edit('', undefined, true);191 192 this.outro = this.outro.replace(rx, '');193 if (this.outro.length) return true;194 }195 }196}197 198function getBtoa() {199 if (typeof globalThis !== 'undefined' && typeof globalThis.btoa === 'function') {200 return (str) => globalThis.btoa(unescape(encodeURIComponent(str)));201 } else if (typeof Buffer === 'function') {202 return (str) => Buffer.from(str, 'utf-8').toString('base64');203 } else {204 return () => {205 throw new Error('Unsupported environment: `window.btoa` or `Buffer` should be supported.');206 };207 }208}209 210const btoa = /*#__PURE__*/ getBtoa();211 212class SourceMap {213 constructor(properties) {214 this.version = 3;215 this.file = properties.file;216 this.sources = properties.sources;217 this.sourcesContent = properties.sourcesContent;218 this.names = properties.names;219 this.mappings = sourcemapCodec.encode(properties.mappings);220 if (typeof properties.x_google_ignoreList !== 'undefined') {221 this.x_google_ignoreList = properties.x_google_ignoreList;222 }223 if (typeof properties.debugId !== 'undefined') {224 this.debugId = properties.debugId;225 }226 }227 228 toString() {229 return JSON.stringify(this);230 }231 232 toUrl() {233 return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString());234 }235}236 237function guessIndent(code) {238 const lines = code.split('\n');239 240 const tabbed = lines.filter((line) => /^\t+/.test(line));241 const spaced = lines.filter((line) => /^ {2,}/.test(line));242 243 if (tabbed.length === 0 && spaced.length === 0) {244 return null;245 }246 247 // More lines tabbed than spaced? Assume tabs, and248 // default to tabs in the case of a tie (or nothing249 // to go on)250 if (tabbed.length >= spaced.length) {251 return '\t';252 }253 254 // Otherwise, we need to guess the multiple255 const min = spaced.reduce((previous, current) => {256 const numSpaces = /^ +/.exec(current)[0].length;257 return Math.min(numSpaces, previous);258 }, Infinity);259 260 return new Array(min + 1).join(' ');261}262 263function getRelativePath(from, to) {264 const fromParts = from.split(/[/\\]/);265 const toParts = to.split(/[/\\]/);266 267 fromParts.pop(); // get dirname268 269 while (fromParts[0] === toParts[0]) {270 fromParts.shift();271 toParts.shift();272 }273 274 if (fromParts.length) {275 let i = fromParts.length;276 while (i--) fromParts[i] = '..';277 }278 279 return fromParts.concat(toParts).join('/');280}281 282const toString = Object.prototype.toString;283 284function isObject(thing) {285 return toString.call(thing) === '[object Object]';286}287 288function getLocator(source) {289 const originalLines = source.split('\n');290 const lineOffsets = [];291 292 for (let i = 0, pos = 0; i < originalLines.length; i++) {293 lineOffsets.push(pos);294 pos += originalLines[i].length + 1;295 }296 297 return function locate(index) {298 let i = 0;299 let j = lineOffsets.length;300 while (i < j) {301 const m = (i + j) >> 1;302 if (index < lineOffsets[m]) {303 j = m;304 } else {305 i = m + 1;306 }307 }308 const line = i - 1;309 const column = index - lineOffsets[line];310 return { line, column };311 };312}313 314const wordRegex = /\w/;315 316class Mappings {317 constructor(hires) {318 this.hires = hires;319 this.generatedCodeLine = 0;320 this.generatedCodeColumn = 0;321 this.raw = [];322 this.rawSegments = this.raw[this.generatedCodeLine] = [];323 this.pending = null;324 }325 326 addEdit(sourceIndex, content, loc, nameIndex) {327 if (content.length) {328 const contentLengthMinusOne = content.length - 1;329 let contentLineEnd = content.indexOf('\n', 0);330 let previousContentLineEnd = -1;331 // Loop through each line in the content and add a segment, but stop if the last line is empty,332 // else code afterwards would fill one line too many333 while (contentLineEnd >= 0 && contentLengthMinusOne > contentLineEnd) {334 const segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column];335 if (nameIndex >= 0) {336 segment.push(nameIndex);337 }338 this.rawSegments.push(segment);339 340 this.generatedCodeLine += 1;341 this.raw[this.generatedCodeLine] = this.rawSegments = [];342 this.generatedCodeColumn = 0;343 344 previousContentLineEnd = contentLineEnd;345 contentLineEnd = content.indexOf('\n', contentLineEnd + 1);346 }347 348 const segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column];349 if (nameIndex >= 0) {350 segment.push(nameIndex);351 }352 this.rawSegments.push(segment);353 354 this.advance(content.slice(previousContentLineEnd + 1));355 } else if (this.pending) {356 this.rawSegments.push(this.pending);357 this.advance(content);358 }359 360 this.pending = null;361 }362 363 addUneditedChunk(sourceIndex, chunk, original, loc, sourcemapLocations) {364 let originalCharIndex = chunk.start;365 let first = true;366 // when iterating each char, check if it's in a word boundary367 let charInHiresBoundary = false;368 369 while (originalCharIndex < chunk.end) {370 if (original[originalCharIndex] === '\n') {371 loc.line += 1;372 loc.column = 0;373 this.generatedCodeLine += 1;374 this.raw[this.generatedCodeLine] = this.rawSegments = [];375 this.generatedCodeColumn = 0;376 first = true;377 charInHiresBoundary = false;378 } else {379 if (this.hires || first || sourcemapLocations.has(originalCharIndex)) {380 const segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column];381 382 if (this.hires === 'boundary') {383 // in hires "boundary", group segments per word boundary than per char384 if (wordRegex.test(original[originalCharIndex])) {385 // for first char in the boundary found, start the boundary by pushing a segment386 if (!charInHiresBoundary) {387 this.rawSegments.push(segment);388 charInHiresBoundary = true;389 }390 } else {391 // for non-word char, end the boundary by pushing a segment392 this.rawSegments.push(segment);393 charInHiresBoundary = false;394 }395 } else {396 this.rawSegments.push(segment);397 }398 }399 400 loc.column += 1;401 this.generatedCodeColumn += 1;402 first = false;403 }404 405 originalCharIndex += 1;406 }407 408 this.pending = null;409 }410 411 advance(str) {412 if (!str) return;413 414 const lines = str.split('\n');415 416 if (lines.length > 1) {417 for (let i = 0; i < lines.length - 1; i++) {418 this.generatedCodeLine++;419 this.raw[this.generatedCodeLine] = this.rawSegments = [];420 }421 this.generatedCodeColumn = 0;422 }423 424 this.generatedCodeColumn += lines[lines.length - 1].length;425 }426}427 428const n = '\n';429 430const warned = {431 insertLeft: false,432 insertRight: false,433 storeName: false,434};435 436class MagicString {437 constructor(string, options = {}) {438 const chunk = new Chunk(0, string.length, string);439 440 Object.defineProperties(this, {441 original: { writable: true, value: string },442 outro: { writable: true, value: '' },443 intro: { writable: true, value: '' },444 firstChunk: { writable: true, value: chunk },445 lastChunk: { writable: true, value: chunk },446 lastSearchedChunk: { writable: true, value: chunk },447 byStart: { writable: true, value: {} },448 byEnd: { writable: true, value: {} },449 filename: { writable: true, value: options.filename },450 indentExclusionRanges: { writable: true, value: options.indentExclusionRanges },451 sourcemapLocations: { writable: true, value: new BitSet() },452 storedNames: { writable: true, value: {} },453 indentStr: { writable: true, value: undefined },454 ignoreList: { writable: true, value: options.ignoreList },455 offset: { writable: true, value: options.offset || 0 },456 });457 458 this.byStart[0] = chunk;459 this.byEnd[string.length] = chunk;460 }461 462 addSourcemapLocation(char) {463 this.sourcemapLocations.add(char);464 }465 466 append(content) {467 if (typeof content !== 'string') throw new TypeError('outro content must be a string');468 469 this.outro += content;470 return this;471 }472 473 appendLeft(index, content) {474 index = index + this.offset;475 476 if (typeof content !== 'string') throw new TypeError('inserted content must be a string');477 478 this._split(index);479 480 const chunk = this.byEnd[index];481 482 if (chunk) {483 chunk.appendLeft(content);484 } else {485 this.intro += content;486 }487 return this;488 }489 490 appendRight(index, content) {491 index = index + this.offset;492 493 if (typeof content !== 'string') throw new TypeError('inserted content must be a string');494 495 this._split(index);496 497 const chunk = this.byStart[index];498 499 if (chunk) {500 chunk.appendRight(content);501 } else {502 this.outro += content;503 }504 return this;505 }506 507 clone() {508 const cloned = new MagicString(this.original, { filename: this.filename, offset: this.offset });509 510 let originalChunk = this.firstChunk;511 let clonedChunk = (cloned.firstChunk = cloned.lastSearchedChunk = originalChunk.clone());512 513 while (originalChunk) {514 cloned.byStart[clonedChunk.start] = clonedChunk;515 cloned.byEnd[clonedChunk.end] = clonedChunk;516 517 const nextOriginalChunk = originalChunk.next;518 const nextClonedChunk = nextOriginalChunk && nextOriginalChunk.clone();519 520 if (nextClonedChunk) {521 clonedChunk.next = nextClonedChunk;522 nextClonedChunk.previous = clonedChunk;523 524 clonedChunk = nextClonedChunk;525 }526 527 originalChunk = nextOriginalChunk;528 }529 530 cloned.lastChunk = clonedChunk;531 532 if (this.indentExclusionRanges) {533 cloned.indentExclusionRanges = this.indentExclusionRanges.slice();534 }535 536 cloned.sourcemapLocations = new BitSet(this.sourcemapLocations);537 538 cloned.intro = this.intro;539 cloned.outro = this.outro;540 541 return cloned;542 }543 544 generateDecodedMap(options) {545 options = options || {};546 547 const sourceIndex = 0;548 const names = Object.keys(this.storedNames);549 const mappings = new Mappings(options.hires);550 551 const locate = getLocator(this.original);552 553 if (this.intro) {554 mappings.advance(this.intro);555 }556 557 this.firstChunk.eachNext((chunk) => {558 const loc = locate(chunk.start);559 560 if (chunk.intro.length) mappings.advance(chunk.intro);561 562 if (chunk.edited) {563 mappings.addEdit(564 sourceIndex,565 chunk.content,566 loc,567 chunk.storeName ? names.indexOf(chunk.original) : -1,568 );569 } else {570 mappings.addUneditedChunk(sourceIndex, chunk, this.original, loc, this.sourcemapLocations);571 }572 573 if (chunk.outro.length) mappings.advance(chunk.outro);574 });575 576 if (this.outro) {577 mappings.advance(this.outro);578 }579 580 return {581 file: options.file ? options.file.split(/[/\\]/).pop() : undefined,582 sources: [583 options.source ? getRelativePath(options.file || '', options.source) : options.file || '',584 ],585 sourcesContent: options.includeContent ? [this.original] : undefined,586 names,587 mappings: mappings.raw,588 x_google_ignoreList: this.ignoreList ? [sourceIndex] : undefined,589 };590 }591 592 generateMap(options) {593 return new SourceMap(this.generateDecodedMap(options));594 }595 596 _ensureindentStr() {597 if (this.indentStr === undefined) {598 this.indentStr = guessIndent(this.original);599 }600 }601 602 _getRawIndentString() {603 this._ensureindentStr();604 return this.indentStr;605 }606 607 getIndentString() {608 this._ensureindentStr();609 return this.indentStr === null ? '\t' : this.indentStr;610 }611 612 indent(indentStr, options) {613 const pattern = /^[^\r\n]/gm;614 615 if (isObject(indentStr)) {616 options = indentStr;617 indentStr = undefined;618 }619 620 if (indentStr === undefined) {621 this._ensureindentStr();622 indentStr = this.indentStr || '\t';623 }624 625 if (indentStr === '') return this; // noop626 627 options = options || {};628 629 // Process exclusion ranges630 const isExcluded = {};631 632 if (options.exclude) {633 const exclusions =634 typeof options.exclude[0] === 'number' ? [options.exclude] : options.exclude;635 exclusions.forEach((exclusion) => {636 for (let i = exclusion[0]; i < exclusion[1]; i += 1) {637 isExcluded[i] = true;638 }639 });640 }641 642 let shouldIndentNextCharacter = options.indentStart !== false;643 const replacer = (match) => {644 if (shouldIndentNextCharacter) return `${indentStr}${match}`;645 shouldIndentNextCharacter = true;646 return match;647 };648 649 this.intro = this.intro.replace(pattern, replacer);650 651 let charIndex = 0;652 let chunk = this.firstChunk;653 654 while (chunk) {655 const end = chunk.end;656 657 if (chunk.edited) {658 if (!isExcluded[charIndex]) {659 chunk.content = chunk.content.replace(pattern, replacer);660 661 if (chunk.content.length) {662 shouldIndentNextCharacter = chunk.content[chunk.content.length - 1] === '\n';663 }664 }665 } else {666 charIndex = chunk.start;667 668 while (charIndex < end) {669 if (!isExcluded[charIndex]) {670 const char = this.original[charIndex];671 672 if (char === '\n') {673 shouldIndentNextCharacter = true;674 } else if (char !== '\r' && shouldIndentNextCharacter) {675 shouldIndentNextCharacter = false;676 677 if (charIndex === chunk.start) {678 chunk.prependRight(indentStr);679 } else {680 this._splitChunk(chunk, charIndex);681 chunk = chunk.next;682 chunk.prependRight(indentStr);683 }684 }685 }686 687 charIndex += 1;688 }689 }690 691 charIndex = chunk.end;692 chunk = chunk.next;693 }694 695 this.outro = this.outro.replace(pattern, replacer);696 697 return this;698 }699 700 insert() {701 throw new Error(702 'magicString.insert(...) is deprecated. Use prependRight(...) or appendLeft(...)',703 );704 }705 706 insertLeft(index, content) {707 if (!warned.insertLeft) {708 console.warn(709 'magicString.insertLeft(...) is deprecated. Use magicString.appendLeft(...) instead',710 );711 warned.insertLeft = true;712 }713 714 return this.appendLeft(index, content);715 }716 717 insertRight(index, content) {718 if (!warned.insertRight) {719 console.warn(720 'magicString.insertRight(...) is deprecated. Use magicString.prependRight(...) instead',721 );722 warned.insertRight = true;723 }724 725 return this.prependRight(index, content);726 }727 728 move(start, end, index) {729 start = start + this.offset;730 end = end + this.offset;731 index = index + this.offset;732 733 if (index >= start && index <= end) throw new Error('Cannot move a selection inside itself');734 735 this._split(start);736 this._split(end);737 this._split(index);738 739 const first = this.byStart[start];740 const last = this.byEnd[end];741 742 const oldLeft = first.previous;743 const oldRight = last.next;744 745 const newRight = this.byStart[index];746 if (!newRight && last === this.lastChunk) return this;747 const newLeft = newRight ? newRight.previous : this.lastChunk;748 749 if (oldLeft) oldLeft.next = oldRight;750 if (oldRight) oldRight.previous = oldLeft;751 752 if (newLeft) newLeft.next = first;753 if (newRight) newRight.previous = last;754 755 if (!first.previous) this.firstChunk = last.next;756 if (!last.next) {757 this.lastChunk = first.previous;758 this.lastChunk.next = null;759 }760 761 first.previous = newLeft;762 last.next = newRight || null;763 764 if (!newLeft) this.firstChunk = first;765 if (!newRight) this.lastChunk = last;766 return this;767 }768 769 overwrite(start, end, content, options) {770 options = options || {};771 return this.update(start, end, content, { ...options, overwrite: !options.contentOnly });772 }773 774 update(start, end, content, options) {775 start = start + this.offset;776 end = end + this.offset;777 778 if (typeof content !== 'string') throw new TypeError('replacement content must be a string');779 780 if (this.original.length !== 0) {781 while (start < 0) start += this.original.length;782 while (end < 0) end += this.original.length;783 }784 785 if (end > this.original.length) throw new Error('end is out of bounds');786 if (start === end)787 throw new Error(788 'Cannot overwrite a zero-length range – use appendLeft or prependRight instead',789 );790 791 this._split(start);792 this._split(end);793 794 if (options === true) {795 if (!warned.storeName) {796 console.warn(797 'The final argument to magicString.overwrite(...) should be an options object. See https://github.com/rich-harris/magic-string',798 );799 warned.storeName = true;800 }801 802 options = { storeName: true };803 }804 const storeName = options !== undefined ? options.storeName : false;805 const overwrite = options !== undefined ? options.overwrite : false;806 807 if (storeName) {808 const original = this.original.slice(start, end);809 Object.defineProperty(this.storedNames, original, {810 writable: true,811 value: true,812 enumerable: true,813 });814 }815 816 const first = this.byStart[start];817 const last = this.byEnd[end];818 819 if (first) {820 let chunk = first;821 while (chunk !== last) {822 if (chunk.next !== this.byStart[chunk.end]) {823 throw new Error('Cannot overwrite across a split point');824 }825 chunk = chunk.next;826 chunk.edit('', false);827 }828 829 first.edit(content, storeName, !overwrite);830 } else {831 // must be inserting at the end832 const newChunk = new Chunk(start, end, '').edit(content, storeName);833 834 // TODO last chunk in the array may not be the last chunk, if it's moved...835 last.next = newChunk;836 newChunk.previous = last;837 }838 return this;839 }840 841 prepend(content) {842 if (typeof content !== 'string') throw new TypeError('outro content must be a string');843 844 this.intro = content + this.intro;845 return this;846 }847 848 prependLeft(index, content) {849 index = index + this.offset;850 851 if (typeof content !== 'string') throw new TypeError('inserted content must be a string');852 853 this._split(index);854 855 const chunk = this.byEnd[index];856 857 if (chunk) {858 chunk.prependLeft(content);859 } else {860 this.intro = content + this.intro;861 }862 return this;863 }864 865 prependRight(index, content) {866 index = index + this.offset;867 868 if (typeof content !== 'string') throw new TypeError('inserted content must be a string');869 870 this._split(index);871 872 const chunk = this.byStart[index];873 874 if (chunk) {875 chunk.prependRight(content);876 } else {877 this.outro = content + this.outro;878 }879 return this;880 }881 882 remove(start, end) {883 start = start + this.offset;884 end = end + this.offset;885 886 if (this.original.length !== 0) {887 while (start < 0) start += this.original.length;888 while (end < 0) end += this.original.length;889 }890 891 if (start === end) return this;892 893 if (start < 0 || end > this.original.length) throw new Error('Character is out of bounds');894 if (start > end) throw new Error('end must be greater than start');895 896 this._split(start);897 this._split(end);898 899 let chunk = this.byStart[start];900 901 while (chunk) {902 chunk.intro = '';903 chunk.outro = '';904 chunk.edit('');905 906 chunk = end > chunk.end ? this.byStart[chunk.end] : null;907 }908 return this;909 }910 911 reset(start, end) {912 start = start + this.offset;913 end = end + this.offset;914 915 if (this.original.length !== 0) {916 while (start < 0) start += this.original.length;917 while (end < 0) end += this.original.length;918 }919 920 if (start === end) return this;921 922 if (start < 0 || end > this.original.length) throw new Error('Character is out of bounds');923 if (start > end) throw new Error('end must be greater than start');924 925 this._split(start);926 this._split(end);927 928 let chunk = this.byStart[start];929 930 while (chunk) {931 chunk.reset();932 933 chunk = end > chunk.end ? this.byStart[chunk.end] : null;934 }935 return this;936 }937 938 lastChar() {939 if (this.outro.length) return this.outro[this.outro.length - 1];940 let chunk = this.lastChunk;941 do {942 if (chunk.outro.length) return chunk.outro[chunk.outro.length - 1];943 if (chunk.content.length) return chunk.content[chunk.content.length - 1];944 if (chunk.intro.length) return chunk.intro[chunk.intro.length - 1];945 } while ((chunk = chunk.previous));946 if (this.intro.length) return this.intro[this.intro.length - 1];947 return '';948 }949 950 lastLine() {951 let lineIndex = this.outro.lastIndexOf(n);952 if (lineIndex !== -1) return this.outro.substr(lineIndex + 1);953 let lineStr = this.outro;954 let chunk = this.lastChunk;955 do {956 if (chunk.outro.length > 0) {957 lineIndex = chunk.outro.lastIndexOf(n);958 if (lineIndex !== -1) return chunk.outro.substr(lineIndex + 1) + lineStr;959 lineStr = chunk.outro + lineStr;960 }961 962 if (chunk.content.length > 0) {963 lineIndex = chunk.content.lastIndexOf(n);964 if (lineIndex !== -1) return chunk.content.substr(lineIndex + 1) + lineStr;965 lineStr = chunk.content + lineStr;966 }967 968 if (chunk.intro.length > 0) {969 lineIndex = chunk.intro.lastIndexOf(n);970 if (lineIndex !== -1) return chunk.intro.substr(lineIndex + 1) + lineStr;971 lineStr = chunk.intro + lineStr;972 }973 } while ((chunk = chunk.previous));974 lineIndex = this.intro.lastIndexOf(n);975 if (lineIndex !== -1) return this.intro.substr(lineIndex + 1) + lineStr;976 return this.intro + lineStr;977 }978 979 slice(start = 0, end = this.original.length - this.offset) {980 start = start + this.offset;981 end = end + this.offset;982 983 if (this.original.length !== 0) {984 while (start < 0) start += this.original.length;985 while (end < 0) end += this.original.length;986 }987 988 let result = '';989 990 // find start chunk991 let chunk = this.firstChunk;992 while (chunk && (chunk.start > start || chunk.end <= start)) {993 // found end chunk before start994 if (chunk.start < end && chunk.end >= end) {995 return result;996 }997 998 chunk = chunk.next;999 }1000 1001 if (chunk && chunk.edited && chunk.start !== start)1002 throw new Error(`Cannot use replaced character ${start} as slice start anchor.`);1003 1004 const startChunk = chunk;1005 while (chunk) {1006 if (chunk.intro && (startChunk !== chunk || chunk.start === start)) {1007 result += chunk.intro;1008 }1009 1010 const containsEnd = chunk.start < end && chunk.end >= end;1011 if (containsEnd && chunk.edited && chunk.end !== end)1012 throw new Error(`Cannot use replaced character ${end} as slice end anchor.`);1013 1014 const sliceStart = startChunk === chunk ? start - chunk.start : 0;1015 const sliceEnd = containsEnd ? chunk.content.length + end - chunk.end : chunk.content.length;1016 1017 result += chunk.content.slice(sliceStart, sliceEnd);1018 1019 if (chunk.outro && (!containsEnd || chunk.end === end)) {1020 result += chunk.outro;1021 }1022 1023 if (containsEnd) {1024 break;1025 }1026 1027 chunk = chunk.next;1028 }1029 1030 return result;1031 }1032 1033 // TODO deprecate this? not really very useful1034 snip(start, end) {1035 const clone = this.clone();1036 clone.remove(0, start);1037 clone.remove(end, clone.original.length);1038 1039 return clone;1040 }1041 1042 _split(index) {1043 if (this.byStart[index] || this.byEnd[index]) return;1044 1045 let chunk = this.lastSearchedChunk;1046 let previousChunk = chunk;1047 const searchForward = index > chunk.end;1048 1049 while (chunk) {1050 if (chunk.contains(index)) return this._splitChunk(chunk, index);1051 1052 chunk = searchForward ? this.byStart[chunk.end] : this.byEnd[chunk.start];1053 1054 // Prevent infinite loop (e.g. via empty chunks, where start === end)1055 if (chunk === previousChunk) return;1056 1057 previousChunk = chunk;1058 }1059 }1060 1061 _splitChunk(chunk, index) {1062 if (chunk.edited && chunk.content.length) {1063 // zero-length edited chunks are a special case (overlapping replacements)1064 const loc = getLocator(this.original)(index);1065 throw new Error(1066 `Cannot split a chunk that has already been edited (${loc.line}:${loc.column} – "${chunk.original}")`,1067 );1068 }1069 1070 const newChunk = chunk.split(index);1071 1072 this.byEnd[index] = chunk;1073 this.byStart[index] = newChunk;1074 this.byEnd[newChunk.end] = newChunk;1075 1076 if (chunk === this.lastChunk) this.lastChunk = newChunk;1077 1078 this.lastSearchedChunk = chunk;1079 return true;1080 }1081 1082 toString() {1083 let str = this.intro;1084 1085 let chunk = this.firstChunk;1086 while (chunk) {1087 str += chunk.toString();1088 chunk = chunk.next;1089 }1090 1091 return str + this.outro;1092 }1093 1094 isEmpty() {1095 let chunk = this.firstChunk;1096 do {1097 if (1098 (chunk.intro.length && chunk.intro.trim()) ||1099 (chunk.content.length && chunk.content.trim()) ||1100 (chunk.outro.length && chunk.outro.trim())1101 )1102 return false;1103 } while ((chunk = chunk.next));1104 return true;1105 }1106 1107 length() {1108 let chunk = this.firstChunk;1109 let length = 0;1110 do {1111 length += chunk.intro.length + chunk.content.length + chunk.outro.length;1112 } while ((chunk = chunk.next));1113 return length;1114 }1115 1116 trimLines() {1117 return this.trim('[\\r\\n]');1118 }1119 1120 trim(charType) {1121 return this.trimStart(charType).trimEnd(charType);1122 }1123 1124 trimEndAborted(charType) {1125 const rx = new RegExp((charType || '\\s') + '+$');1126 1127 this.outro = this.outro.replace(rx, '');1128 if (this.outro.length) return true;1129 1130 let chunk = this.lastChunk;1131 1132 do {1133 const end = chunk.end;1134 const aborted = chunk.trimEnd(rx);1135 1136 // if chunk was trimmed, we have a new lastChunk1137 if (chunk.end !== end) {1138 if (this.lastChunk === chunk) {1139 this.lastChunk = chunk.next;1140 }1141 1142 this.byEnd[chunk.end] = chunk;1143 this.byStart[chunk.next.start] = chunk.next;1144 this.byEnd[chunk.next.end] = chunk.next;1145 }1146 1147 if (aborted) return true;1148 chunk = chunk.previous;1149 } while (chunk);1150 1151 return false;1152 }1153 1154 trimEnd(charType) {1155 this.trimEndAborted(charType);1156 return this;1157 }1158 trimStartAborted(charType) {1159 const rx = new RegExp('^' + (charType || '\\s') + '+');1160 1161 this.intro = this.intro.replace(rx, '');1162 if (this.intro.length) return true;1163 1164 let chunk = this.firstChunk;1165 1166 do {1167 const end = chunk.end;1168 const aborted = chunk.trimStart(rx);1169 1170 if (chunk.end !== end) {1171 // special case...1172 if (chunk === this.lastChunk) this.lastChunk = chunk.next;1173 1174 this.byEnd[chunk.end] = chunk;1175 this.byStart[chunk.next.start] = chunk.next;1176 this.byEnd[chunk.next.end] = chunk.next;1177 }1178 1179 if (aborted) return true;1180 chunk = chunk.next;1181 } while (chunk);1182 1183 return false;1184 }1185 1186 trimStart(charType) {1187 this.trimStartAborted(charType);1188 return this;1189 }1190 1191 hasChanged() {1192 return this.original !== this.toString();1193 }1194 1195 _replaceRegexp(searchValue, replacement) {1196 function getReplacement(match, str) {1197 if (typeof replacement === 'string') {1198 return replacement.replace(/\$(\$|&|\d+)/g, (_, i) => {1199 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_a_parameter1200 if (i === '$') return '$';