UNPKG

codemirror-wrapped-line-indent

Version:
107 lines (106 loc) 3.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.wrappedLineIndent = void 0; const language_1 = require("@codemirror/language"); const state_1 = require("@codemirror/state"); const view_1 = require("@codemirror/view"); class WrappedLineIndent { constructor(view) { this.view = view; this.indentUnit = (0, language_1.getIndentUnit)(view.state); this.initialPaddingLeft = null; this.isChrome = window === null || window === void 0 ? void 0 : window.navigator.userAgent.includes("Chrome"); this.generate(view.state); } update(update) { const indentUnit = (0, language_1.getIndentUnit)(update.state); if (indentUnit !== this.indentUnit || update.docChanged || update.viewportChanged) { this.indentUnit = indentUnit; this.generate(update.state); } } generate(state) { const builder = new state_1.RangeSetBuilder(); if (this.initialPaddingLeft) { this.addStyleToBuilder(builder, state, this.initialPaddingLeft); } else { this.view.requestMeasure({ read: (view) => { const lineElement = view.contentDOM.querySelector(".cm-line"); if (lineElement) { this.initialPaddingLeft = window .getComputedStyle(lineElement) .getPropertyValue("padding-left"); this.addStyleToBuilder(builder, view.state, this.initialPaddingLeft); } this.decorations = builder.finish(); }, }); } this.decorations = builder.finish(); } addStyleToBuilder(builder, state, initialPaddingLeft) { const visibleLines = this.getVisibleLines(state); for (const line of visibleLines) { const { numColumns, containsTab } = this.numColumns(line.text, state.tabSize); const paddingValue = `calc(${numColumns + this.indentUnit}ch + ${initialPaddingLeft})`; const textIndentValue = this.isChrome ? `calc(-${numColumns + this.indentUnit}ch - ${containsTab ? 1 : 0}px)` : `-${numColumns + this.indentUnit}ch`; builder.add(line.from, line.from, view_1.Decoration.line({ attributes: { style: `padding-left: ${paddingValue}; text-indent: ${textIndentValue};`, }, })); } } // Get all lines that are currently visible in the viewport. getVisibleLines(state) { const lines = new Set(); let lastLine = null; for (const { from, to } of this.view.visibleRanges) { let pos = from; while (pos <= to) { const line = state.doc.lineAt(pos); if (lastLine !== line) { lines.add(line); lastLine = line; } pos = line.to + 1; } } return lines; } numColumns(str, tabSize) { let cols = 0; let containsTab = false; loop: for (let i = 0; i < str.length; i++) { switch (str[i]) { case " ": { cols += 1; continue loop; } case "\t": { cols += tabSize - (cols % tabSize); containsTab = true; continue loop; } case "\r": { continue loop; } default: { break loop; } } } return { numColumns: cols, containsTab }; } } exports.wrappedLineIndent = [ view_1.ViewPlugin.fromClass(WrappedLineIndent, { decorations: (v) => v.decorations, }), ];