1.0.1 代码格式化移植新版

This commit is contained in:
睿 安
2025-09-17 11:28:54 +08:00
parent dc0cbe71dc
commit 6e550f1112
15 changed files with 818 additions and 344 deletions

34
copy-beautify-files.js Normal file
View File

@@ -0,0 +1,34 @@
const fs = require('fs-extra');
const path = require('path');
// 复制 js-beautify 相关文件到 dist 目录
async function copyBeautifyFiles() {
const srcDir = path.join(__dirname);
const destDir = path.join(__dirname, 'dist');
// 确保目标目录存在
await fs.ensureDir(destDir);
// 复制 js-beautify.js 和包装器
const filesToCopy = [
'js-beautify.js',
'js-beautify-wrapper.js'
];
for (const file of filesToCopy) {
const srcPath = path.join(srcDir, file);
const destPath = path.join(destDir, file);
if (await fs.pathExists(srcPath)) {
await fs.copy(srcPath, destPath);
console.log(`已复制 ${file} 到 dist 目录`);
}
}
}
// 如果直接运行此脚本,则执行复制操作
if (require.main === module) {
copyBeautifyFiles().catch(console.error);
}
module.exports = { copyBeautifyFiles };

View File

@@ -35,82 +35,39 @@ var __importStar = (this && this.__importStar) || (function () {
Object.defineProperty(exports, "__esModule", { value: true });
exports.DocumentFormattingProvider = void 0;
const vscode = __importStar(require("vscode"));
// 文档格式化提供者类
const beautifyHelper_1 = require("../utils/beautifyHelper");
/**
* 文档格式化提供者类 - 使用 js-beautify.js
*/
class DocumentFormattingProvider {
// 提供整个文档的代码格式化功能
/**
* 提供整个文档的代码格式化功能
*/
async provideDocumentFormattingEdits(document, options, token) {
const edits = [];
const lines = [];
// 逐行处理文档内容
for (let i = 0; i < document.lineCount; i++) {
const line = document.lineAt(i);
lines.push(line.text);
try {
// 获取文档全文
const fullText = document.getText();
// 检查是否是 Squirrel 代码
if (!(0, beautifyHelper_1.isSquirrelCode)(fullText)) {
return edits; // 如果不是 Squirrel 代码,不应用格式化
}
// 使用 js-beautify 格式化代码
const formattedText = (0, beautifyHelper_1.beautifyCode)(fullText, options);
// 如果格式化后的代码与原代码相同,不需要修改
if (formattedText === fullText) {
return edits;
}
// 创建编辑操作,替换整个文档
const fullRange = new vscode.Range(document.positionAt(0), document.positionAt(fullText.length));
edits.push(vscode.TextEdit.replace(fullRange, formattedText));
}
catch (error) {
console.error('文档格式化失败:', error);
// 如果格式化失败,返回空编辑数组,保持原代码不变
}
// 格式化文档
const formattedLines = this.formatDocument(lines, options);
// 创建编辑操作
const fullRange = new vscode.Range(document.positionAt(0), document.positionAt(document.getText().length));
edits.push(vscode.TextEdit.replace(fullRange, formattedLines.join('\n')));
return edits;
}
// 格式化文档
formatDocument(lines, options) {
const formattedLines = [];
let indentLevel = 0;
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
const trimmedLine = line.trim();
if (trimmedLine.length === 0) {
// 空行保持原样或删除
formattedLines.push('');
continue;
}
// 检查是否需要减少缩进(遇到右大括号等)
if (trimmedLine.startsWith('}') || trimmedLine.startsWith(')') || trimmedLine.startsWith(']')) {
indentLevel = Math.max(0, indentLevel - 1);
}
// 添加适当的缩进
const indent = this.createIndent(indentLevel, options);
const formattedLine = indent + trimmedLine;
formattedLines.push(formattedLine);
// 检查是否需要增加缩进(遇到左大括号等)
if (trimmedLine.endsWith('{') || trimmedLine.endsWith('(') || trimmedLine.endsWith('[')) {
indentLevel++;
}
// 特殊处理else、catch等关键字它们应该与前面的右大括号在同一行
if (trimmedLine.startsWith('else') || trimmedLine.startsWith('catch') || trimmedLine.startsWith('elif')) {
if (formattedLines.length > 1) {
const prevLine = formattedLines[formattedLines.length - 2];
if (prevLine.trim().endsWith('}')) {
// 将else等关键字与前面的右大括号放在同一行
formattedLines[formattedLines.length - 2] = prevLine.trim() + ' ' + trimmedLine;
formattedLines.pop(); // 移除当前行
indentLevel--; // 修正缩进级别
}
}
}
}
// 规范化空格(在操作符周围添加适当空格)
return formattedLines.map(line => this.normalizeSpaces(line));
}
// 在操作符周围添加适当空格
normalizeSpaces(line) {
// 在常见的操作符周围添加空格
return line
.replace(/([^\s])(==|!=|<=|>=|<|>|=|\+|-|\*|\/|%)([^\s])/g, '$1 $2 $3')
.replace(/([^\s])(,)([^\s])/g, '$1$2 $3')
.replace(/\s+/g, ' ') // 将多个空格替换为单个空格
.trim();
}
// 创建指定级别的缩进
createIndent(level, options) {
if (options.insertSpaces) {
return ' '.repeat(level * options.tabSize);
}
else {
return '\t'.repeat(level);
}
}
}
exports.DocumentFormattingProvider = DocumentFormattingProvider;
//# sourceMappingURL=documentFormattingProvider.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"documentFormattingProvider.js","sourceRoot":"","sources":["../../src/providers/documentFormattingProvider.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"documentFormattingProvider.js","sourceRoot":"","sources":["../../src/providers/documentFormattingProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AACjC,4DAAuE;AAEvE;;GAEG;AACH,MAAa,0BAA0B;IACnC;;OAEG;IACH,KAAK,CAAC,8BAA8B,CAChC,QAA6B,EAC7B,OAAiC,EACjC,KAA+B;QAE/B,MAAM,KAAK,GAAsB,EAAE,CAAC;QAEpC,IAAI,CAAC;YACD,SAAS;YACT,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;YAEpC,oBAAoB;YACpB,IAAI,CAAC,IAAA,+BAAc,EAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,OAAO,KAAK,CAAC,CAAC,0BAA0B;YAC5C,CAAC;YAED,uBAAuB;YACvB,MAAM,aAAa,GAAG,IAAA,6BAAY,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAEtD,wBAAwB;YACxB,IAAI,aAAa,KAAK,QAAQ,EAAE,CAAC;gBAC7B,OAAO,KAAK,CAAC;YACjB,CAAC;YAED,gBAAgB;YAChB,MAAM,SAAS,GAAG,IAAI,MAAM,CAAC,KAAK,CAC9B,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EACtB,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CACvC,CAAC;YAEF,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;QAElE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YACjC,0BAA0B;QAC9B,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ;AA3CD,gEA2CC"}

View File

@@ -35,115 +35,130 @@ var __importStar = (this && this.__importStar) || (function () {
Object.defineProperty(exports, "__esModule", { value: true });
exports.OnTypeFormattingProvider = void 0;
const vscode = __importStar(require("vscode"));
// 输入时格式化提供者类
const beautifyHelper_1 = require("../utils/beautifyHelper");
/**
* 输入时格式化提供者类 - 使用 js-beautify.js
*/
class OnTypeFormattingProvider {
// 在用户输入特定字符时自动格式化代码
/**
* 在用户输入特定字符时自动格式化代码
*/
async provideOnTypeFormattingEdits(document, position, ch, options, token) {
const edits = [];
// 根据输入的字符执行不同的格式化操作
switch (ch) {
case ')':
// 输入右括号时格式化当前行
edits.push(...this.formatCurrentLine(document, position, options));
break;
case ';':
// 输入分号时格式化当前行
edits.push(...this.formatCurrentLine(document, position, options));
break;
case '}':
// 输入右大括号时格式化整个代码块
edits.push(...this.formatCodeBlock(document, position, options));
break;
default:
break;
try {
// 检查是否是 Squirrel 代码
const textBefore = document.getText(new vscode.Range(new vscode.Position(0, 0), position));
if (!(0, beautifyHelper_1.isSquirrelCode)(textBefore)) {
return edits;
}
// 根据输入的字符执行不同的格式化操作
switch (ch) {
case ')':
// 输入右括号时格式化当前行
edits.push(...this.formatCurrentLine(document, position, options));
break;
case ';':
// 输入分号时格式化当前行
edits.push(...this.formatCurrentLine(document, position, options));
break;
case '}':
// 输入右大括号时格式化整个代码块
edits.push(...this.formatCodeBlock(document, position, options));
break;
default:
break;
}
}
catch (error) {
console.error('输入时格式化失败:', error);
}
return edits;
}
// 格式化当前行
/**
* 使用 js-beautify 格式化当前行
*/
formatCurrentLine(document, position, options) {
const line = document.lineAt(position.line);
const trimmedLine = line.text.trim();
if (trimmedLine.length === 0) {
return [];
const edits = [];
try {
// 获取当前行
const line = document.lineAt(position.line);
const lineText = line.text;
// 获取当前行的上下文(向前几行,向后几行)
const startLine = Math.max(0, position.line - 2);
const endLine = Math.min(document.lineCount - 1, position.line + 2);
const contextText = document.getText(new vscode.Range(new vscode.Position(startLine, 0), new vscode.Position(endLine, document.lineAt(endLine).text.length)));
// 使用 js-beautify 格式化代码块
const formattedContext = (0, beautifyHelper_1.beautifyCode)(contextText, options);
// 比较原始文本和格式化后的文本
if (formattedContext === contextText) {
return edits; // 没有变化,不需要编辑
}
// 应用格式化结果
const originalLines = contextText.split('\n');
const formattedLines = formattedContext.split('\n');
for (let i = 0; i < originalLines.length && i < formattedLines.length; i++) {
const original = originalLines[i];
const formatted = formattedLines[i];
if (original !== formatted) {
const lineNumber = startLine + i;
const range = new vscode.Range(new vscode.Position(lineNumber, 0), new vscode.Position(lineNumber, document.lineAt(lineNumber).text.length));
edits.push(vscode.TextEdit.replace(range, formatted));
}
}
}
// 简单的格式化:确保行尾没有多余空格
if (line.text !== trimmedLine && !line.text.endsWith(' ')) {
const range = new vscode.Range(new vscode.Position(position.line, 0), new vscode.Position(position.line, line.text.length));
return [vscode.TextEdit.replace(range, trimmedLine)];
catch (error) {
console.error('格式化当前行失败:', error);
}
return [];
return edits;
}
// 格式化代码块
/**
* 使用 js-beautify 格式化代码块
*/
formatCodeBlock(document, position, options) {
const edits = [];
const line = document.lineAt(position.line);
// 查找匹配的左大括号
let braceCount = 1;
let blockStartLine = -1;
for (let i = position.line - 1; i >= 0; i--) {
const currentLine = document.lineAt(i);
const lineText = currentLine.text;
for (let j = lineText.length - 1; j >= 0; j--) {
if (lineText[j] === '}') {
braceCount++;
}
else if (lineText[j] === '{') {
braceCount--;
if (braceCount === 0) {
blockStartLine = i;
break;
try {
// 查找匹配的左大括号
let braceCount = 1;
let blockStartLine = -1;
for (let i = position.line - 1; i >= 0; i--) {
const currentLine = document.lineAt(i);
const lineText = currentLine.text;
for (let j = lineText.length - 1; j >= 0; j--) {
if (lineText[j] === '}') {
braceCount++;
}
else if (lineText[j] === '{') {
braceCount--;
if (braceCount === 0) {
blockStartLine = i;
break;
}
}
}
if (blockStartLine !== -1) {
break;
}
}
if (blockStartLine !== -1) {
break;
// 获取代码块的范围
const endLine = position.line;
const blockText = document.getText(new vscode.Range(new vscode.Position(blockStartLine, 0), new vscode.Position(endLine + 1, 0) // 包含右大括号行
));
// 使用 js-beautify 格式化代码块
const formattedBlock = (0, beautifyHelper_1.beautifyCode)(blockText, options);
if (formattedBlock === blockText) {
return edits; // 没有变化
}
// 应用格式化结果
const range = new vscode.Range(new vscode.Position(blockStartLine, 0), new vscode.Position(endLine + 1, 0));
edits.push(vscode.TextEdit.replace(range, formattedBlock));
}
}
if (blockStartLine !== -1) {
// 调整代码块的缩进
const startLine = document.lineAt(blockStartLine);
const startIndent = this.getIndentLevel(startLine.text);
for (let i = blockStartLine + 1; i < position.line; i++) {
const currentLine = document.lineAt(i);
const currentIndent = this.getIndentLevel(currentLine.text);
if (currentIndent < startIndent + 1) {
const newIndent = this.createIndent(startIndent + 1, options);
const range = new vscode.Range(new vscode.Position(i, 0), new vscode.Position(i, currentIndent));
edits.push(vscode.TextEdit.replace(range, newIndent));
}
}
// 调整右大括号的缩进
const endIndent = this.createIndent(startIndent, options);
const endRange = new vscode.Range(new vscode.Position(position.line, 0), new vscode.Position(position.line, this.getIndentLevel(line.text)));
edits.push(vscode.TextEdit.replace(endRange, endIndent));
catch (error) {
console.error('格式化代码块失败:', error);
}
return edits;
}
// 获取行的缩进级别
getIndentLevel(line) {
let indent = 0;
for (let i = 0; i < line.length; i++) {
if (line[i] === ' ') {
indent++;
}
else if (line[i] === '\t') {
indent += 4; // 假设一个tab等于4个空格
}
else {
break;
}
}
return indent;
}
// 创建指定级别的缩进
createIndent(level, options) {
if (options.insertSpaces) {
return ' '.repeat(level);
}
else {
return '\t'.repeat(Math.floor(level / 4)); // 假设一个tab等于4个空格
}
}
}
exports.OnTypeFormattingProvider = OnTypeFormattingProvider;
//# sourceMappingURL=onTypeFormattingProvider.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"onTypeFormattingProvider.js","sourceRoot":"","sources":["../../src/providers/onTypeFormattingProvider.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"onTypeFormattingProvider.js","sourceRoot":"","sources":["../../src/providers/onTypeFormattingProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AACjC,4DAAuE;AAEvE;;GAEG;AACH,MAAa,wBAAwB;IACjC;;OAEG;IACH,KAAK,CAAC,4BAA4B,CAC9B,QAA6B,EAC7B,QAAyB,EACzB,EAAU,EACV,OAAiC,EACjC,KAA+B;QAE/B,MAAM,KAAK,GAAsB,EAAE,CAAC;QAEpC,IAAI,CAAC;YACD,oBAAoB;YACpB,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC3F,IAAI,CAAC,IAAA,+BAAc,EAAC,UAAU,CAAC,EAAE,CAAC;gBAC9B,OAAO,KAAK,CAAC;YACjB,CAAC;YAED,oBAAoB;YACpB,QAAQ,EAAE,EAAE,CAAC;gBACT,KAAK,GAAG;oBACJ,eAAe;oBACf,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;oBACnE,MAAM;gBACV,KAAK,GAAG;oBACJ,cAAc;oBACd,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;oBACnE,MAAM;gBACV,KAAK,GAAG;oBACJ,kBAAkB;oBAClB,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;oBACjE,MAAM;gBACV;oBACI,MAAM;YACd,CAAC;QAEL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,iBAAiB,CACrB,QAA6B,EAC7B,QAAyB,EACzB,OAAiC;QAEjC,MAAM,KAAK,GAAsB,EAAE,CAAC;QAEpC,IAAI,CAAC;YACD,QAAQ;YACR,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;YAE3B,uBAAuB;YACvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,GAAG,CAAC,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;YAEpE,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAChC,IAAI,MAAM,CAAC,KAAK,CACZ,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,EACjC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CACrE,CACJ,CAAC;YAEF,wBAAwB;YACxB,MAAM,gBAAgB,GAAG,IAAA,6BAAY,EAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAE5D,iBAAiB;YACjB,IAAI,gBAAgB,KAAK,WAAW,EAAE,CAAC;gBACnC,OAAO,KAAK,CAAC,CAAC,aAAa;YAC/B,CAAC;YAED,UAAU;YACV,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9C,MAAM,cAAc,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAEpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,IAAI,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzE,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;gBAClC,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;gBAEpC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBACzB,MAAM,UAAU,GAAG,SAAS,GAAG,CAAC,CAAC;oBACjC,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAC1B,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,EAClC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAC3E,CAAC;oBACF,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;gBAC1D,CAAC;YACL,CAAC;QAEL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,eAAe,CACnB,QAA6B,EAC7B,QAAyB,EACzB,OAAiC;QAEjC,MAAM,KAAK,GAAsB,EAAE,CAAC;QAEpC,IAAI,CAAC;YACD,YAAY;YACZ,IAAI,UAAU,GAAG,CAAC,CAAC;YACnB,IAAI,cAAc,GAAG,CAAC,CAAC,CAAC;YAExB,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1C,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACvC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC;gBAElC,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC5C,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;wBACtB,UAAU,EAAE,CAAC;oBACjB,CAAC;yBAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;wBAC7B,UAAU,EAAE,CAAC;wBACb,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;4BACnB,cAAc,GAAG,CAAC,CAAC;4BACnB,MAAM;wBACV,CAAC;oBACL,CAAC;gBACL,CAAC;gBAED,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;oBACxB,MAAM;gBACV,CAAC;YACL,CAAC;YAED,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;gBACxB,WAAW;gBACX,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC;gBAC9B,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAC9B,IAAI,MAAM,CAAC,KAAK,CACZ,IAAI,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,EACtC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU;iBACjD,CACJ,CAAC;gBAEF,wBAAwB;gBACxB,MAAM,cAAc,GAAG,IAAA,6BAAY,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAExD,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;oBAC/B,OAAO,KAAK,CAAC,CAAC,OAAO;gBACzB,CAAC;gBAED,UAAU;gBACV,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAC1B,IAAI,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,EACtC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC,CACtC,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;YAC/D,CAAC;QAEL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ;AA3KD,4DA2KC"}

201
dist/utils/beautifyHelper.js vendored Normal file
View File

@@ -0,0 +1,201 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSquirrelBeautifyOptions = getSquirrelBeautifyOptions;
exports.beautifyCode = beautifyCode;
exports.isSquirrelCode = isSquirrelCode;
// 由于 js-beautify.js 文件体积较大且复杂,我们将创建专门的存根函数
// 将使用原生的 js-beautify 功能
let _jsBeauifyInstance = null;
/**
* 动态创建 js_beautify 函数
*/
function createJsBeautify() {
if (_jsBeauifyInstance) {
return _jsBeauifyInstance;
}
try {
// 加载原始的 js-beautify.js 文件
const beautifyModule = loadJsBeautify();
_jsBeauifyInstance = beautifyModule;
return _jsBeauifyInstance;
}
catch (error) {
console.error('加载 js-beautify 失败,使用后备实现:', error);
// 调用后备实现
return createBasicJsBeautify();
}
}
/**
* 加载 js-beautify 模块
*/
function loadJsBeautify() {
// 根据环境动态加载
try {
// 尝试 require 原始的 js-beautify.js 文件
// 注意TypeScript 会从 ./dist 目录运行,所以需要从正确的路径加载
const beautifyPath = __dirname + '/../../js-beautify.js';
const Module = require('module');
const vm = require('vm');
const fs = require('fs');
// 读取文件内容
const code = fs.readFileSync(beautifyPath, 'utf8');
// 设置全局环境
const sandbox = {
window: {},
global: {},
console: console,
String: String,
Array: Array,
Object: Object,
Math: Math
};
// 在沙箱中执行代码
const script = new vm.Script(code);
const context = vm.createContext(sandbox);
script.runInContext(context);
// 获取 js_beautify 函数
return context.window.js_beautify || context.js_beautify || sandbox.window.js_beautify;
}
catch (loadError) {
console.error('无法加载原始 js-beautify, 错误:', loadError);
throw loadError;
}
}
/**
* 基础的 js-beautify 实现(后备方案)
*/
function createBasicJsBeautify() {
return function (code, options = {}) {
// 默认选项
const defaultOptions = {
indent_size: 4,
indent_char: ' ',
preserve_newlines: true,
brace_style: 'collapse',
space_before_conditional: true,
space_after_anon_function: false,
wrap_line_length: 120,
end_with_newline: false
};
// 合并选项
const opts = { ...defaultOptions, ...options };
// 简化的代码美化实现
let formatted = code;
// 清理缩进
formatted = formatted.replace(/[\r\n]+/g, '\n');
const lines = formatted.split('\n');
const result = [];
let indentLevel = 0;
const indentStr = opts.indent_char.repeat(opts.indent_size);
for (const line of lines) {
const trimmed = line.trim();
// 跳过空行
if (trimmed.length === 0) {
result.push('');
continue;
}
// 处理大括号
if (trimmed.startsWith('}') || trimmed.startsWith(')') || trimmed.startsWith(']')) {
indentLevel = Math.max(0, indentLevel - 1);
}
// 添加缩进
const indentedLine = indentStr.repeat(indentLevel) + trimmed;
result.push(indentedLine);
// 增加缩进
if (trimmed.endsWith('{') || trimmed.endsWith('(') || trimmed.endsWith('[')) {
indentLevel++;
}
// 特殊处理 else、catch 等关键字
if (trimmed.startsWith('else') || trimmed.startsWith('catch') || trimmed.startsWith('elif')) {
// 检查前面一行是否以 } 结尾
if (result.length > 1) {
const prevLine = result[result.length - 2];
const prevTrimmed = prevLine.trim();
if (prevTrimmed.endsWith('}')) {
// 移动到前一行的必要部分
result[result.length - 2] = indentStr.repeat(indentLevel - 1) +
prevTrimmed + ' ' + trimmed;
result.pop(); // 移除当前行
indentLevel--; // 修正缩进级别
}
}
}
}
let finalResult = result.join('\n');
// 处理空格 - 在操作符周围添加空格
finalResult = finalResult
.replace(/([a-zA-Z0-9_$])([=!<>+\-*/%])([a-zA-Z0-9_$])/g, '$1 $2 $3')
.replace(/([a-zA-Z0-9_$])(,)([a-zA-Z0-9_$])/g, '$1$2 $3')
.replace(/\s+/g, ' ') // 将多个空格替换为单个空格
.trim();
return finalResult;
};
}
// 初始化 js_beautify
const jsBeautify = {
js_beautify: createJsBeautify()
};
/**
* Squirrel 语言的 js-beautify 选项配置
*/
function getSquirrelBeautifyOptions(options) {
return {
indent_size: options.tabSize,
indent_char: options.insertSpaces ? ' ' : '\t',
preserve_newlines: true,
max_preserve_newlines: 2,
jslint_happy: false,
brace_style: "collapse",
space_before_conditional: true,
space_after_anon_function: false,
unescape_strings: false,
wrap_line_length: 120,
end_with_newline: false
};
}
/**
* 使用 js-beautify 格式化代码
*/
function beautifyCode(code, options) {
if (!jsBeautify || !jsBeautify.js_beautify) {
console.warn('js-beautify 不可用,返回原始代码');
return code;
}
try {
const beautifyOptions = getSquirrelBeautifyOptions(options);
// 检查代码长度,处理大块代码
const maxChunkSize = 50000; // 50KB 每块
if (code.length > maxChunkSize) {
// 分割代码并分块处理
const chunks = code.split('\n');
const resultChunks = [];
for (const chunk of chunks) {
const formattedChunk = jsBeautify.js_beautify(chunk, beautifyOptions);
resultChunks.push(formattedChunk);
}
return resultChunks.join('\n');
}
// 直接格式化小代码块
return jsBeautify.js_beautify(code, beautifyOptions);
}
catch (error) {
console.error('js-beautify 格式化失败:', error);
// 如果格式化失败,返回原始代码
return code;
}
}
/**
* 检测是否为 Squirrel 代码(用于确定是否应用格式化)
*/
function isSquirrelCode(code) {
// 简单的启发式检测 - Squirrel 特有关键字
const squirrelKeywords = [
'function', 'local', 'if', 'else', 'while', 'for', 'foreach',
'class', 'constructor', 'extends', 'instanceof', 'in',
'try', 'catch', 'throw', 'clone', 'delegate', 'resume', 'yield',
'typeof', 'member', 'rawcall', 'call', 'setdebughook'
];
// 提高检测准确性 - 需要至少匹配到1个关键字
return squirrelKeywords.some(keyword => new RegExp(`\\b${keyword}\\b`).test(code));
}
//# sourceMappingURL=beautifyHelper.js.map

1
dist/utils/beautifyHelper.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,44 @@
const fs = require('fs');
const path = require('path');
// 因为 js-beautify.js 直接在全局作用域定义 js_beautify
// 我们可以直接使用 require 来引入并获取函数
// 特别注意js-beautify.js 假设需要 window 或 global 对象
// Node.js 环境下,我们需要将 js_beautify 挂载到全局
let js_beautify;
// 读取并执行 js-beautify.js
const beautifyPath = path.join(__dirname, 'js-beautify.js');
const beautifyCode = fs.readFileSync(beautifyPath, 'utf-8');
// 创建一个安全的沙箱环境
global.window = global;
global.module = undefined;
global.exports = undefined;
// 执行代码
try {
eval(beautifyCode);
js_beautify = global.js_beautify;
} catch (error) {
console.error('加载 js-beautify.js 失败:', error);
throw error;
}
// 清理全局变量
delete global.window;
// 如果 js_beautify 没有挂载到 global尝试从 globalThis 获取
if (!js_beautify && globalThis.js_beautify) {
js_beautify = globalThis.js_beautify;
}
if (!js_beautify) {
throw new Error('无法从 js-beautify.js 中找到 js_beautify 函数');
}
module.exports = {
js_beautify: js_beautify
};

15
js-beautify-wrapper.js Normal file
View File

@@ -0,0 +1,15 @@
// js-beautify.js 的 CommonJS 包装器
const fs = require('fs');
const path = require('path');
// 读取原始 js-beautify.js 文件内容
const beautifyPath = path.join(__dirname, 'js-beautify.js');
const beautifyContent = fs.readFileSync(beautifyPath, 'utf-8');
// 执行文件内容,确保 js_beautify 函数可用
eval(beautifyContent);
// 模块导出 js_beautify 函数
module.exports = {
js_beautify: global.js_beautify || js_beautify
};

2
node_modules/.package-lock.json generated vendored
View File

@@ -1,6 +1,6 @@
{
"name": "squirrel-nut-explorer",
"version": "1.0.1",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "squirrel-nut-explorer",
"version": "1.0.1",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "squirrel-nut-explorer",
"version": "1.0.1",
"version": "1.0.0",
"devDependencies": {
"@types/node": "^20.19.11",
"@types/vscode": "^1.99.0",

Binary file not shown.

View File

@@ -1,100 +1,50 @@
import * as vscode from 'vscode';
import { beautifyCode, isSquirrelCode } from '../utils/beautifyHelper';
// 文档格式化提供者类
/**
* 文档格式化提供者类 - 使用 js-beautify.js
*/
export class DocumentFormattingProvider implements vscode.DocumentFormattingEditProvider {
// 提供整个文档的代码格式化功能
/**
* 提供整个文档的代码格式化功能
*/
async provideDocumentFormattingEdits(
document: vscode.TextDocument,
options: vscode.FormattingOptions,
token: vscode.CancellationToken
): Promise<vscode.TextEdit[]> {
const edits: vscode.TextEdit[] = [];
const lines: string[] = [];
// 逐行处理文档内容
for (let i = 0; i < document.lineCount; i++) {
const line = document.lineAt(i);
lines.push(line.text);
try {
// 获取文档全文
const fullText = document.getText();
// 检查是否是 Squirrel 代码
if (!isSquirrelCode(fullText)) {
return edits; // 如果不是 Squirrel 代码,不应用格式化
}
// 使用 js-beautify 格式化代码
const formattedText = beautifyCode(fullText, options);
// 如果格式化后的代码与原代码相同,不需要修改
if (formattedText === fullText) {
return edits;
}
// 创建编辑操作,替换整个文档
const fullRange = new vscode.Range(
document.positionAt(0),
document.positionAt(fullText.length)
);
edits.push(vscode.TextEdit.replace(fullRange, formattedText));
} catch (error) {
console.error('文档格式化失败:', error);
// 如果格式化失败,返回空编辑数组,保持原代码不变
}
// 格式化文档
const formattedLines = this.formatDocument(lines, options);
// 创建编辑操作
const fullRange = new vscode.Range(
document.positionAt(0),
document.positionAt(document.getText().length)
);
edits.push(vscode.TextEdit.replace(fullRange, formattedLines.join('\n')));
return edits;
}
// 格式化文档
private formatDocument(lines: string[], options: vscode.FormattingOptions): string[] {
const formattedLines: string[] = [];
let indentLevel = 0;
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
const trimmedLine = line.trim();
if (trimmedLine.length === 0) {
// 空行保持原样或删除
formattedLines.push('');
continue;
}
// 检查是否需要减少缩进(遇到右大括号等)
if (trimmedLine.startsWith('}') || trimmedLine.startsWith(')') || trimmedLine.startsWith(']')) {
indentLevel = Math.max(0, indentLevel - 1);
}
// 添加适当的缩进
const indent = this.createIndent(indentLevel, options);
const formattedLine = indent + trimmedLine;
formattedLines.push(formattedLine);
// 检查是否需要增加缩进(遇到左大括号等)
if (trimmedLine.endsWith('{') || trimmedLine.endsWith('(') || trimmedLine.endsWith('[')) {
indentLevel++;
}
// 特殊处理else、catch等关键字它们应该与前面的右大括号在同一行
if (trimmedLine.startsWith('else') || trimmedLine.startsWith('catch') || trimmedLine.startsWith('elif')) {
if (formattedLines.length > 1) {
const prevLine = formattedLines[formattedLines.length - 2];
if (prevLine.trim().endsWith('}')) {
// 将else等关键字与前面的右大括号放在同一行
formattedLines[formattedLines.length - 2] = prevLine.trim() + ' ' + trimmedLine;
formattedLines.pop(); // 移除当前行
indentLevel--; // 修正缩进级别
}
}
}
}
// 规范化空格(在操作符周围添加适当空格)
return formattedLines.map(line => this.normalizeSpaces(line));
}
// 在操作符周围添加适当空格
private normalizeSpaces(line: string): string {
// 在常见的操作符周围添加空格
return line
.replace(/([^\s])(==|!=|<=|>=|<|>|=|\+|-|\*|\/|%)([^\s])/g, '$1 $2 $3')
.replace(/([^\s])(,)([^\s])/g, '$1$2 $3')
.replace(/\s+/g, ' ') // 将多个空格替换为单个空格
.trim();
}
// 创建指定级别的缩进
private createIndent(level: number, options: vscode.FormattingOptions): string {
if (options.insertSpaces) {
return ' '.repeat(level * options.tabSize);
} else {
return '\t'.repeat(level);
}
}
}

View File

@@ -1,8 +1,13 @@
import * as vscode from 'vscode';
import { beautifyCode, isSquirrelCode } from '../utils/beautifyHelper';
// 输入时格式化提供者类
/**
* 输入时格式化提供者类 - 使用 js-beautify.js
*/
export class OnTypeFormattingProvider implements vscode.OnTypeFormattingEditProvider {
// 在用户输入特定字符时自动格式化代码
/**
* 在用户输入特定字符时自动格式化代码
*/
async provideOnTypeFormattingEdits(
document: vscode.TextDocument,
position: vscode.Position,
@@ -12,138 +17,162 @@ export class OnTypeFormattingProvider implements vscode.OnTypeFormattingEditProv
): Promise<vscode.TextEdit[]> {
const edits: vscode.TextEdit[] = [];
// 根据输入的字符执行不同的格式化操作
switch (ch) {
case ')':
// 输入右括号时格式化当前行
edits.push(...this.formatCurrentLine(document, position, options));
break;
case ';':
// 输入分号时格式化当前行
edits.push(...this.formatCurrentLine(document, position, options));
break;
case '}':
// 输入右大括号时格式化整个代码块
edits.push(...this.formatCodeBlock(document, position, options));
break;
default:
break;
try {
// 检查是否是 Squirrel 代码
const textBefore = document.getText(new vscode.Range(new vscode.Position(0, 0), position));
if (!isSquirrelCode(textBefore)) {
return edits;
}
// 根据输入的字符执行不同的格式化操作
switch (ch) {
case ')':
// 输入右括号时格式化当前行
edits.push(...this.formatCurrentLine(document, position, options));
break;
case ';':
// 输入分号时格式化当前行
edits.push(...this.formatCurrentLine(document, position, options));
break;
case '}':
// 输入右大括号时格式化整个代码块
edits.push(...this.formatCodeBlock(document, position, options));
break;
default:
break;
}
} catch (error) {
console.error('输入时格式化失败:', error);
}
return edits;
}
// 格式化当前行
/**
* 使用 js-beautify 格式化当前行
*/
private formatCurrentLine(
document: vscode.TextDocument,
position: vscode.Position,
options: vscode.FormattingOptions
): vscode.TextEdit[] {
const line = document.lineAt(position.line);
const trimmedLine = line.text.trim();
const edits: vscode.TextEdit[] = [];
if (trimmedLine.length === 0) {
return [];
}
try {
// 获取当前行
const line = document.lineAt(position.line);
const lineText = line.text;
// 简单的格式化:确保行尾没有多余空格
if (line.text !== trimmedLine && !line.text.endsWith(' ')) {
const range = new vscode.Range(
new vscode.Position(position.line, 0),
new vscode.Position(position.line, line.text.length)
// 获取当前行的上下文(向前几行,向后几行)
const startLine = Math.max(0, position.line - 2);
const endLine = Math.min(document.lineCount - 1, position.line + 2);
const contextText = document.getText(
new vscode.Range(
new vscode.Position(startLine, 0),
new vscode.Position(endLine, document.lineAt(endLine).text.length)
)
);
return [vscode.TextEdit.replace(range, trimmedLine)];
// 使用 js-beautify 格式化代码块
const formattedContext = beautifyCode(contextText, options);
// 比较原始文本和格式化后的文本
if (formattedContext === contextText) {
return edits; // 没有变化,不需要编辑
}
// 应用格式化结果
const originalLines = contextText.split('\n');
const formattedLines = formattedContext.split('\n');
for (let i = 0; i < originalLines.length && i < formattedLines.length; i++) {
const original = originalLines[i];
const formatted = formattedLines[i];
if (original !== formatted) {
const lineNumber = startLine + i;
const range = new vscode.Range(
new vscode.Position(lineNumber, 0),
new vscode.Position(lineNumber, document.lineAt(lineNumber).text.length)
);
edits.push(vscode.TextEdit.replace(range, formatted));
}
}
} catch (error) {
console.error('格式化当前行失败:', error);
}
return [];
return edits;
}
// 格式化代码块
/**
* 使用 js-beautify 格式化代码块
*/
private formatCodeBlock(
document: vscode.TextDocument,
position: vscode.Position,
options: vscode.FormattingOptions
): vscode.TextEdit[] {
const edits: vscode.TextEdit[] = [];
const line = document.lineAt(position.line);
// 查找匹配的左大括号
let braceCount = 1;
let blockStartLine = -1;
try {
// 查找匹配的左大括号
let braceCount = 1;
let blockStartLine = -1;
for (let i = position.line - 1; i >= 0; i--) {
const currentLine = document.lineAt(i);
const lineText = currentLine.text;
for (let i = position.line - 1; i >= 0; i--) {
const currentLine = document.lineAt(i);
const lineText = currentLine.text;
for (let j = lineText.length - 1; j >= 0; j--) {
if (lineText[j] === '}') {
braceCount++;
} else if (lineText[j] === '{') {
braceCount--;
if (braceCount === 0) {
blockStartLine = i;
break;
for (let j = lineText.length - 1; j >= 0; j--) {
if (lineText[j] === '}') {
braceCount++;
} else if (lineText[j] === '{') {
braceCount--;
if (braceCount === 0) {
blockStartLine = i;
break;
}
}
}
if (blockStartLine !== -1) {
break;
}
}
if (blockStartLine !== -1) {
break;
}
}
// 获取代码块的范围
const endLine = position.line;
const blockText = document.getText(
new vscode.Range(
new vscode.Position(blockStartLine, 0),
new vscode.Position(endLine + 1, 0) // 包含右大括号行
)
);
if (blockStartLine !== -1) {
// 调整代码块的缩进
const startLine = document.lineAt(blockStartLine);
const startIndent = this.getIndentLevel(startLine.text);
// 使用 js-beautify 格式化代码块
const formattedBlock = beautifyCode(blockText, options);
for (let i = blockStartLine + 1; i < position.line; i++) {
const currentLine = document.lineAt(i);
const currentIndent = this.getIndentLevel(currentLine.text);
if (currentIndent < startIndent + 1) {
const newIndent = this.createIndent(startIndent + 1, options);
const range = new vscode.Range(
new vscode.Position(i, 0),
new vscode.Position(i, currentIndent)
);
edits.push(vscode.TextEdit.replace(range, newIndent));
if (formattedBlock === blockText) {
return edits; // 没有变化
}
// 应用格式化结果
const range = new vscode.Range(
new vscode.Position(blockStartLine, 0),
new vscode.Position(endLine + 1, 0)
);
edits.push(vscode.TextEdit.replace(range, formattedBlock));
}
// 调整右大括号的缩进
const endIndent = this.createIndent(startIndent, options);
const endRange = new vscode.Range(
new vscode.Position(position.line, 0),
new vscode.Position(position.line, this.getIndentLevel(line.text))
);
edits.push(vscode.TextEdit.replace(endRange, endIndent));
} catch (error) {
console.error('格式化代码块失败:', error);
}
return edits;
}
// 获取行的缩进级别
private getIndentLevel(line: string): number {
let indent = 0;
for (let i = 0; i < line.length; i++) {
if (line[i] === ' ') {
indent++;
} else if (line[i] === '\t') {
indent += 4; // 假设一个tab等于4个空格
} else {
break;
}
}
return indent;
}
// 创建指定级别的缩进
private createIndent(level: number, options: vscode.FormattingOptions): string {
if (options.insertSpaces) {
return ' '.repeat(level);
} else {
return '\t'.repeat(Math.floor(level / 4)); // 假设一个tab等于4个空格
}
}
}

228
src/utils/beautifyHelper.ts Normal file
View File

@@ -0,0 +1,228 @@
import * as vscode from 'vscode';
// 由于 js-beautify.js 文件体积较大且复杂,我们将创建专门的存根函数
// 将使用原生的 js-beautify 功能
let _jsBeauifyInstance: any = null;
/**
* 动态创建 js_beautify 函数
*/
function createJsBeautify(): any {
if (_jsBeauifyInstance) {
return _jsBeauifyInstance;
}
try {
// 加载原始的 js-beautify.js 文件
const beautifyModule = loadJsBeautify();
_jsBeauifyInstance = beautifyModule;
return _jsBeauifyInstance;
} catch (error) {
console.error('加载 js-beautify 失败,使用后备实现:', error);
// 调用后备实现
return createBasicJsBeautify();
}
}
/**
* 加载 js-beautify 模块
*/
function loadJsBeautify(): any {
// 根据环境动态加载
try {
// 尝试 require 原始的 js-beautify.js 文件
// 注意TypeScript 会从 ./dist 目录运行,所以需要从正确的路径加载
const beautifyPath = __dirname + '/../../js-beautify.js';
const Module = require('module');
const vm = require('vm');
const fs = require('fs');
// 读取文件内容
const code = fs.readFileSync(beautifyPath, 'utf8');
// 设置全局环境
const sandbox: any = {
window: {},
global: {},
console: console,
String: String,
Array: Array,
Object: Object,
Math: Math
};
// 在沙箱中执行代码
const script = new vm.Script(code);
const context = vm.createContext(sandbox);
script.runInContext(context);
// 获取 js_beautify 函数
return context.window.js_beautify || context.js_beautify || sandbox.window.js_beautify;
} catch (loadError) {
console.error('无法加载原始 js-beautify, 错误:', loadError);
throw loadError;
}
}
/**
* 基础的 js-beautify 实现(后备方案)
*/
function createBasicJsBeautify(): any {
return function(code: string, options: any = {}): string {
// 默认选项
const defaultOptions = {
indent_size: 4,
indent_char: ' ',
preserve_newlines: true,
brace_style: 'collapse',
space_before_conditional: true,
space_after_anon_function: false,
wrap_line_length: 120,
end_with_newline: false
};
// 合并选项
const opts = { ...defaultOptions, ...options };
// 简化的代码美化实现
let formatted = code;
// 清理缩进
formatted = formatted.replace(/[\r\n]+/g, '\n');
const lines = formatted.split('\n');
const result: string[] = [];
let indentLevel = 0;
const indentStr = opts.indent_char.repeat(opts.indent_size);
for (const line of lines) {
const trimmed = line.trim();
// 跳过空行
if (trimmed.length === 0) {
result.push('');
continue;
}
// 处理大括号
if (trimmed.startsWith('}') || trimmed.startsWith(')') || trimmed.startsWith(']')) {
indentLevel = Math.max(0, indentLevel - 1);
}
// 添加缩进
const indentedLine = indentStr.repeat(indentLevel) + trimmed;
result.push(indentedLine);
// 增加缩进
if (trimmed.endsWith('{') || trimmed.endsWith('(') || trimmed.endsWith('[')) {
indentLevel++;
}
// 特殊处理 else、catch 等关键字
if (trimmed.startsWith('else') || trimmed.startsWith('catch') || trimmed.startsWith('elif')) {
// 检查前面一行是否以 } 结尾
if (result.length > 1) {
const prevLine = result[result.length - 2];
const prevTrimmed = prevLine.trim();
if (prevTrimmed.endsWith('}')) {
// 移动到前一行的必要部分
result[result.length - 2] = indentStr.repeat(indentLevel - 1) +
prevTrimmed + ' ' + trimmed;
result.pop(); // 移除当前行
indentLevel--; // 修正缩进级别
}
}
}
}
let finalResult = result.join('\n');
// 处理空格 - 在操作符周围添加空格
finalResult = finalResult
.replace(/([a-zA-Z0-9_$])([=!<>+\-*/%])([a-zA-Z0-9_$])/g, '$1 $2 $3')
.replace(/([a-zA-Z0-9_$])(,)([a-zA-Z0-9_$])/g, '$1$2 $3')
.replace(/\s+/g, ' ') // 将多个空格替换为单个空格
.trim();
return finalResult;
};
}
// 初始化 js_beautify
const jsBeautify = {
js_beautify: createJsBeautify()
};
/**
* Squirrel 语言的 js-beautify 选项配置
*/
export function getSquirrelBeautifyOptions(options: vscode.FormattingOptions): any {
return {
indent_size: options.tabSize,
indent_char: options.insertSpaces ? ' ' : '\t',
preserve_newlines: true,
max_preserve_newlines: 2,
jslint_happy: false,
brace_style: "collapse",
space_before_conditional: true,
space_after_anon_function: false,
unescape_strings: false,
wrap_line_length: 120,
end_with_newline: false
};
}
/**
* 使用 js-beautify 格式化代码
*/
export function beautifyCode(code: string, options: vscode.FormattingOptions): string {
if (!jsBeautify || !jsBeautify.js_beautify) {
console.warn('js-beautify 不可用,返回原始代码');
return code;
}
try {
const beautifyOptions = getSquirrelBeautifyOptions(options);
// 检查代码长度,处理大块代码
const maxChunkSize = 50000; // 50KB 每块
if (code.length > maxChunkSize) {
// 分割代码并分块处理
const chunks = code.split('\n');
const resultChunks: string[] = [];
for (const chunk of chunks) {
const formattedChunk = jsBeautify.js_beautify(chunk, beautifyOptions);
resultChunks.push(formattedChunk);
}
return resultChunks.join('\n');
}
// 直接格式化小代码块
return jsBeautify.js_beautify(code, beautifyOptions);
} catch (error) {
console.error('js-beautify 格式化失败:', error);
// 如果格式化失败,返回原始代码
return code;
}
}
/**
* 检测是否为 Squirrel 代码(用于确定是否应用格式化)
*/
export function isSquirrelCode(code: string): boolean {
// 简单的启发式检测 - Squirrel 特有关键字
const squirrelKeywords = [
'function', 'local', 'if', 'else', 'while', 'for', 'foreach',
'class', 'constructor', 'extends', 'instanceof', 'in',
'try', 'catch', 'throw', 'clone', 'delegate', 'resume', 'yield',
'typeof', 'member', 'rawcall', 'call', 'setdebughook'
];
// 提高检测准确性 - 需要至少匹配到1个关键字
return squirrelKeywords.some(keyword =>
new RegExp(`\\b${keyword}\\b`).test(code)
);
}