1.0.0 初始版

This commit is contained in:
睿 安
2025-09-17 10:54:25 +08:00
commit dc0cbe71dc
315 changed files with 528712 additions and 0 deletions

906
dist/providers/codeErrorProvider.js vendored Normal file
View File

@@ -0,0 +1,906 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CodeErrorProvider = void 0;
const vscode = __importStar(require("vscode"));
// 代码错误检测提供者类
class CodeErrorProvider {
// 提供代码诊断信息
static async provideDiagnostics(document, diagnostics) {
const diagnosticList = [];
let isInBlockComment = false; // 文档级别的块注释状态
// 全文档检查,支持多行结构
const documentText = document.getText();
const lines = documentText.split('\n');
// 检查未闭合的字符串(支持多行)
diagnosticList.push(...this.checkForUnclosedStrings(document));
// 检查未闭合的括号(支持多行)
diagnosticList.push(...this.checkForUnclosedBrackets(document));
// 逐行检查其他错误,传递块注释状态
for (let i = 0; i < document.lineCount; i++) {
const line = document.lineAt(i);
const result = this.checkLineForErrors(line, i, isInBlockComment);
diagnosticList.push(...result.diagnostics);
isInBlockComment = result.isInBlockComment; // 更新块注释状态
}
// 发布诊断信息
diagnostics.set(document.uri, diagnosticList);
}
// 检查单行代码错误,支持块注释状态跟踪
static checkLineForErrors(line, lineIndex, isInBlockComment) {
const diagnostics = [];
const lineText = line.text;
// 处理行注释和块注释状态
const commentInfo = this.processCommentsAndGetValidText(lineText, isInBlockComment);
// 如果整行都在注释中,直接返回
if (commentInfo.skipEntireLine) {
return { diagnostics, isInBlockComment: commentInfo.newBlockCommentState };
}
// 只对非注释部分进行错误检测
if (commentInfo.validText.trim().length > 0) {
// 检查常见的语法错误
diagnostics.push(...this.checkForCommonSyntaxErrorsWithValidText(lineText, commentInfo.validText, commentInfo.validRange, lineIndex));
// 检查可能的拼写错误
diagnostics.push(...this.checkForPossibleTyposWithValidText(lineText, commentInfo.validText, commentInfo.validRange, lineIndex));
}
return {
diagnostics,
isInBlockComment: commentInfo.newBlockCommentState
};
}
// 处理注释并获取有效的代码文本
static processCommentsAndGetValidText(lineText, isInBlockComment) {
let currentBlockCommentState = isInBlockComment;
// 如果整行都在块注释中,先检查是否有结束标记
if (currentBlockCommentState) {
const blockCommentEnd = lineText.indexOf('*/');
if (blockCommentEnd !== -1) {
// 找到块注释结束,从结束位置后开始处理
currentBlockCommentState = false;
const remainingLine = lineText.substring(blockCommentEnd + 2);
// 递归处理剩余部分
const remainingResult = this.processCommentsAndGetValidText(remainingLine, false);
return {
validText: remainingResult.validText,
validRange: {
start: blockCommentEnd + 2 + remainingResult.validRange.start,
end: blockCommentEnd + 2 + remainingResult.validRange.end
},
skipEntireLine: remainingResult.skipEntireLine,
newBlockCommentState: remainingResult.newBlockCommentState
};
}
else {
// 整行都在块注释中
return {
validText: '',
validRange: { start: 0, end: 0 },
skipEntireLine: true,
newBlockCommentState: true
};
}
}
// 现在处理这一行,移除所有注释,只保留有效代码部分
let result = '';
let validRanges = [];
let inString = false;
let stringChar = '';
let escaped = false;
let i = 0;
let currentValidStart = 0;
while (i < lineText.length) {
const char = lineText[i];
const nextChar = i < lineText.length - 1 ? lineText[i + 1] : '';
// 处理字符串状态
if (!inString) {
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
escaped = false;
}
}
else {
if (escaped) {
escaped = false;
i++;
continue;
}
if (char === '\\') {
escaped = true;
i++;
continue;
}
if (char === stringChar) {
inString = false;
stringChar = '';
i++;
continue;
}
i++;
continue;
}
// 只有在非字符串状态下才检查注释
if (!inString) {
// 检查行注释 // (优先级最高)
if (char === '/' && nextChar === '/') {
// 遇到行注释,保存当前有效部分,后续全部跳过
if (i > currentValidStart) {
validRanges.push({ start: currentValidStart, end: i });
result += lineText.substring(currentValidStart, i);
}
break; // 行注释后面的内容全部跳过
}
// 检查块注释开始 /*
if (char === '/' && nextChar === '*') {
// 保存块注释前的有效部分
if (i > currentValidStart) {
validRanges.push({ start: currentValidStart, end: i });
result += lineText.substring(currentValidStart, i);
}
// 寻找块注释结束
const blockCommentEnd = lineText.indexOf('*/', i + 2);
if (blockCommentEnd !== -1) {
// 同行找到块注释结束,跳过整个块注释
i = blockCommentEnd + 2;
currentValidStart = i;
continue;
}
else {
// 没有找到结束标记,块注释延续到下一行
currentBlockCommentState = true;
break;
}
}
}
i++;
}
// 添加最后的有效部分
if (!currentBlockCommentState && currentValidStart < lineText.length) {
validRanges.push({ start: currentValidStart, end: lineText.length });
result += lineText.substring(currentValidStart);
}
// 如果没有有效内容,返回空
if (validRanges.length === 0) {
return {
validText: '',
validRange: { start: 0, end: 0 },
skipEntireLine: true,
newBlockCommentState: currentBlockCommentState
};
}
// 返回第一个有效范围(简化处理,实际使用时会在所有有效范围中检查)
return {
validText: result,
validRange: { start: validRanges[0].start, end: validRanges[validRanges.length - 1].end },
skipEntireLine: result.trim().length === 0,
newBlockCommentState: currentBlockCommentState
};
}
// 检查指定位置是否在字符串中
static isInString(line, position) {
let inString = false;
let stringChar = '';
let escaped = false;
for (let i = 0; i < position && i < line.length; i++) {
const char = line[i];
if (!inString) {
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
escaped = false;
}
}
else {
if (escaped) {
escaped = false;
continue;
}
if (char === '\\') {
escaped = true;
continue;
}
if (char === stringChar) {
inString = false;
stringChar = '';
}
}
}
return inString;
}
// 基于有效文本范围检查语法错误
static checkForCommonSyntaxErrorsWithValidText(originalLine, validText, validRange, lineIndex) {
const diagnostics = [];
// 跳过空行
if (validText.trim().length === 0) {
return diagnostics;
}
// 由于validText可能是多个片段拼接的结果我们需要直接在原始行中查找
// 但只检查那些不在注释和字符串中的位置
const typoPatterns = [
{ pattern: /\bloacl\b/g, correct: 'local', message: '拼写错误:应该是 "local" 而不是 "loacl"' },
{ pattern: /\bfunctoin\b/g, correct: 'function', message: '拼写错误:应该是 "function" 而不是 "functoin"' },
{ pattern: /\bretun\b/g, correct: 'return', message: '拼写错误:应该是 "return" 而不是 "retun"' },
{ pattern: /\bwhlie\b/g, correct: 'while', message: '拼写错误:应该是 "while" 而不是 "whlie"' },
{ pattern: /\belsee\b/g, correct: 'else', message: '拼写错误:应该是 "else" 而不是 "elsee"' },
{ pattern: /\bforech\b/g, correct: 'foreach', message: '拼写错误:应该是 "foreach" 而不是 "forech"' },
{ pattern: /\bclas\b/g, correct: 'class', message: '拼写错误:应该是 "class" 而不是 "clas"' },
{ pattern: /\bbreka\b/g, correct: 'break', message: '拼写错误:应该是 "break" 而不是 "breka"' },
{ pattern: /\bcontineu\b/g, correct: 'continue', message: '拼写错误:应该是 "continue" 而不是 "contineu"' }
];
typoPatterns.forEach(({ pattern, correct, message }) => {
let match;
// 在原始行中查找所有匹配
while ((match = pattern.exec(originalLine)) !== null) {
const matchPosition = match.index;
// 检查这个位置是否在有效的代码区域(不在注释或字符串中)
if (this.isPositionInValidCode(originalLine, matchPosition)) {
const range = new vscode.Range(new vscode.Position(lineIndex, matchPosition), new vscode.Position(lineIndex, matchPosition + match[0].length));
const diagnostic = new vscode.Diagnostic(range, message, vscode.DiagnosticSeverity.Error);
diagnostic.tags = [vscode.DiagnosticTag.Deprecated];
diagnostics.push(diagnostic);
}
}
});
return diagnostics;
}
// 检查指定位置是否在有效代码中(不在注释或字符串中)
static isPositionInValidCode(line, position) {
let inString = false;
let stringChar = '';
let escaped = false;
let inBlockComment = false;
for (let i = 0; i < position && i < line.length; i++) {
const char = line[i];
const nextChar = i < line.length - 1 ? line[i + 1] : '';
// 如果在块注释中,检查是否遇到结束标记
if (inBlockComment) {
if (char === '*' && nextChar === '/') {
inBlockComment = false;
i++; // 跳过 '/'
}
continue;
}
// 处理字符串状态
if (!inString) {
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
escaped = false;
}
}
else {
if (escaped) {
escaped = false;
continue;
}
if (char === '\\') {
escaped = true;
continue;
}
if (char === stringChar) {
inString = false;
stringChar = '';
}
continue;
}
// 只有在非字符串状态下才检查注释
if (!inString) {
// 检查行注释
if (char === '/' && nextChar === '/') {
return false; // 位置在行注释中
}
// 检查块注释开始
if (char === '/' && nextChar === '*') {
inBlockComment = true;
i++; // 跳过 '*'
continue;
}
}
}
// 如果到达目标位置时仍在字符串或块注释中,则该位置无效
return !inString && !inBlockComment;
}
// 基于有效文本范围检查可能的拼写错误
static checkForPossibleTyposWithValidText(originalLine, validText, validRange, lineIndex) {
const diagnostics = [];
// 暂时空实现,可以后续扩展
return diagnostics;
}
// 检查常见的语法错误
static checkForCommonSyntaxErrors(lineText, lineIndex) {
const diagnostics = [];
// 跳过空行
const trimmedLine = lineText.trim();
if (trimmedLine.length === 0) {
return diagnostics;
}
// 检查是否使用了错误的关键字拼写(仅检查明显的拼写错误)
const typoPatterns = [
{ pattern: /\bloacl\b/g, correct: 'local', message: '拼写错误:应该是 "local" 而不是 "loacl"' },
{ pattern: /\bfunctoin\b/g, correct: 'function', message: '拼写错误:应该是 "function" 而不是 "functoin"' },
{ pattern: /\bretun\b/g, correct: 'return', message: '拼写错误:应该是 "return" 而不是 "retun"' },
{ pattern: /\bwhlie\b/g, correct: 'while', message: '拼写错误:应该是 "while" 而不是 "whlie"' },
{ pattern: /\belsee\b/g, correct: 'else', message: '拼写错误:应该是 "else" 而不是 "elsee"' },
{ pattern: /\bforech\b/g, correct: 'foreach', message: '拼写错误:应该是 "foreach" 而不是 "forech"' },
{ pattern: /\bclas\b/g, correct: 'class', message: '拼写错误:应该是 "class" 而不是 "clas"' },
{ pattern: /\bbreka\b/g, correct: 'break', message: '拼写错误:应该是 "break" 而不是 "breka"' },
{ pattern: /\bcontineu\b/g, correct: 'continue', message: '拼写错误:应该是 "continue" 而不是 "contineu"' }
];
typoPatterns.forEach(({ pattern, correct, message }) => {
let match;
while ((match = pattern.exec(lineText)) !== null) {
// 检查这个匹配是否在注释或字符串中
if (this.isPositionInCommentOrString(lineText, match.index)) {
continue;
}
const range = new vscode.Range(new vscode.Position(lineIndex, match.index), new vscode.Position(lineIndex, match.index + match[0].length));
const diagnostic = new vscode.Diagnostic(range, message, vscode.DiagnosticSeverity.Error);
// 添加快速修复信息
diagnostic.tags = [vscode.DiagnosticTag.Deprecated];
diagnostics.push(diagnostic);
}
});
// 检查赋值操作符错误(使用 = 而不是 == 进行比较)
// 更精确的正则表达式,避免误报
const assignmentPattern = /\b(if|while)\s*\(\s*[^=<>!]*\s=(?!=)\s*[^=][^)]*\)/g;
let assignmentMatch;
while ((assignmentMatch = assignmentPattern.exec(lineText)) !== null) {
// 检查这个匹配是否在注释或字符串中
if (this.isPositionInCommentOrString(lineText, assignmentMatch.index)) {
continue;
}
// 排除明显的合法赋值情况
const matchText = assignmentMatch[0];
// 检查是否是函数调用或其他合法语法
if (!matchText.includes('()') && !matchText.includes('new ')) {
const range = new vscode.Range(new vscode.Position(lineIndex, assignmentMatch.index), new vscode.Position(lineIndex, assignmentMatch.index + assignmentMatch[0].length));
const diagnostic = new vscode.Diagnostic(range, '可能的逻辑错误:在条件语句中使用了赋值操作符 "=" 而不是比较操作符 "=="', vscode.DiagnosticSeverity.Warning);
diagnostics.push(diagnostic);
}
}
// 检查常见的语法结构错误
// 检查函数定义语法
if (lineText.includes('function') && !lineText.match(/function\s+[a-zA-Z_]\w*\s*\(/)) {
const functionMatch = lineText.match(/function\s*\(/);
if (functionMatch && !this.isPositionInCommentOrString(lineText, functionMatch.index)) {
const range = new vscode.Range(new vscode.Position(lineIndex, functionMatch.index), new vscode.Position(lineIndex, functionMatch.index + functionMatch[0].length));
const diagnostic = new vscode.Diagnostic(range, '语法错误:函数定义缺少函数名', vscode.DiagnosticSeverity.Error);
diagnostics.push(diagnostic);
}
}
// 检查缺少分号的语句(仅对明显需要分号的语句检查)
const needsSemicolon = /\b(local|return|break|continue)\s+[^;\/]*[^;\s\/]$/;
if (needsSemicolon.test(trimmedLine) && !trimmedLine.endsWith(';') && !trimmedLine.endsWith('{')) {
// 确保这不是在注释中
const cleanLine = this.removeStringsAndComments(lineText);
if (cleanLine.trim()) {
const range = new vscode.Range(new vscode.Position(lineIndex, lineText.length - 1), new vscode.Position(lineIndex, lineText.length));
const diagnostic = new vscode.Diagnostic(range, '可能缺少分号', vscode.DiagnosticSeverity.Information);
diagnostics.push(diagnostic);
}
}
return diagnostics;
}
// 检查未闭合的字符串(支持多行文档检查)
static checkForUnclosedStrings(document) {
const diagnostics = [];
const text = document.getText();
// 使用状态机来正确解析字符串
let inString = false;
let stringStartPos = null;
let stringChar = '';
let escaped = false;
let inLineComment = false;
let inBlockComment = false;
const lines = text.split('\n');
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
const line = lines[lineIndex];
// 检查是否整行都是注释(以 // 开头)
const trimmedLine = line.trim();
if (trimmedLine.startsWith('//')) {
inLineComment = true;
}
for (let charIndex = 0; charIndex < line.length; charIndex++) {
const char = line[charIndex];
const nextChar = charIndex < line.length - 1 ? line[charIndex + 1] : '';
// 处理注释
if (!inString) {
if (!inBlockComment && char === '/' && nextChar === '/') {
inLineComment = true;
charIndex++; // 跳过下一个字符
continue;
}
if (!inLineComment && char === '/' && nextChar === '*') {
inBlockComment = true;
charIndex++; // 跳过下一个字符
continue;
}
if (inBlockComment && char === '*' && nextChar === '/') {
inBlockComment = false;
charIndex++; // 跳过下一个字符
continue;
}
}
// 如果在注释中,跳过所有处理
if (inLineComment || inBlockComment) {
continue;
}
if (!inString) {
// 检查字符串开始
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
stringStartPos = new vscode.Position(lineIndex, charIndex);
escaped = false;
}
}
else {
// 在字符串中
if (escaped) {
escaped = false;
continue;
}
if (char === '\\') {
escaped = true;
continue;
}
if (char === stringChar) {
// 字符串结束
inString = false;
stringStartPos = null;
stringChar = '';
}
}
}
// 行结束处理
inLineComment = false; // 行注释在行末结束
// 只有在非注释行且有未闭合字符串时才报告错误
if (inString && stringStartPos && stringStartPos.line === lineIndex && !trimmedLine.startsWith('//')) {
// 如果字符串在当前行开始但没有结束,报告错误
const range = new vscode.Range(stringStartPos, new vscode.Position(lineIndex, line.length));
const diagnostic = new vscode.Diagnostic(range, `字符串未正确闭合:缺少结束${stringChar === '"' ? '双' : '单'}引号`, vscode.DiagnosticSeverity.Error);
diagnostics.push(diagnostic);
// 重置状态,避免后续行都报错
inString = false;
stringStartPos = null;
}
}
// 如果文档结束时还有未闭合的字符串,并且不在注释中
if (inString && stringStartPos) {
const lastLine = lines.length - 1;
const lastLineTrimmed = lines[lastLine].trim();
if (!lastLineTrimmed.startsWith('//')) {
const range = new vscode.Range(stringStartPos, new vscode.Position(lastLine, lines[lastLine].length));
const diagnostic = new vscode.Diagnostic(range, `字符串未正确闭合:缺少结束${stringChar === '"' ? '双' : '单'}引号`, vscode.DiagnosticSeverity.Error);
diagnostics.push(diagnostic);
}
}
return diagnostics;
}
// 检查未闭合的括号(支持多行文档检查)
static checkForUnclosedBrackets(document) {
const diagnostics = [];
const text = document.getText();
// 括号栈,记录每个开括号的位置和类型
const bracketStack = [];
const bracketPairs = [
{ open: '(', close: ')', name: '圆括号' },
{ open: '[', close: ']', name: '方括号' },
{ open: '{', close: '}', name: '花括号' }
];
// 状态追踪
let inString = false;
let stringChar = '';
let escaped = false;
let inLineComment = false;
let inBlockComment = false;
const lines = text.split('\n');
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
const line = lines[lineIndex];
// 检查是否整行都是注释(以 // 开头)
const trimmedLine = line.trim();
const isCommentLine = trimmedLine.startsWith('//');
for (let charIndex = 0; charIndex < line.length; charIndex++) {
const char = line[charIndex];
const nextChar = charIndex < line.length - 1 ? line[charIndex + 1] : '';
// 处理注释
if (!inString) {
if (!inBlockComment && char === '/' && nextChar === '/') {
inLineComment = true;
charIndex++; // 跳过下一个字符
continue;
}
if (!inLineComment && char === '/' && nextChar === '*') {
inBlockComment = true;
charIndex++; // 跳过下一个字符
continue;
}
if (inBlockComment && char === '*' && nextChar === '/') {
inBlockComment = false;
charIndex++; // 跳过下一个字符
continue;
}
}
// 如果在注释中,跳过所有处理
if (inLineComment || inBlockComment || isCommentLine) {
continue;
}
// 处理字符串状态
if (!inString) {
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
escaped = false;
}
}
else {
if (escaped) {
escaped = false;
continue;
}
if (char === '\\') {
escaped = true;
continue;
}
if (char === stringChar) {
inString = false;
stringChar = '';
}
continue; // 在字符串中,跳过括号检查
}
// 检查括号(只在非字符串、非注释中)
if (!inString && !inLineComment && !inBlockComment && !isCommentLine) {
const openBracket = bracketPairs.find(bp => bp.open === char);
if (openBracket) {
bracketStack.push({
char: char,
position: new vscode.Position(lineIndex, charIndex),
name: openBracket.name,
inComment: false
});
}
else {
const closeBracket = bracketPairs.find(bp => bp.close === char);
if (closeBracket) {
if (bracketStack.length === 0) {
// 多余的闭合括号
const range = new vscode.Range(new vscode.Position(lineIndex, charIndex), new vscode.Position(lineIndex, charIndex + 1));
const diagnostic = new vscode.Diagnostic(range, `多余的${closeBracket.name}闭合符`, vscode.DiagnosticSeverity.Error);
diagnostics.push(diagnostic);
}
else {
const lastOpen = bracketStack.pop();
const expectedClose = bracketPairs.find(bp => bp.open === lastOpen.char)?.close;
if (expectedClose !== char) {
// 括号不匹配
const range = new vscode.Range(new vscode.Position(lineIndex, charIndex), new vscode.Position(lineIndex, charIndex + 1));
const diagnostic = new vscode.Diagnostic(range, `括号不匹配:期望 "${expectedClose}" 但找到 "${char}"`, vscode.DiagnosticSeverity.Error);
diagnostics.push(diagnostic);
// 也标记未匹配的开括号
const openRange = new vscode.Range(lastOpen.position, new vscode.Position(lastOpen.position.line, lastOpen.position.character + 1));
const openDiagnostic = new vscode.Diagnostic(openRange, `未匹配的${lastOpen.name}`, vscode.DiagnosticSeverity.Error);
diagnostics.push(openDiagnostic);
}
}
}
}
}
}
// 行结束处理
inLineComment = false; // 行注释在行末结束
}
// 检查未闭合的开括号(排除在注释中的括号)
bracketStack.forEach(bracket => {
if (!bracket.inComment) {
const range = new vscode.Range(bracket.position, new vscode.Position(bracket.position.line, bracket.position.character + 1));
const diagnostic = new vscode.Diagnostic(range, `未闭合的${bracket.name}`, vscode.DiagnosticSeverity.Error);
diagnostics.push(diagnostic);
}
});
return diagnostics;
}
// 检查可能的拼写错误
static checkForPossibleTypos(lineText, lineIndex) {
const diagnostics = [];
// 跳过空行
const trimmedLine = lineText.trim();
if (trimmedLine.length === 0) {
return diagnostics;
}
// 更完整的Squirrel关键字列表
const squirrelKeywords = [
'function', 'local', 'if', 'else', 'while', 'for', 'foreach', 'in',
'return', 'break', 'continue', 'class', 'extends', 'constructor',
'null', 'true', 'false', 'try', 'catch', 'throw', 'const',
'enum', 'switch', 'case', 'default', 'delete', 'typeof',
'clone', 'resume', 'yield', 'static', 'this', 'base'
];
// 提取标识符(避免数字、操作符等)
const wordPattern = /\b[a-zA-Z_]\w{2,}\b/g;
let match;
while ((match = wordPattern.exec(lineText)) !== null) {
const word = match[0];
const wordLower = word.toLowerCase();
const startIndex = match.index;
// 检查这个单词是否在注释或字符串中
if (this.isPositionInCommentOrString(lineText, startIndex)) {
continue;
}
// 跳过已知的关键字(正确拼写)
if (squirrelKeywords.includes(wordLower)) {
continue;
}
// 跳过常见的标识符模式(避免误报)
if (this.isLikelyValidIdentifier(word)) {
continue;
}
// 检查是否与关键字相似
const similarKeyword = squirrelKeywords.find(keyword => {
const distance = this.editDistance(wordLower, keyword);
// 只对编辑距离为1-2且长度相近的单词提示
return distance >= 1 && distance <= 2 &&
Math.abs(word.length - keyword.length) <= 2;
});
if (similarKeyword) {
const range = new vscode.Range(new vscode.Position(lineIndex, startIndex), new vscode.Position(lineIndex, startIndex + word.length));
const diagnostic = new vscode.Diagnostic(range, `可能的拼写错误:您是否想输入 "${similarKeyword}"?`, vscode.DiagnosticSeverity.Hint);
diagnostics.push(diagnostic);
}
}
return diagnostics;
}
// 检查指定位置是否在注释或字符串中
static isPositionInCommentOrString(line, position) {
let inString = false;
let stringChar = '';
let escaped = false;
let inBlockComment = false;
for (let i = 0; i < position && i < line.length; i++) {
const char = line[i];
const nextChar = i < line.length - 1 ? line[i + 1] : '';
if (inBlockComment) {
if (char === '*' && nextChar === '/') {
inBlockComment = false;
i++; // 跳过 '/'
}
continue;
}
// 检查行注释
if (char === '/' && nextChar === '/') {
return true; // 位置在行注释中
}
// 检查块注释开始
if (char === '/' && nextChar === '*') {
inBlockComment = true;
i++; // 跳过 '*'
continue;
}
if (!inString) {
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
escaped = false;
}
}
else {
if (escaped) {
escaped = false;
continue;
}
if (char === '\\') {
escaped = true;
continue;
}
if (char === stringChar) {
inString = false;
stringChar = '';
}
}
}
return inString || inBlockComment;
}
// 移除字符串和注释内容,避免对其中的内容进行拼写检查
static removeStringsAndComments(line) {
let result = '';
let inString = false;
let stringChar = '';
let escaped = false;
let inLineComment = false;
let inBlockComment = false;
for (let i = 0; i < line.length; i++) {
const char = line[i];
const nextChar = i < line.length - 1 ? line[i + 1] : '';
// 如果已经在行注释中,所有后续字符都用空格替换
if (inLineComment) {
result += ' ';
continue;
}
// 如果已经在块注释中,检查结束标记
if (inBlockComment) {
if (char === '*' && nextChar === '/') {
inBlockComment = false;
result += ' '; // 用空格替换 */
i++; // 跳过下一个字符
}
else {
result += ' '; // 用空格替换块注释内容
}
continue;
}
if (!inString) {
// 检查行注释开始
if (char === '/' && nextChar === '/') {
inLineComment = true;
result += ' '; // 用空格替换 //
i++; // 跳过下一个字符
continue;
}
// 检查块注释开始
if (char === '/' && nextChar === '*') {
inBlockComment = true;
result += ' '; // 用空格替换 /*
i++; // 跳过下一个字符
continue;
}
// 检查字符串开始
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
escaped = false;
result += ' '; // 用空格替换字符串内容
continue;
}
}
else {
// 在字符串中处理转义和结束
if (escaped) {
escaped = false;
result += ' ';
continue;
}
if (char === '\\') {
escaped = true;
result += ' ';
continue;
}
if (char === stringChar) {
inString = false;
stringChar = '';
result += ' ';
continue;
}
result += ' '; // 用空格替换字符串内容
continue;
}
// 保留非字符串、非注释的字符
result += char;
}
return result;
}
// 判断是否是可能的有效标识符(减少误报)
static isLikelyValidIdentifier(word) {
// 常见的有效标识符模式
const validPatterns = [
/^[A-Z][A-Z_0-9]+$/, // 常量名(全大写)
/^[a-z][a-zA-Z0-9]*$/, // 驼峰命名
/^[a-z]+_[a-z0-9_]*$/, // 下划线命名
/^[A-Z][a-zA-Z0-9]*$/, // 帕斯卡命名
/^\w+\d+$/, // 带数字结尾
/^get[A-Z]/, // getter方法
/^set[A-Z]/, // setter方法
/^is[A-Z]/, // 布尔方法
/^has[A-Z]/, // 检查方法
];
return validPatterns.some(pattern => pattern.test(word));
}
// 计算两个字符串之间的编辑距离Levenshtein距离
static editDistance(str1, str2) {
const matrix = [];
// 初始化矩阵
for (let i = 0; i <= str2.length; i++) {
matrix[i] = [i];
}
for (let j = 0; j <= str1.length; j++) {
matrix[0][j] = j;
}
// 填充矩阵
for (let i = 1; i <= str2.length; i++) {
for (let j = 1; j <= str1.length; j++) {
if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
}
else {
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // 替换
matrix[i][j - 1] + 1, // 插入
matrix[i - 1][j] + 1 // 删除
);
}
}
}
return matrix[str2.length][str1.length];
}
// 实现CodeActionProvider接口
async provideCodeActions(document, range, context, token) {
const actions = [];
// 为诊断问题提供快速修复
for (const diagnostic of context.diagnostics) {
// 拼写错误快速修复
if (diagnostic.message.includes('可能的拼写错误:您是否想输入')) {
const match = diagnostic.message.match(/您是否想输入 "([^"]+)"\?/);
if (match) {
const correctWord = match[1];
const action = new vscode.CodeAction(`将 "${document.getText(diagnostic.range)}" 更正为 "${correctWord}"`, vscode.CodeActionKind.QuickFix);
action.edit = new vscode.WorkspaceEdit();
action.edit.replace(document.uri, diagnostic.range, correctWord);
action.isPreferred = true;
actions.push(action);
}
}
// 明显拼写错误快速修复
else if (diagnostic.message.includes('拼写错误:应该是')) {
const match = diagnostic.message.match(/应该是 "([^"]+)" 而不是 "[^"]+"/);
if (match) {
const correctWord = match[1];
const action = new vscode.CodeAction(`更正拼写为 "${correctWord}"`, vscode.CodeActionKind.QuickFix);
action.edit = new vscode.WorkspaceEdit();
action.edit.replace(document.uri, diagnostic.range, correctWord);
action.isPreferred = true;
actions.push(action);
}
}
// 添加分号快速修复
else if (diagnostic.message.includes('可能缺少分号')) {
const action = new vscode.CodeAction('添加分号', vscode.CodeActionKind.QuickFix);
action.edit = new vscode.WorkspaceEdit();
const line = document.lineAt(diagnostic.range.start.line);
const endPos = new vscode.Position(line.lineNumber, line.text.length);
action.edit.insert(document.uri, endPos, ';');
actions.push(action);
}
// 修复赋值操作符错误
else if (diagnostic.message.includes('使用了赋值操作符 "=" 而不是比较操作符')) {
const action = new vscode.CodeAction('将 "=" 更改为 "=="', vscode.CodeActionKind.QuickFix);
action.edit = new vscode.WorkspaceEdit();
const text = document.getText(diagnostic.range);
const fixedText = text.replace(/([^=])=([^=])/g, '$1==$2');
action.edit.replace(document.uri, diagnostic.range, fixedText);
actions.push(action);
}
}
return actions;
}
}
exports.CodeErrorProvider = CodeErrorProvider;
//# sourceMappingURL=codeErrorProvider.js.map