fix: error cannot read 'charAt'

This commit is contained in:
kapitche 2025-07-05 17:00:55 -04:00
parent 437bbf0c9d
commit ef67a8107a
3 changed files with 109 additions and 143 deletions

4
.gitignore vendored
View file

@ -1,4 +1,6 @@
node_modules node_modules
*.vsix *.vsix
/scrapper/discovered_mnemonics.txt /scrapper/discovered_mnemonics.txt
/scrapper/mnemonic_url_mappings.txt /scrapper/mnemonic_url_mappings.txt
*.s
*.asm

View file

@ -2,7 +2,7 @@
"name": "x86-assembly-syntax", "name": "x86-assembly-syntax",
"displayName": "Universal Assembly Syntax Highlighting", "displayName": "Universal Assembly Syntax Highlighting",
"description": "Syntax highlighting extension for x86, x64 and ARM assembly both for Intel and AT&T syntax", "description": "Syntax highlighting extension for x86, x64 and ARM assembly both for Intel and AT&T syntax",
"version": "1.2.3", "version": "1.2.4",
"engines": { "engines": {
"vscode": "^1.75.0" "vscode": "^1.75.0"
}, },

View file

@ -2,43 +2,41 @@ const vscode = require("vscode");
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
let languageConfigDisposable = null;
let instructionData = null; let instructionData = null;
function activate(context) { function activate(context) {
// Load instruction data from local JSON file // Load instruction data from local JSON file
loadInstructionData(); loadInstructionData();
// Set up initial language configuration
updateLanguageConfiguration();
// Listen for configuration changes
const configChangeListener = vscode.workspace.onDidChangeConfiguration(
(event) => {
if (event.affectsConfiguration("assembly.comments")) {
updateLanguageConfiguration();
}
}
);
// Hover provider for mnemonics // Hover provider for mnemonics
const hoverProvider = vscode.languages.registerHoverProvider("x86asm", { const hoverProvider = vscode.languages.registerHoverProvider("x86asm", {
provideHover(document, position, token) { provideHover(document, position, token) {
const range = document.getWordRangeAtPosition( try {
position, const range = document.getWordRangeAtPosition(
/\b[a-zA-Z0-9_]+\b/ position,
); /\b[a-zA-Z0-9_]+\b/
const word = document.getText(range); );
if (word && instructionData) { // Add null check for range to prevent charAt error
// Check if the word is a valid mnemonic by looking it up in the instruction data if (!range) {
const instructionInfo = getInstructionInfo(word.toLowerCase()); return undefined;
if (instructionInfo) {
return new vscode.Hover(instructionInfo);
} }
}
return undefined; const word = document.getText(range);
if (word && instructionData) {
// Check if the word is a valid mnemonic by looking it up in the instruction data
const instructionInfo = getInstructionInfo(word.toLowerCase());
if (instructionInfo) {
return new vscode.Hover(instructionInfo);
}
}
return undefined;
} catch (error) {
console.error("Error in hover provider:", error);
return undefined;
}
}, },
}); });
@ -47,22 +45,23 @@ function activate(context) {
"x86asm", "x86asm",
{ {
async provideDefinition(document, position, token) { async provideDefinition(document, position, token) {
const range = document.getWordRangeAtPosition(position); try {
if (!range) { const range = document.getWordRangeAtPosition(position);
return; if (!range) {
} return;
}
const word = document.getText(range); const word = document.getText(range);
return await findDefinition(word); return await findDefinition(word);
} catch (error) {
console.error("Error in definition provider:", error);
return undefined;
}
}, },
} }
); );
context.subscriptions.push( context.subscriptions.push(hoverProvider, definitionProvider);
hoverProvider,
definitionProvider,
configChangeListener
);
} }
function loadInstructionData() { function loadInstructionData() {
@ -97,130 +96,95 @@ function loadInstructionData() {
} }
} }
function updateLanguageConfiguration() {
// Dispose previous language configuration if it exists
if (languageConfigDisposable) {
languageConfigDisposable.dispose();
}
// Get current configuration
const config = vscode.workspace.getConfiguration("assembly.comments");
const lineComment = config.get("lineComment", ";");
const blockComment = config.get("blockComment", ["/*", "*/"]);
// Register new language configuration
languageConfigDisposable = vscode.languages.setLanguageConfiguration(
"x86asm",
{
comments: {
lineComment: lineComment,
blockComment: blockComment,
},
brackets: [
["{", "}"],
["[", "]"],
["(", ")"],
],
autoClosingPairs: [
["{", "}"],
["[", "]"],
["(", ")"],
['"', '"'],
["'", "'"],
],
surroundingPairs: [
["{", "}"],
["[", "]"],
["(", ")"],
['"', '"'],
["'", "'"],
],
folding: {
markers: {
start: "\\.section",
end: "\\.endsection",
},
},
}
);
}
function getInstructionInfo(instruction) { function getInstructionInfo(instruction) {
if (!instructionData) { try {
if (!instructionData) {
return null;
}
const info = instructionData[instruction.toLowerCase()];
if (!info) {
return null;
}
// Format the hover content using the syntaxes/x86_instructions.json format
// Keep title as is since it usually doesn't need paragraph breaks
let hoverContent = `**${info.title || "Unknown Instruction"}**\n\n`;
if (info.opcode) {
hoverContent += `**Opcode:** ${info.opcode}\n\n`;
}
if (info.description) {
// Replace single \n with double \n for proper markdown paragraph breaks
const formattedDescription = info.description.replace(/\n/g, "\n\n");
hoverContent += `**Description:** ${formattedDescription}\n\n`;
}
if (info.url) {
hoverContent += `[View Documentation](${info.url})`;
}
return hoverContent;
} catch (error) {
console.error("Error in getInstructionInfo:", error);
return null; return null;
} }
const info = instructionData[instruction.toLowerCase()];
if (!info) {
return null;
}
// Format the hover content using the syntaxes/x86_instructions.json format
// Keep title as is since it usually doesn't need paragraph breaks
let hoverContent = `**${info.title}**\n\n`;
if (info.opcode) {
hoverContent += `**Opcode:** ${info.opcode}\n\n`;
}
if (info.description) {
// Replace single \n with double \n for proper markdown paragraph breaks
const formattedDescription = info.description.replace(/\n/g, "\n\n");
hoverContent += `**Description:** ${formattedDescription}\n\n`;
}
if (info.url) {
hoverContent += `[View Documentation](${info.url})`;
}
return hoverContent;
} }
async function findDefinition(word) { async function findDefinition(word) {
// Get all x86 assembly files in the workspace try {
const files = await vscode.workspace.findFiles( // Get all x86 assembly files in the workspace
"**/*.s", const files = await vscode.workspace.findFiles(
"**/node_modules/**" "**/*.s",
); "**/node_modules/**"
);
for (const file of files) { for (const file of files) {
const document = await vscode.workspace.openTextDocument(file); const document = await vscode.workspace.openTextDocument(file);
const text = document.getText(); const text = document.getText();
const lines = text.split("\n"); const lines = text.split("\n");
// Check for definitions in each file // Check for definitions in each file
const location = searchForDefinition(lines, word, document); const location = searchForDefinition(lines, word, document);
if (location) { if (location) {
return location; return location;
}
} }
}
// If no definition is found, return undefined // If no definition is found, return undefined
return undefined; return undefined;
} catch (error) {
console.error("Error in findDefinition:", error);
return undefined;
}
} }
function searchForDefinition(lines, word, document) { function searchForDefinition(lines, word, document) {
const externRegex = new RegExp(`^extern\\s+${word}\\s*`, "i"); try {
const globalRegex = new RegExp(`^global\\s+${word}\\s*`, "i"); const externRegex = new RegExp(`^extern\\s+${word}\\s*`, "i");
const labelRegex = new RegExp(`^${word}:`, "i"); const globalRegex = new RegExp(`^global\\s+${word}\\s*`, "i");
const labelRegex = new RegExp(`^${word}:`, "i");
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
if ( if (
externRegex.test(lines[i]) || externRegex.test(lines[i]) ||
globalRegex.test(lines[i]) || globalRegex.test(lines[i]) ||
labelRegex.test(lines[i]) labelRegex.test(lines[i])
) { ) {
return new vscode.Location(document.uri, new vscode.Position(i, 0)); return new vscode.Location(document.uri, new vscode.Position(i, 0));
}
} }
}
return undefined; // If no match is found return undefined; // If no match is found
} catch (error) {
console.error("Error in searchForDefinition:", error);
return undefined;
}
} }
function deactivate() { function deactivate() {
if (languageConfigDisposable) { // No cleanup needed
languageConfigDisposable.dispose();
}
} }
module.exports = { module.exports = {