Add configurable comment characters for assembly
Introduces new settings for customizing line and block comment characters via VS Code configuration. Updates the extension to dynamically apply these settings and documents the feature in the README. Also bumps the minimum VS Code engine version and extension version.
This commit is contained in:
parent
0d0cc1dd84
commit
43fb2d4a78
21
README.md
21
README.md
|
|
@ -49,6 +49,8 @@ This extension provides syntax highlighting for:
|
||||||
|
|
||||||
## Customization 🎨
|
## Customization 🎨
|
||||||
|
|
||||||
|
### Syntax Highlighting Colors
|
||||||
|
|
||||||
You can customize the colors used for syntax highlighting by modifying your VS Code color theme. Add or modify entries in your `settings.json` file under `"editor.tokenColorCustomizations"`.
|
You can customize the colors used for syntax highlighting by modifying your VS Code color theme. Add or modify entries in your `settings.json` file under `"editor.tokenColorCustomizations"`.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
@ -72,6 +74,25 @@ For example:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Comment Characters
|
||||||
|
|
||||||
|
You can configure which characters are used for comments to match your assembler. Add these settings to your VS Code `settings.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"assembly.comments.lineComment": "#",
|
||||||
|
"assembly.comments.blockComment": ["/*", "*/"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Common configurations:**
|
||||||
|
|
||||||
|
- **GNU Assembler (as)**: Use `#` for line comments
|
||||||
|
- **NASM/MASM**: Use `;` for line comments (default)
|
||||||
|
- **Custom assemblers**: Set to any character or string you prefer
|
||||||
|
|
||||||
|
The extension will automatically update comment behavior when you change these settings.
|
||||||
|
|
||||||
## Contributing 🤝
|
## Contributing 🤝
|
||||||
|
|
||||||
If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the GitHub repository.
|
If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the GitHub repository.
|
||||||
|
|
|
||||||
35
package.json
35
package.json
|
|
@ -2,18 +2,43 @@
|
||||||
"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.1.0",
|
"version": "1.2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.60.0"
|
"vscode": "^1.75.0"
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"Programming Languages"
|
"Programming Languages"
|
||||||
],
|
],
|
||||||
"main": "./src/extension.js",
|
"main": "./src/extension.js",
|
||||||
"activationEvents": [
|
|
||||||
"onLanguage:x86asm"
|
|
||||||
],
|
|
||||||
"contributes": {
|
"contributes": {
|
||||||
|
"configuration": {
|
||||||
|
"title": "Assembly Language",
|
||||||
|
"properties": {
|
||||||
|
"assembly.comments.lineComment": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ";",
|
||||||
|
"description": "Character(s) used for line comments",
|
||||||
|
"examples": [
|
||||||
|
";",
|
||||||
|
"#",
|
||||||
|
"//"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"assembly.comments.blockComment": {
|
||||||
|
"type": "array",
|
||||||
|
"default": [
|
||||||
|
"/*",
|
||||||
|
"*/"
|
||||||
|
],
|
||||||
|
"description": "Characters used for block comments [start, end]",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"minItems": 2,
|
||||||
|
"maxItems": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"languages": [
|
"languages": [
|
||||||
{
|
{
|
||||||
"id": "x86asm",
|
"id": "x86asm",
|
||||||
|
|
|
||||||
262
src/extension.js
262
src/extension.js
|
|
@ -1,122 +1,212 @@
|
||||||
const vscode = require('vscode');
|
const vscode = require("vscode");
|
||||||
const axios = require('axios');
|
const axios = require("axios");
|
||||||
const cheerio = require('cheerio');
|
const cheerio = require("cheerio");
|
||||||
const list = require('./mnemonics.js');
|
const list = require("./mnemonics.js");
|
||||||
|
|
||||||
|
let languageConfigDisposable = null;
|
||||||
|
|
||||||
function activate(context) {
|
function activate(context) {
|
||||||
// Hover provider for mnemonics
|
// Set up initial language configuration
|
||||||
const hoverProvider = vscode.languages.registerHoverProvider('x86asm', {
|
updateLanguageConfiguration();
|
||||||
async provideHover(document, position, token) {
|
|
||||||
const range = document.getWordRangeAtPosition(position, /\b[a-zA-Z0-9_]+\b/);
|
|
||||||
const word = document.getText(range);
|
|
||||||
|
|
||||||
if (word) {
|
// Listen for configuration changes
|
||||||
// Check if the word is a valid mnemonic
|
const configChangeListener = vscode.workspace.onDidChangeConfiguration(
|
||||||
if (list.x86x64Mnemonics.includes(word.toUpperCase())) {
|
(event) => {
|
||||||
const instructionInfo = await fetchInstructionInfo(word.toLowerCase());
|
if (event.affectsConfiguration("assembly.comments")) {
|
||||||
if (instructionInfo) {
|
updateLanguageConfiguration();
|
||||||
return new vscode.Hover(instructionInfo);
|
}
|
||||||
}
|
}
|
||||||
} else {
|
);
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
// Hover provider for mnemonics
|
||||||
|
const hoverProvider = vscode.languages.registerHoverProvider("x86asm", {
|
||||||
|
async provideHover(document, position, token) {
|
||||||
|
const range = document.getWordRangeAtPosition(
|
||||||
|
position,
|
||||||
|
/\b[a-zA-Z0-9_]+\b/
|
||||||
|
);
|
||||||
|
const word = document.getText(range);
|
||||||
|
|
||||||
|
if (word) {
|
||||||
|
// Check if the word is a valid mnemonic
|
||||||
|
if (list.x86x64Mnemonics.includes(word.toUpperCase())) {
|
||||||
|
const instructionInfo = await fetchInstructionInfo(
|
||||||
|
word.toLowerCase()
|
||||||
|
);
|
||||||
|
if (instructionInfo) {
|
||||||
|
return new vscode.Hover(instructionInfo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// Definition provider (Ctrl+Click to jump)
|
return undefined;
|
||||||
const definitionProvider = vscode.languages.registerDefinitionProvider('x86asm', {
|
},
|
||||||
async provideDefinition(document, position, token) {
|
});
|
||||||
const range = document.getWordRangeAtPosition(position);
|
|
||||||
if (!range) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const word = document.getText(range);
|
// Definition provider (Ctrl+Click to jump)
|
||||||
return await findDefinition(word);
|
const definitionProvider = vscode.languages.registerDefinitionProvider(
|
||||||
|
"x86asm",
|
||||||
|
{
|
||||||
|
async provideDefinition(document, position, token) {
|
||||||
|
const range = document.getWordRangeAtPosition(position);
|
||||||
|
if (!range) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
context.subscriptions.push(hoverProvider, definitionProvider);
|
const word = document.getText(range);
|
||||||
|
return await findDefinition(word);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
context.subscriptions.push(
|
||||||
|
hoverProvider,
|
||||||
|
definitionProvider,
|
||||||
|
configChangeListener
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchInstructionInfo(instruction) {
|
async function fetchInstructionInfo(instruction) {
|
||||||
try {
|
try {
|
||||||
const url = `https://www.felixcloutier.com/x86/${instruction}`;
|
const url = `https://www.felixcloutier.com/x86/${instruction}`;
|
||||||
const response = await axios.get(url);
|
const response = await axios.get(url);
|
||||||
const $ = cheerio.load(response.data);
|
const $ = cheerio.load(response.data);
|
||||||
|
|
||||||
// Extract the title (instruction name)
|
// Extract the title (instruction name)
|
||||||
const instructionTitle = $('h1').text();
|
const instructionTitle = $("h1").text();
|
||||||
|
|
||||||
// Extract Opcode table and relevant details
|
// Extract Opcode table and relevant details
|
||||||
const opcodeTable = $('table').first();
|
const opcodeTable = $("table").first();
|
||||||
const opcode = opcodeTable.find('tr').eq(1).find('td').eq(0).text();
|
const opcode = opcodeTable.find("tr").eq(1).find("td").eq(0).text();
|
||||||
const instructionDescription = opcodeTable.find('tr').eq(1).find('td').eq(5).text();
|
const instructionDescription = opcodeTable
|
||||||
|
.find("tr")
|
||||||
|
.eq(1)
|
||||||
|
.find("td")
|
||||||
|
.eq(5)
|
||||||
|
.text();
|
||||||
|
|
||||||
// Extract the operation section
|
// Extract the operation section
|
||||||
const operationSection = $('#operation').next('pre').text();
|
const operationSection = $("#operation").next("pre").text();
|
||||||
|
|
||||||
// Extract the description section
|
// Extract the description section
|
||||||
const descriptionSection = $('#description').nextUntil('h2', 'p').text();
|
const descriptionSection = $("#description").nextUntil("h2", "p").text();
|
||||||
|
|
||||||
// Combine the extracted information into a formatted output
|
// Combine the extracted information into a formatted output
|
||||||
let hoverContent = `**${instructionTitle}**\n\n`;
|
let hoverContent = `**${instructionTitle}**\n\n`;
|
||||||
hoverContent += `**Opcode:** ${opcode}\n`;
|
hoverContent += `**Opcode:** ${opcode}\n`;
|
||||||
hoverContent += `**Description:** ${instructionDescription}\n\n`;
|
hoverContent += `**Description:** ${instructionDescription}\n\n`;
|
||||||
hoverContent += `**Details:**\n${descriptionSection}\n\n`;
|
hoverContent += `**Details:**\n${descriptionSection}\n\n`;
|
||||||
hoverContent += `**Operation:**\n${operationSection}`;
|
hoverContent += `**Operation:**\n${operationSection}`;
|
||||||
|
|
||||||
return hoverContent;
|
return hoverContent;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.status === 404) {
|
if (error.response && error.response.status === 404) {
|
||||||
console.warn(`Instruction info not found for: ${instruction}`);
|
console.warn(`Instruction info not found for: ${instruction}`);
|
||||||
} else {
|
} else {
|
||||||
console.error(`Failed to fetch instruction info: ${error.message}`);
|
console.error(`Failed to fetch instruction info: ${error.message}`);
|
||||||
}
|
|
||||||
return null; // Return null if fetching fails
|
|
||||||
}
|
}
|
||||||
|
return null; // Return null if fetching fails
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findDefinition(word) {
|
async function findDefinition(word) {
|
||||||
// Get all x86 assembly files in the workspace
|
// Get all x86 assembly files in the workspace
|
||||||
const files = await vscode.workspace.findFiles('**/*.s', '**/node_modules/**');
|
const files = await vscode.workspace.findFiles(
|
||||||
|
"**/*.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchForDefinition(lines, word, document) {
|
function searchForDefinition(lines, word, document) {
|
||||||
const externRegex = new RegExp(`^extern\\s+${word}\\s*`, 'i');
|
const externRegex = new RegExp(`^extern\\s+${word}\\s*`, "i");
|
||||||
const globalRegex = new RegExp(`^global\\s+${word}\\s*`, 'i');
|
const globalRegex = new RegExp(`^global\\s+${word}\\s*`, "i");
|
||||||
const labelRegex = new RegExp(`^${word}:`, 'i');
|
const labelRegex = new RegExp(`^${word}:`, "i");
|
||||||
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
if (externRegex.test(lines[i]) || globalRegex.test(lines[i]) || labelRegex.test(lines[i])) {
|
if (
|
||||||
return new vscode.Location(document.uri, new vscode.Position(i, 0));
|
externRegex.test(lines[i]) ||
|
||||||
}
|
globalRegex.test(lines[i]) ||
|
||||||
|
labelRegex.test(lines[i])
|
||||||
|
) {
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
function deactivate() {}
|
function deactivate() {
|
||||||
|
if (languageConfigDisposable) {
|
||||||
|
languageConfigDisposable.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
activate,
|
activate,
|
||||||
deactivate
|
deactivate,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue