2026-10-07 21:34:05 +00:00
|
|
|
import * as vscode from 'vscode';
|
|
|
|
|
|
|
|
|
|
export class TplDocumentFormatter implements vscode.DocumentFormattingEditProvider {
|
|
|
|
|
provideDocumentFormattingEdits(document: vscode.TextDocument, options: vscode.FormattingOptions, token: vscode.CancellationToken): vscode.ProviderResult<vscode.TextEdit[]> {
|
2026-10-08 20:02:08 +00:00
|
|
|
const text = document.getText();
|
|
|
|
|
const isCRLF = text.includes('\r\n');
|
|
|
|
|
const lines = text.split(/\r?\n/);
|
|
|
|
|
|
|
|
|
|
const formattedLines: string[] = [];
|
2026-10-07 21:34:05 +00:00
|
|
|
const edits: vscode.TextEdit[] = [];
|
|
|
|
|
|
|
|
|
|
let indentLevel = 0;
|
2026-10-08 20:02:08 +00:00
|
|
|
const indentString = ' ';
|
|
|
|
|
let inTripleDouble = false;
|
|
|
|
|
let inTripleSingle = false;
|
|
|
|
|
let consecutiveEmptyLines = 0;
|
|
|
|
|
|
|
|
|
|
const alignmentStack: number[] = [];
|
2026-10-07 21:34:05 +00:00
|
|
|
|
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
2026-10-08 20:02:08 +00:00
|
|
|
const rawLine = lines[i];
|
|
|
|
|
let line = rawLine.trim();
|
2026-10-07 21:34:05 +00:00
|
|
|
|
2026-10-08 20:02:08 +00:00
|
|
|
const tripleDoubleCount = (rawLine.match(/"""/g) || []).length;
|
|
|
|
|
const tripleSingleCount = (rawLine.match(/'''/g) || []).length;
|
|
|
|
|
|
|
|
|
|
let isInternalStringLine = false;
|
|
|
|
|
|
|
|
|
|
if (inTripleDouble) {
|
|
|
|
|
isInternalStringLine = true;
|
|
|
|
|
if (tripleDoubleCount % 2 !== 0) { inTripleDouble = false; isInternalStringLine = false; }
|
|
|
|
|
} else if (tripleDoubleCount % 2 !== 0) { inTripleDouble = true; }
|
|
|
|
|
|
|
|
|
|
if (inTripleSingle) {
|
|
|
|
|
isInternalStringLine = true;
|
|
|
|
|
if (tripleSingleCount % 2 !== 0) { inTripleSingle = false; isInternalStringLine = false; }
|
|
|
|
|
} else if (tripleSingleCount % 2 !== 0) { inTripleSingle = true; }
|
|
|
|
|
|
|
|
|
|
if (isInternalStringLine && (inTripleDouble || inTripleSingle)) {
|
|
|
|
|
formattedLines.push(rawLine);
|
|
|
|
|
consecutiveEmptyLines = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (line.length === 0) {
|
|
|
|
|
consecutiveEmptyLines++;
|
|
|
|
|
if (consecutiveEmptyLines <= 1) { formattedLines.push(""); }
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consecutiveEmptyLines = 0;
|
|
|
|
|
|
|
|
|
|
if (line.match(/^(end\s+(pattern|syncmapping|table|enumeration|configuration|definitions?|define|if|for|while|metadata|overview|constants|triggers|mapping|removal|body)|else|elif)\b/)) {
|
2026-10-07 21:34:05 +00:00
|
|
|
indentLevel = Math.max(0, indentLevel - 1);
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-08 20:02:08 +00:00
|
|
|
let newLineText = "";
|
|
|
|
|
if (alignmentStack.length > 0) {
|
|
|
|
|
let spaces = alignmentStack[alignmentStack.length - 1];
|
|
|
|
|
if (line.match(/^[)\]]/)) { spaces = Math.max(0, spaces - 1); }
|
|
|
|
|
newLineText = " ".repeat(spaces) + line;
|
|
|
|
|
} else {
|
|
|
|
|
newLineText = indentString.repeat(indentLevel) + line;
|
2026-10-07 21:34:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-10-08 20:02:08 +00:00
|
|
|
formattedLines.push(newLineText);
|
|
|
|
|
|
|
|
|
|
let cleanLineForParens = newLineText.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, match => " ".repeat(match.length));
|
|
|
|
|
const commentIdx = cleanLineForParens.indexOf('//');
|
|
|
|
|
if (commentIdx !== -1) {
|
|
|
|
|
cleanLineForParens = cleanLineForParens.substring(0, commentIdx) + " ".repeat(cleanLineForParens.length - commentIdx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (let charIdx = 0; charIdx < cleanLineForParens.length; charIdx++) {
|
|
|
|
|
const char = cleanLineForParens[charIdx];
|
|
|
|
|
if (char === '(' || char === '[') {
|
|
|
|
|
alignmentStack.push(charIdx + 1);
|
|
|
|
|
} else if (char === ')' || char === ']') {
|
|
|
|
|
if (alignmentStack.length > 0) { alignmentStack.pop(); }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (line.match(/^(pattern|syncmapping|table|enumeration|configuration|definitions?|define|metadata|overview|constants|triggers|mapping|removal|body|if|for|while|else|elif)\b/)) {
|
2026-10-07 21:34:05 +00:00
|
|
|
if (!line.startsWith('end ')) {
|
|
|
|
|
indentLevel++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-08 20:02:08 +00:00
|
|
|
const newText = formattedLines.join(isCRLF ? '\r\n' : '\n');
|
|
|
|
|
|
|
|
|
|
if (newText !== text) {
|
|
|
|
|
const fullRange = new vscode.Range(document.positionAt(0), document.positionAt(text.length));
|
|
|
|
|
edits.push(vscode.TextEdit.replace(fullRange, newText));
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-07 21:34:05 +00:00
|
|
|
return edits;
|
|
|
|
|
}
|
|
|
|
|
}
|