UNPKG

prism-code-editor

Version:

Lightweight, extensible code editor component for the web using Prism

249 lines (248 loc) 8.24 kB
import { n as numLines, l as languageMap, c as createTemplate, b as addListener } from "../../index-q0zRzWVD.js"; import { u as updateNode, f as getLineBefore, k as getLineEnd } from "../../index-CxiLA9IO.js"; const template = /* @__PURE__ */ createTemplate("<div><div> "); const template2 = /* @__PURE__ */ createTemplate( "<div class=pce-unfold> <span title=Unfold>   </span> " ); const isMultiline = (str, start, end) => str.slice(start, end).includes("\n"); const readOnlyCodeFolding = (...providers) => { let cEditor; let value; let code; let lines; let lineNumberWidth; let textarea; let foldPositions; const foldToggles = []; const foldPlaceholders = []; const foldedLines = /* @__PURE__ */ new Set(); const foldedRanges = /* @__PURE__ */ new Set(); const getPosition = (pos) => { let result = pos; for (let [start, end] of foldedRanges) { if (pos > start) { if (pos < end) return -1; result -= end - start - 3; } } return result; }; const toggleFold = (line) => { const start = foldPositions[line][0]; const addFold = (line2) => { let [start2, end] = foldPositions[line2]; let expanded; for (let range of foldedRanges) { if (start2 <= range[0] && end > range[0]) { if (expanded) foldedRanges.delete(range); else { range[0] = start2; if (end > range[1]) range[1] = end; expanded = true; } } } if (!expanded) foldedRanges.add([start2, end]); }; if (foldedLines.has(line)) { foldedLines.delete(line); for (let range of foldedRanges) { if (start == range[0]) { foldedRanges.delete(range); for (let currentLine of foldedLines) { const pos = foldPositions[currentLine][0]; if (pos > start) addFold(currentLine); } break; } } } else { foldedLines.add(line); addFold(line); } }; const update = (line) => { value = ""; let pos = 0; for (let [start, end] of [...foldedRanges].sort((a, b) => a[0] - b[0])) { value += code.slice(pos, start) + "   "; pos = end; } textarea.value = value += code.slice(pos); if (line) textarea.setSelectionRange(pos = getPosition(foldPositions[line][0]), pos); cEditor.update(); cEditor.container.style.setProperty("--number-width", lineNumberWidth); updateFolds(); }; const updateFolds = () => { for (let line = 0, l = foldPositions.length, prev; line < l; line++) { if (!foldPositions[line]) continue; let pos = getPosition(foldPositions[line][0]); if (pos + 1) { let parent = lines[numLines(value, 0, pos)]; let el = foldToggles[line]; let isClosed = foldedLines.has(line); let pos2 = getPosition(foldPositions[line][1]); if (!el) { el = foldToggles[line] = template(); addListener(el, "click", () => toggleAndUpdate(line)); } if (parent != el.parentNode && parent != prev) parent.prepend(el); prev = parent; el.className = `pce-fold${isClosed ? " closed-fold" : ""}`; el.title = `${isClosed ? "Unf" : "F"}old line`; el = foldPlaceholders[line]; if (isClosed) { if (!el) { el = foldPlaceholders[line] = template2(); addListener(el, "click", () => toggleAndUpdate(line)); } el.style.counterIncrement = `line ${numLines(code, ...foldPositions[line]) - 1}`; updateNode(el.firstChild, getLineBefore(value, pos)); updateNode(el.lastChild, value.slice(pos2, getLineEnd(value, pos2))); if (parent != el.parentNode) parent.prepend(el); } else el?.remove(); } } }; const toggleAndUpdate = (line) => { toggleFold(line); update(line); }; const createFolds = () => { foldPositions = []; foldedRanges.clear(); foldedLines.clear(); value = code = cEditor.value; lineNumberWidth = (0 | Math.log10(numLines(code))) + 1 + ".001ch"; const folds = []; providers.forEach((clb) => folds.push(...clb(cEditor, folds) || [])); for (let i = 0, l = folds.length; i < l; i++) { const [start, end] = folds[i]; const index = numLines(value, 0, start); if (!foldPositions[index] || end > foldPositions[index][1]) foldPositions[index] = [start, end]; } updateFolds(); }; return { update(editor, options) { if (!cEditor) { cEditor = editor; textarea = editor.textarea; editor.extensions.codeFold = this; lines = editor.lines; if (editor.tokens[0]) createFolds(); } editor.container.style.setProperty( "--padding-left", options.lineNumbers == false ? "calc(var(--_pse) + var(--_ns))" : "" ); setTimeout(editor.on("update", createFolds)); }, get fullCode() { return code; }, toggleFold: (lineNumber, force) => !!foldPositions[lineNumber] && foldedLines.has(lineNumber) != force && !toggleFold(lineNumber), updateFolds: () => update() }; }; const bracketFolding = ({ value, extensions: { matchBrackets } }) => { if (matchBrackets) { let folds = []; let { brackets, pairs } = matchBrackets; let i = 0; let j; let l = pairs.length; for (; i < l; i++) { if ((j = pairs[i]) > i && isMultiline(value, brackets[i][1], brackets[j][1])) { folds.push([brackets[i][2], brackets[j][1]]); } } return folds; } }; const tagFolding = ({ value, extensions: { matchTags } }) => { if (matchTags) { let folds = []; let { tags, pairs } = matchTags; let i = 0; let j; let l = pairs.length; for (; i < l; i++) { if ((j = pairs[i]) > i && isMultiline(value, tags[i][2], tags[j][1])) { folds.push([tags[i][2], tags[j][1]]); } } return folds; } }; const blockCommentFolding = ({ tokens, value, options: { language } }) => { const folds = []; const findBlockComments = (tokens2, position, language2) => { for (let i = 0, l = tokens2.length; i < l; ) { const token = tokens2[i++]; const content = token.content; const length = token.length; const aliasType = token.alias || token.type; if (aliasType == "comment" && isMultiline(value, position, position + length)) { let comment = languageMap[language2]?.comments?.block; if (comment && value.indexOf(comment[0], position) == position) folds.push([position + comment[0].length, position + length - comment[1].length]); } else if (Array.isArray(content)) { findBlockComments( content, position, aliasType.slice(0, 9) == "language-" ? aliasType.slice(9) : language2 ); } position += length; } }; findBlockComments(tokens, 0, language); return folds; }; const markdownFolding = ({ tokens, value, options: { language } }) => { if (language == "markdown" || language == "md") { let folds = []; let pos = 0; let openTitles = []; let levels; let closeTitles = (level) => { for (let end = value.slice(0, pos).trimEnd().length; level <= levels; ) { folds.push([openTitles[level++], end]); } }; let i = 0; let l = tokens.length; for (; i < l; ) { const token = tokens[i++]; const length = token.length; const type = token.type; if (type == "code" && !token.alias) { let content = token.content; folds.push([ pos + content[0].length + (content[1].content || "").length, pos + length - content[content.length - 1].length - 1 ]); } if (type == "title") { let [token1, token2] = token.content; let level = token1.type ? token1.length - 1 : token2.content[0] == "=" ? 0 : 1; closeTitles(level); openTitles[levels = level] = pos + (token1.type ? length : token1.length - 1); } pos += length; } closeTitles(0); return folds; } }; export { blockCommentFolding, bracketFolding, markdownFolding, readOnlyCodeFolding, tagFolding }; //# sourceMappingURL=index.js.map