prism-code-editor
Version:
Lightweight, extensible code editor component for the web using Prism
105 lines (104 loc) • 3.68 kB
JavaScript
import { i as doc, r as createTemplate } from "../core-E7btWBqK.js";
//#region src/extensions/guides.ts
/** @module guides */
var template = /* @__PURE__ */ createTemplate("<div class=guide-indents> ");
/**
* Extension adding indent guides to an editor. Does not work with word wrap.
* Requires styles from `prism-code-editor/guides.css`
*/
var indentGuides = () => {
let tabSize;
let prevLength = 0;
let lineIndentMap;
let active;
let currentEditor;
let lines = [];
let indents = [];
let container;
let update = (code) => {
lineIndentMap = [];
const newIndents = getIndentGuides(code, tabSize);
const l = newIndents.length;
for (let i = 0, prev = [], next = newIndents[0]; next; i++) {
const style = (lines[i] ||= doc.createElement("div")).style;
const [top, left, height] = next;
const old = indents[i];
next = newIndents[i + 1];
if (top != old?.[0]) style.top = top + "00%";
if (left != old?.[1]) style.left = left + "00%";
if (height != old?.[2]) style.height = height + "00%";
const isSingleIndent = prev[0] != top && next?.[0] != top, isSingleOutdent = prev[0] + prev[1] != top + height && next?.[0] + next?.[1] != top + height;
for (let j = -isSingleIndent, l = height + isSingleOutdent; j < l; j++) lineIndentMap[j + top] = i;
prev = indents[i] = newIndents[i];
}
for (let i = l; i < prevLength;) lines[i++].remove();
container.append(...lines.slice(prevLength, prevLength = l));
};
let updateActive = () => {
const newActive = lines[lineIndentMap[currentEditor.activeLine - 1]];
if (newActive != active) {
if (active) active.className = "";
if (newActive) newActive.className = "active-indent";
active = newActive;
}
};
return { update(editor, options) {
if (!currentEditor) {
currentEditor = editor;
let overlays = editor.lines[0];
if (container = overlays.querySelector(".guide-indents")) {
lines.push(...container.children);
active = lines.find((line) => line.className);
} else overlays.append(container = template());
editor.on("update", update);
editor.on("selectionChange", updateActive);
}
container.style.display = options.wordWrap ? "none" : "";
if (tabSize != (tabSize = options.tabSize || 2)) {
update(editor.value);
updateActive();
}
} };
};
/**
* Calculates the position and height of indentation guides for a string of code.
* @param code Code you want to calculate indentation lines for.
* @param tabSize Number of spaces a tab is equal to.
* @returns An array of indentation guides.
* Each guide is a tuple containing 3 numbers with the following values:
* - The starting line of the guide.
* - How many tabs the guide is offset to the right.
* - How many lines tall the guide is.
*/
var getIndentGuides = (code, tabSize) => {
const lines = code.split("\n");
const l = lines.length;
const stack = [];
const results = [];
for (let prevIndent = 0, emptyPos = -1, i = 0, p = 0;; i++) {
let last = i == l;
let line = lines[i];
let pos = last ? 0 : line.search(/\S/);
let indent = 0;
let j = 0;
if (pos < 0) {
if (emptyPos < 0) emptyPos = i;
} else {
for (; j < pos;) indent += line[j++] == " " ? tabSize - indent % tabSize : 1;
if (indent) indent = Math.ceil(indent / tabSize);
for (j = indent; j < prevIndent; j++) stack[j][2] = (emptyPos < 0 || j == indent && !last ? i : emptyPos) - stack[j][0];
for (j = prevIndent; j < indent;) results[p++] = stack[j] = [
emptyPos < 0 || j > prevIndent ? i : emptyPos,
j++,
0
];
emptyPos = -1;
prevIndent = indent;
}
if (last) break;
}
return results;
};
//#endregion
export { getIndentGuides, indentGuides };
//# sourceMappingURL=guides.js.map