window.EditorTables = (function () { function repeat(ch, n) { var s = ''; for (var i = 0; i < n; i++) s += ch; return s; } function padLeft(s, w) { while (s.length < w) s = ' ' + s; return s; } function padRight(s, w) { while (s.length < w) s += ' '; return s; } function padCenter(s, w) { while (s.length < w) { s = s + ' '; if (s.length < w) s = ' ' + s; } return s; } function parseTableRow(line) { var trimmed = line.trim(); if (trimmed.charAt(0) === '|') trimmed = trimmed.slice(1); if (trimmed.charAt(trimmed.length - 1) === '|') trimmed = trimmed.slice(0, -1); return trimmed.split('|').map(function (c) { return c.trim(); }); } function isSeparatorRow(cells) { return cells.every(function (c) { return /^:?-+:?$/.test(c); }); } function parseAlignment(cell) { var left = cell.charAt(0) === ':'; var right = cell.charAt(cell.length - 1) === ':'; if (left && right) return 'center'; if (left) return 'left'; if (right) return 'right'; return null; } function makeSepCell(width, align) { if (align === 'left') return ':' + repeat('-', width - 1); if (align === 'center') return ':' + repeat('-', width - 2) + ':'; if (align === 'right') return repeat('-', width - 1) + ':'; return repeat('-', width); } function findTableRange(text, cursorPos) { var lines = text.split('\n'); var charCount = 0; var cursorLine = 0; for (var i = 0; i < lines.length; i++) { if (charCount + lines[i].length >= cursorPos && charCount <= cursorPos) { cursorLine = i; } charCount += lines[i].length + 1; } if (!/^\|.*\|$/.test(lines[cursorLine].trim())) return null; var start = cursorLine; while (start > 0 && /^\|.*\|$/.test(lines[start - 1].trim())) start--; var end = cursorLine; while (end < lines.length - 1 && /^\|.*\|$/.test(lines[end + 1].trim())) end++; if (end - start < 1) return null; return { start: start, end: end, lines: lines, cursorLine: cursorLine }; } function formatTableText(text, cursorPos) { var range = findTableRange(text, cursorPos); if (!range) return null; var rows = []; var sepIndex = -1; var alignments = []; for (var i = range.start; i <= range.end; i++) { var cells = parseTableRow(range.lines[i]); if (sepIndex === -1 && isSeparatorRow(cells)) { sepIndex = rows.length; alignments = cells.map(function (c) { return parseAlignment(c); }); } rows.push(cells); } if (sepIndex === -1) return null; var colCount = 0; rows.forEach(function (r) { if (r.length > colCount) colCount = r.length; }); while (alignments.length < colCount) alignments.push(null); rows = rows.map(function (r) { while (r.length < colCount) r.push(''); return r; }); var widths = []; for (var c = 0; c < colCount; c++) { var max = 3; for (var r = 0; r < rows.length; r++) { if (r === sepIndex) continue; if (rows[r][c].length > max) max = rows[r][c].length; } widths.push(max); } var formatted = rows.map(function (row, ri) { var cells = row.map(function (cell, ci) { var w = widths[ci]; if (ri === sepIndex) return makeSepCell(w, alignments[ci]); var align = alignments[ci]; if (align === 'right') return padLeft(cell, w); if (align === 'center') return padCenter(cell, w); return padRight(cell, w); }); return '| ' + cells.join(' | ') + ' |'; }); var beforeTable = range.lines.slice(0, range.start).join('\n'); var afterTable = range.lines.slice(range.end + 1).join('\n'); var parts = []; if (beforeTable) parts.push(beforeTable); parts.push(formatted.join('\n')); if (afterTable) parts.push(afterTable); var newText = parts.join('\n'); var oldBeforeLen = 0; for (var i = 0; i < range.start; i++) oldBeforeLen += range.lines[i].length + 1; var cursorInTable = cursorPos - oldBeforeLen; var newTableText = formatted.join('\n'); var newCursor = (beforeTable ? beforeTable.length + 1 : 0) + Math.min(cursorInTable, newTableText.length); return { text: newText, cursor: newCursor }; } function getCursorColumn(text, cursorPos) { var range = findTableRange(text, cursorPos); if (!range) return null; var lines = text.split('\n'); var charCount = 0; for (var i = 0; i < range.cursorLine; i++) charCount += lines[i].length + 1; var lineOffset = cursorPos - charCount; var line = lines[range.cursorLine]; var col = -1; for (var c = 0; c < line.length; c++) { if (line.charAt(c) === '|') { col++; if (c >= lineOffset) return Math.max(col - 1, 0); } } return Math.max(col, 0); } function setColumnAlignment(text, cursorPos, align) { var range = findTableRange(text, cursorPos); if (!range) return null; var colIdx = getCursorColumn(text, cursorPos); if (colIdx === null) return null; var rows = []; var sepIndex = -1; for (var i = range.start; i <= range.end; i++) { var cells = parseTableRow(range.lines[i]); if (sepIndex === -1 && isSeparatorRow(cells)) sepIndex = rows.length; rows.push(cells); } if (sepIndex === -1 || colIdx >= rows[sepIndex].length) return null; var cell = rows[sepIndex][colIdx].replace(/:/g, '-'); if (align === 'left') cell = ':' + cell.slice(1); else if (align === 'center') cell = ':' + cell.slice(1, -1) + ':'; else if (align === 'right') cell = cell.slice(0, -1) + ':'; rows[sepIndex][colIdx] = cell; var newLines = range.lines.slice(); for (var i = 0; i < rows.length; i++) { newLines[range.start + i] = '| ' + rows[i].join(' | ') + ' |'; } return formatTableText(newLines.join('\n'), cursorPos); } function insertColumn(text, cursorPos) { var range = findTableRange(text, cursorPos); if (!range) return null; var colIdx = getCursorColumn(text, cursorPos); if (colIdx === null) return null; var newLines = range.lines.slice(); var sepIndex = -1; for (var i = range.start; i <= range.end; i++) { var cells = parseTableRow(range.lines[i]); var isSep = sepIndex === -1 && isSeparatorRow(cells); if (isSep) sepIndex = i; cells.splice(colIdx, 0, isSep ? '---' : ''); newLines[i] = '| ' + cells.join(' | ') + ' |'; } return formatTableText(newLines.join('\n'), cursorPos); } function deleteColumn(text, cursorPos) { var range = findTableRange(text, cursorPos); if (!range) return null; var colIdx = getCursorColumn(text, cursorPos); if (colIdx === null) return null; var newLines = range.lines.slice(); for (var i = range.start; i <= range.end; i++) { var cells = parseTableRow(range.lines[i]); if (cells.length <= 1) return null; cells.splice(colIdx, 1); newLines[i] = '| ' + cells.join(' | ') + ' |'; } return formatTableText(newLines.join('\n'), cursorPos); } function insertRow(text, cursorPos) { var range = findTableRange(text, cursorPos); if (!range) return null; var colCount = 0; for (var i = range.start; i <= range.end; i++) { var cells = parseTableRow(range.lines[i]); if (cells.length > colCount) colCount = cells.length; } var emptyCells = []; for (var c = 0; c < colCount; c++) emptyCells.push(''); var newLines = range.lines.slice(); newLines.splice(range.cursorLine + 1, 0, '| ' + emptyCells.join(' | ') + ' |'); return formatTableText(newLines.join('\n'), cursorPos); } function insertRowBelow(text, cursorPos) { var range = findTableRange(text, cursorPos); if (!range) return null; var result = insertRow(text, cursorPos); if (!result) return null; var lines = result.text.split('\n'); var cursor = 0; for (var i = 0; i <= range.cursorLine; i++) cursor += lines[i].length + 1; cursor += 2; // skip leading '| ' return { text: result.text, cursor: cursor }; } function deleteRow(text, cursorPos) { var range = findTableRange(text, cursorPos); if (!range) return null; var sepIndex = -1; for (var i = range.start; i <= range.end; i++) { if (isSeparatorRow(parseTableRow(range.lines[i]))) { sepIndex = i; break; } } if (range.cursorLine === range.start || range.cursorLine === sepIndex) return null; var newLines = range.lines.slice(); newLines.splice(range.cursorLine, 1); var newCursor = cursorPos; if (range.cursorLine < newLines.length) { var charCount = 0; for (var i = 0; i < range.cursorLine; i++) charCount += newLines[i].length + 1; newCursor = charCount; } return formatTableText(newLines.join('\n'), Math.min(newCursor, newLines.join('\n').length)); } return { formatTableText: formatTableText, setColumnAlignment: setColumnAlignment, insertColumn: insertColumn, deleteColumn: deleteColumn, insertRow: insertRow, insertRowBelow: insertRowBelow, deleteRow: deleteRow, }; })();