before rewriting formatter
This commit is contained in:
68
README.md
68
README.md
@@ -1,71 +1,9 @@
|
||||
# format-4690 README
|
||||
|
||||
This is the README for your extension "format-4690". After writing up a brief description, we recommend including the following sections.
|
||||
|
||||
## Features
|
||||
|
||||
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
|
||||
|
||||
For example if there is an image subfolder under your extension project workspace:
|
||||
|
||||
\!\[feature X\]\(images/feature-x.png\)
|
||||
|
||||
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
|
||||
|
||||
## Requirements
|
||||
|
||||
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
|
||||
|
||||
## Extension Settings
|
||||
|
||||
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
|
||||
|
||||
For example:
|
||||
|
||||
This extension contributes the following settings:
|
||||
|
||||
* `myExtension.enable`: Enable/disable this extension.
|
||||
* `myExtension.thing`: Set to `blah` to do something.
|
||||
|
||||
## Known Issues
|
||||
|
||||
Calling out known issues can help limit users opening duplicate issues against your extension.
|
||||
|
||||
## Release Notes
|
||||
|
||||
Users appreciate release notes as you update your extension.
|
||||
|
||||
### 1.0.0
|
||||
|
||||
Initial release of ...
|
||||
|
||||
### 1.0.1
|
||||
|
||||
Fixed issue #.
|
||||
|
||||
### 1.1.0
|
||||
|
||||
Added features X, Y, and Z.
|
||||
Hola
|
||||
|
||||
---
|
||||
|
||||
## Following extension guidelines
|
||||
### 2025.06.01
|
||||
|
||||
Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension.
|
||||
|
||||
* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
|
||||
|
||||
## Working with Markdown
|
||||
|
||||
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
|
||||
|
||||
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux).
|
||||
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux).
|
||||
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets.
|
||||
|
||||
## For more information
|
||||
|
||||
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
|
||||
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
|
||||
|
||||
**Enjoy!**
|
||||
Inicial
|
||||
|
||||
@@ -23,5 +23,6 @@
|
||||
["(", ")"],
|
||||
["\"", "\""],
|
||||
["'", "'"]
|
||||
]
|
||||
],
|
||||
"wordPattern": "(\\?|[a-zA-Z])([a-zA-Z0-9#\\.]*)[$#%]?"
|
||||
}
|
||||
612
src/extension.ts
612
src/extension.ts
@@ -4,12 +4,42 @@ interface FunctionDefinition {
|
||||
name: string;
|
||||
location: vscode.Location;
|
||||
type: 'FUNCTION' | 'SUB' | 'DEF';
|
||||
parameters: string[]; // Array of parameter names
|
||||
parameterCount: number; // Number of parameters
|
||||
}
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
// Global symbol index - maps lowercase function names to their definitions
|
||||
const symbolIndex = new Map<string, FunctionDefinition[]>();
|
||||
|
||||
// File index - maps file URIs to their function definitions
|
||||
const fileIndex = new Map<string, FunctionDefinition[]>();
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
const selector: vscode.DocumentSelector = { language: '4690basic' };
|
||||
|
||||
// Existing formatter provider
|
||||
const saveWatcher = vscode.workspace.onDidSaveTextDocument(async (document) => {
|
||||
if (document.languageId === '4690basic') {
|
||||
console.log(`File saved: ${document.uri.toString()}`);
|
||||
await updateIndexForFile(document.uri);
|
||||
}
|
||||
});
|
||||
|
||||
const fsWatcher = vscode.workspace.createFileSystemWatcher('**/*.{bas,BAS,j86,J86}');
|
||||
|
||||
fsWatcher.onDidCreate(async (uri) => {
|
||||
console.log(`File created: ${uri.toString()}`);
|
||||
await updateIndexForFile(uri);
|
||||
});
|
||||
|
||||
fsWatcher.onDidDelete((uri) => {
|
||||
console.log(`File deleted: ${uri.toString()}`);
|
||||
removeFromIndex(uri);
|
||||
});
|
||||
|
||||
// Build initial symbol index
|
||||
await buildInitialSymbolIndex();
|
||||
|
||||
// Existing formatter provider (unchanged)
|
||||
const formatterProvider: vscode.DocumentFormattingEditProvider = {
|
||||
provideDocumentFormattingEdits(document: vscode.TextDocument): vscode.TextEdit[] {
|
||||
const config = vscode.workspace.getConfiguration('4690basic.format');
|
||||
@@ -26,7 +56,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
function removeComments(line: string): string {
|
||||
let inQuotes = false;
|
||||
let quoteChar = '';
|
||||
|
||||
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const char = line[i];
|
||||
if (!inQuotes && (char === '"' || char === "'")) {
|
||||
@@ -44,20 +74,38 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Helper function to check if a line should continue
|
||||
function shouldContinue(line: string, allLines: string[], currentIndex: number): boolean {
|
||||
const trimmedLine = line.trim();
|
||||
|
||||
// Skip comment lines that start with backslash (like \REM!!)
|
||||
// These should not be treated as continuation lines
|
||||
if (/^\s*\\(REM|rem)/i.test(trimmedLine)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const withoutComments = removeComments(line).trim();
|
||||
|
||||
|
||||
// Check for explicit continuation with \
|
||||
if (withoutComments.endsWith('\\')) {
|
||||
if (/^(?:[^"\\]|"[^"]*")*\\/.test(withoutComments)) {
|
||||
// Special case: if this is a THEN \ line, don't continue
|
||||
// Let the next line be processed as its own logical group
|
||||
if (/\bTHEN\s*\\/.test(withoutComments)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Check for IF without THEN on the same line
|
||||
if (/^\s*IF\b/i.test(withoutComments) && !/\bTHEN\b/i.test(withoutComments)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Check if current line looks like a continuation of a condition
|
||||
if (/^\s*(AND\b|OR\b|NOT\b|\()/i.test(withoutComments) && currentIndex > 0) {
|
||||
// BUT: if this line contains THEN, it terminates the condition, so it should NOT continue
|
||||
if (/\bTHEN\b/i.test(withoutComments)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look back to see if we're in a continuation chain
|
||||
let prevIndex = currentIndex - 1;
|
||||
while (prevIndex >= 0) {
|
||||
@@ -66,22 +114,22 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
prevIndex--;
|
||||
continue;
|
||||
}
|
||||
if (prevLine.endsWith('\\') ||
|
||||
/^\s*IF\b/i.test(prevLine) ||
|
||||
if (/\\.*$/.test(prevLine) ||
|
||||
/^\s*IF\b/i.test(prevLine) ||
|
||||
/^\s*(AND\b|OR\b|NOT\b|\()/i.test(prevLine)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
while (i < lines.length) {
|
||||
const originalLine = lines[i];
|
||||
const trimmedLine = originalLine.trim();
|
||||
|
||||
|
||||
// Skip empty lines
|
||||
if (trimmedLine === '') {
|
||||
i++;
|
||||
@@ -91,7 +139,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
// Collect continuation lines
|
||||
let continuationLines = [originalLine];
|
||||
let j = i;
|
||||
|
||||
|
||||
while (j < lines.length && shouldContinue(lines[j], lines, j)) {
|
||||
if (j + 1 < lines.length) {
|
||||
j++;
|
||||
@@ -113,20 +161,40 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
logicalParts.push(part);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const fullLogical = logicalParts.join(' ').trim();
|
||||
const firstLineTrimmed = removeComments(continuationLines[0]).trim();
|
||||
|
||||
// Check if this line follows a THEN \ continuation
|
||||
const isPrevThenContinuation = i > 0 && /\bTHEN\s*\\/.test(removeComments(lines[i - 1]));
|
||||
|
||||
// Check if this is a THEN continuation that starts a new block
|
||||
const isThenContinuation = /\bTHEN\s*\\/.test(removeComments(continuationLines[0]));
|
||||
let thenBlockStarts = false;
|
||||
|
||||
if (isThenContinuation && continuationLines.length > 1) {
|
||||
// Check if the continuation contains an opening construct
|
||||
for (let k = 1; k < continuationLines.length; k++) {
|
||||
const contLine = removeComments(continuationLines[k]).trim();
|
||||
if (/^\s*(FUNCTION|DEF|SUB|WHILE|FOR|IF|BEGIN)\b/i.test(contLine)) {
|
||||
thenBlockStarts = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple approach: look for keywords that affect indentation
|
||||
const containsBegin = /\bBEGIN\b/i.test(fullLogical);
|
||||
const containsNext = /\bNEXT\b/i.test(fullLogical);
|
||||
|
||||
const isClosing = /^\s*(END FUNCTION|FEND|END SUB|ENDIF|WEND|NEXT)\b/i.test(firstLineTrimmed) ||
|
||||
const containsNext = /^\s*NEXT\b/i.test(firstLineTrimmed);
|
||||
|
||||
const isClosing = /^\s*(END\s+FUNCTION|FEND|END\s+SUB|ENDIF|WEND|NEXT)\b/i.test(firstLineTrimmed) ||
|
||||
containsNext ||
|
||||
(/^\s*ELSE\b/i.test(firstLineTrimmed) && !containsBegin);
|
||||
|
||||
const isOpening = /^\s*(FUNCTION|DEF|SUB|WHILE|FOR)\b/i.test(fullLogical) ||
|
||||
containsBegin;
|
||||
/^\s*(FUNCTION|DEF|SUB|WHILE|FOR)\b/i.test(firstLineTrimmed) ||
|
||||
containsBegin ||
|
||||
thenBlockStarts;
|
||||
|
||||
// Handle compound statements like ENDIF ELSE BEGIN
|
||||
const isCompoundEndifElse = /\bENDIF\b.*\bELSE\s+BEGIN\b/i.test(fullLogical);
|
||||
@@ -147,7 +215,25 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
if (trimmed === '') continue;
|
||||
|
||||
const indent = indentUnit.repeat(indentLevel);
|
||||
// For continuation lines (k > 0), use appropriate indentation
|
||||
let lineIndentLevel = indentLevel;
|
||||
|
||||
if (isPrevThenContinuation) {
|
||||
// This line follows a THEN \ - it should be indented
|
||||
lineIndentLevel = indentLevel + 1;
|
||||
} else if (k > 0 && isThenContinuation) {
|
||||
// This is a continuation after THEN - it should be indented
|
||||
lineIndentLevel = indentLevel + 1;
|
||||
} else if (k > 0) {
|
||||
// Regular continuation line - check if the previous line ended with \
|
||||
const prevLine = removeComments(continuationLines[k - 1]).trim();
|
||||
if (prevLine.endsWith('\\')) {
|
||||
// Keep the same indentation as the main statement
|
||||
lineIndentLevel = indentLevel;
|
||||
}
|
||||
}
|
||||
|
||||
const indent = indentUnit.repeat(lineIndentLevel);
|
||||
const formatted = indent + trimmed;
|
||||
|
||||
if (formatted !== original) {
|
||||
@@ -181,7 +267,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
function removeComments(line: string): string {
|
||||
let inQuotes = false;
|
||||
let quoteChar = '';
|
||||
|
||||
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const char = line[i];
|
||||
if (!inQuotes && (char === '"' || char === "'")) {
|
||||
@@ -200,12 +286,12 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
// Helper function to check if a line should continue
|
||||
function shouldContinue(line: string, allLines: string[], currentIndex: number): boolean {
|
||||
const withoutComments = removeComments(line).trim();
|
||||
|
||||
|
||||
// Check for explicit continuation with \
|
||||
if (withoutComments.endsWith('\\')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// For function definitions, also check if we have incomplete parentheses
|
||||
if (/^\s*(FUNCTION|DEF|SUB)\b/i.test(withoutComments)) {
|
||||
const openParens = (withoutComments.match(/\(/g) || []).length;
|
||||
@@ -214,15 +300,38 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper function to parse parameters from a parameter string
|
||||
function parseParameters(paramString: string): string[] {
|
||||
if (!paramString.trim()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parameters: string[] = [];
|
||||
const parts = paramString.split(',');
|
||||
|
||||
for (const part of parts) {
|
||||
const trimmedPart = part.trim();
|
||||
if (trimmedPart) {
|
||||
// Extract parameter name using the identifier regex
|
||||
const match = identifierRegex.exec(trimmedPart);
|
||||
if (match) {
|
||||
parameters.push(match[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
while (i < lines.length) {
|
||||
const originalLine = lines[i];
|
||||
const trimmedLine = originalLine.trim();
|
||||
|
||||
|
||||
// Skip empty lines
|
||||
if (trimmedLine === '') {
|
||||
i++;
|
||||
@@ -239,7 +348,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
// Collect continuation lines for this function definition
|
||||
let continuationLines = [originalLine];
|
||||
let j = i;
|
||||
|
||||
|
||||
while (j < lines.length && shouldContinue(lines[j], lines, j)) {
|
||||
if (j + 1 < lines.length) {
|
||||
j++;
|
||||
@@ -261,27 +370,41 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
logicalParts.push(part);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const fullLogical = logicalParts.join(' ').trim();
|
||||
|
||||
|
||||
// Check if this is not an external declaration
|
||||
if (!/\bEXTERNAL\s*$/i.test(fullLogical)) {
|
||||
// Extract the function type and name
|
||||
const defType = functionMatch[1].toUpperCase() as 'FUNCTION' | 'SUB' | 'DEF';
|
||||
|
||||
|
||||
// Find the identifier after the function keyword
|
||||
const afterKeyword = fullLogical.substring(functionMatch[0].length).trim();
|
||||
const nameMatch = identifierRegex.exec(afterKeyword);
|
||||
|
||||
|
||||
if (nameMatch) {
|
||||
const functionName = nameMatch[0];
|
||||
const position = new vscode.Position(i, originalLine.indexOf(functionName));
|
||||
const location = new vscode.Location(document.uri, position);
|
||||
|
||||
|
||||
// Extract parameters
|
||||
let parameters: string[] = [];
|
||||
const afterName = afterKeyword.substring(nameMatch[0].length).trim();
|
||||
|
||||
// Check if there are parentheses after the function name
|
||||
const parenMatch = /^\s*\(\s*(.*?)\s*\)/.exec(afterName);
|
||||
if (parenMatch) {
|
||||
// Extract parameter string and parse it
|
||||
const paramString = parenMatch[1];
|
||||
parameters = parseParameters(paramString);
|
||||
}
|
||||
|
||||
definitions.push({
|
||||
name: functionName,
|
||||
location: location,
|
||||
type: defType
|
||||
type: defType,
|
||||
parameters: parameters,
|
||||
parameterCount: parameters.length
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -293,7 +416,84 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
return definitions;
|
||||
}
|
||||
|
||||
// Definition provider - searches all files in workspace
|
||||
// Function to build the initial symbol index
|
||||
async function buildInitialSymbolIndex(): Promise<void> {
|
||||
try {
|
||||
console.log('Building symbol index...');
|
||||
const workspaceFiles = await vscode.workspace.findFiles('**/*.{bas,BAS,j86,J86}');
|
||||
|
||||
for (const fileUri of workspaceFiles) {
|
||||
try {
|
||||
await updateIndexForFile(fileUri);
|
||||
} catch (error) {
|
||||
console.warn(`Failed to index file ${fileUri.toString()}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Symbol index built with ${symbolIndex.size} unique symbols across ${fileIndex.size} files`);
|
||||
} catch (error) {
|
||||
console.error('Failed to build initial symbol index:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update the index for a specific file
|
||||
async function updateIndexForFile(fileUri: vscode.Uri): Promise<void> {
|
||||
try {
|
||||
const document = await vscode.workspace.openTextDocument(fileUri);
|
||||
const definitions = parseFunctionDefinitions(document);
|
||||
const fileKey = fileUri.toString();
|
||||
|
||||
// Remove old definitions from the global symbol index
|
||||
const oldDefinitions = fileIndex.get(fileKey) || [];
|
||||
for (const oldDef of oldDefinitions) {
|
||||
const symbolKey = oldDef.name.toLowerCase();
|
||||
const symbolDefs = symbolIndex.get(symbolKey) || [];
|
||||
const filteredDefs = symbolDefs.filter(def => def.location.uri.toString() !== fileKey);
|
||||
|
||||
if (filteredDefs.length === 0) {
|
||||
symbolIndex.delete(symbolKey);
|
||||
} else {
|
||||
symbolIndex.set(symbolKey, filteredDefs);
|
||||
}
|
||||
}
|
||||
|
||||
// Add new definitions to the indexes
|
||||
fileIndex.set(fileKey, definitions);
|
||||
|
||||
for (const definition of definitions) {
|
||||
const symbolKey = definition.name.toLowerCase();
|
||||
const existing = symbolIndex.get(symbolKey) || [];
|
||||
existing.push(definition);
|
||||
symbolIndex.set(symbolKey, existing);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Failed to update index for file ${fileUri.toString()}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to remove a file from the index
|
||||
function removeFromIndex(fileUri: vscode.Uri): void {
|
||||
const fileKey = fileUri.toString();
|
||||
const definitions = fileIndex.get(fileKey) || [];
|
||||
|
||||
// Remove from symbol index
|
||||
for (const definition of definitions) {
|
||||
const symbolKey = definition.name.toLowerCase();
|
||||
const symbolDefs = symbolIndex.get(symbolKey) || [];
|
||||
const filteredDefs = symbolDefs.filter(def => def.location.uri.toString() !== fileKey);
|
||||
|
||||
if (filteredDefs.length === 0) {
|
||||
symbolIndex.delete(symbolKey);
|
||||
} else {
|
||||
symbolIndex.set(symbolKey, filteredDefs);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from file index
|
||||
fileIndex.delete(fileKey);
|
||||
}
|
||||
|
||||
// Optimized definition provider - uses the symbol index
|
||||
const definitionProvider: vscode.DefinitionProvider = {
|
||||
async provideDefinition(
|
||||
document: vscode.TextDocument,
|
||||
@@ -305,66 +505,44 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const word = document.getText(wordRange);
|
||||
|
||||
// Search in current document first
|
||||
const currentDocDefs = parseFunctionDefinitions(document);
|
||||
const localDef = currentDocDefs.find(def => def.name.toLowerCase() === word.toLowerCase());
|
||||
const word = document.getText(wordRange).toLowerCase();
|
||||
const definitions = symbolIndex.get(word);
|
||||
|
||||
if (!definitions || definitions.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If multiple definitions exist, prefer the one in the current document
|
||||
const localDef = definitions.find(def => def.location.uri.toString() === document.uri.toString());
|
||||
if (localDef) {
|
||||
return localDef.location;
|
||||
}
|
||||
|
||||
// Search in all workspace files
|
||||
const workspaceFiles = await vscode.workspace.findFiles('**/*.{bas,BAS,j86,J86}');
|
||||
|
||||
for (const fileUri of workspaceFiles) {
|
||||
if (fileUri.toString() === document.uri.toString()) {
|
||||
continue; // Skip current document as we already searched it
|
||||
}
|
||||
|
||||
try {
|
||||
const doc = await vscode.workspace.openTextDocument(fileUri);
|
||||
const definitions = parseFunctionDefinitions(doc);
|
||||
const definition = definitions.find(def => def.name.toLowerCase() === word.toLowerCase());
|
||||
|
||||
if (definition) {
|
||||
return definition.location;
|
||||
}
|
||||
} catch (error) {
|
||||
// Skip files that can't be opened
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
// Otherwise return the first definition found
|
||||
return definitions[0].location;
|
||||
}
|
||||
};
|
||||
|
||||
// Workspace symbol provider - only searches open documents
|
||||
// Updated workspace symbol provider - uses the symbol index
|
||||
const workspaceSymbolProvider: vscode.WorkspaceSymbolProvider = {
|
||||
async provideWorkspaceSymbols(
|
||||
query: string,
|
||||
token: vscode.CancellationToken
|
||||
): Promise<vscode.SymbolInformation[]> {
|
||||
const symbols: vscode.SymbolInformation[] = [];
|
||||
|
||||
// Only search in currently open documents
|
||||
for (const document of vscode.workspace.textDocuments) {
|
||||
// Only search in files with our language ID
|
||||
if (document.languageId === '4690basic') {
|
||||
const definitions = parseFunctionDefinitions(document);
|
||||
|
||||
const queryLower = query.toLowerCase();
|
||||
|
||||
for (const [symbolName, definitions] of symbolIndex) {
|
||||
if (!query || symbolName.includes(queryLower)) {
|
||||
for (const def of definitions) {
|
||||
if (!query || def.name.toLowerCase().includes(query.toLowerCase())) {
|
||||
const symbolKind = def.type === 'SUB' ? vscode.SymbolKind.Method : vscode.SymbolKind.Function;
|
||||
const symbol = new vscode.SymbolInformation(
|
||||
def.name,
|
||||
symbolKind,
|
||||
'',
|
||||
def.location
|
||||
);
|
||||
symbols.push(symbol);
|
||||
}
|
||||
const symbolKind = def.type === 'SUB' ? vscode.SymbolKind.Method : vscode.SymbolKind.Function;
|
||||
const symbol = new vscode.SymbolInformation(
|
||||
def.name,
|
||||
symbolKind,
|
||||
'',
|
||||
def.location
|
||||
);
|
||||
symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,34 +551,214 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
};
|
||||
|
||||
// Document symbol provider (for outline view)
|
||||
// Enhanced Document Symbol Provider that provides hierarchical symbols for breadcrumbs
|
||||
const documentSymbolProvider: vscode.DocumentSymbolProvider = {
|
||||
provideDocumentSymbols(
|
||||
document: vscode.TextDocument,
|
||||
token: vscode.CancellationToken
|
||||
): vscode.DocumentSymbol[] {
|
||||
const definitions = parseFunctionDefinitions(document);
|
||||
const symbols: vscode.DocumentSymbol[] = [];
|
||||
|
||||
for (const def of definitions) {
|
||||
const symbolKind = def.type === 'SUB' ? vscode.SymbolKind.Method : vscode.SymbolKind.Function;
|
||||
const range = new vscode.Range(def.location.range.start, def.location.range.start);
|
||||
|
||||
const symbol = new vscode.DocumentSymbol(
|
||||
def.name,
|
||||
def.type,
|
||||
symbolKind,
|
||||
range,
|
||||
range
|
||||
);
|
||||
symbols.push(symbol);
|
||||
}
|
||||
|
||||
return symbols;
|
||||
return parseDocumentSymbolsWithRanges(document);
|
||||
}
|
||||
};
|
||||
|
||||
// Hover provider to help VS Code recognize symbols and show proper highlighting
|
||||
// Function to parse document symbols with proper ranges for breadcrumbs
|
||||
function parseDocumentSymbolsWithRanges(document: vscode.TextDocument): vscode.DocumentSymbol[] {
|
||||
const symbols: vscode.DocumentSymbol[] = [];
|
||||
const lines = document.getText().split('\n');
|
||||
const identifierRegex = /(\?|[a-zA-Z])([a-zA-Z0-9#\.]*)[\$#%]?/;
|
||||
|
||||
// Helper function to check if a keyword appears after a backslash or comment marker
|
||||
function isKeywordCommentedOut(line: string, keywordMatch: RegExpExecArray): boolean {
|
||||
const keywordStart = keywordMatch.index!;
|
||||
let inQuotes = false;
|
||||
|
||||
for (let i = 0; i < keywordStart; i++) {
|
||||
const char = line[i];
|
||||
if (!inQuotes && char === '"') {
|
||||
inQuotes = true;
|
||||
} else if (inQuotes && char === '"') {
|
||||
inQuotes = false;
|
||||
} else if (!inQuotes && (char === '\\' || char === '!')) {
|
||||
// Found a comment marker before the keyword, so keyword is commented out
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper function to parse parameters from a parameter string
|
||||
function parseParameters(paramString: string): string[] {
|
||||
if (!paramString.trim()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parameters: string[] = [];
|
||||
const parts = paramString.split(',');
|
||||
|
||||
for (const part of parts) {
|
||||
const trimmedPart = part.trim();
|
||||
if (trimmedPart) {
|
||||
// Extract parameter name using the identifier regex
|
||||
const match = identifierRegex.exec(trimmedPart);
|
||||
if (match) {
|
||||
parameters.push(match[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Find the end of a function/subroutine starting from a given line
|
||||
function findFunctionEnd(startLine: number, functionType: 'FUNCTION' | 'DEF' | 'SUB'): number {
|
||||
let endPattern: RegExp;
|
||||
|
||||
// console.log('functionType: ', functionType);
|
||||
|
||||
if (functionType === 'FUNCTION' || functionType === 'DEF') {
|
||||
endPattern = /^\s*(END\s+FUNCTION)|(FEND)\b/i;
|
||||
} else { // SUB
|
||||
endPattern = /^\s*END\s+SUB\b/i;
|
||||
}
|
||||
|
||||
// console.log('endPattern: ', endPattern);
|
||||
|
||||
for (let i = startLine + 1; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
|
||||
// Skip commented lines
|
||||
if (/^\s*(!|\\)/.test(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip empty lines
|
||||
if (line.trim() === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// console.log('Evaluating for end: ', line);
|
||||
|
||||
// Check if this line matches the end pattern
|
||||
const endMatch = endPattern.exec(line);
|
||||
if (endMatch) {
|
||||
|
||||
// console.log('Found match: ', endMatch);
|
||||
|
||||
// Check if the end keyword is not commented out
|
||||
if (!isKeywordCommentedOut(line, endMatch)) {
|
||||
// console.log('Returning i');
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no end found, return the last line of the document
|
||||
return lines.length - 1;
|
||||
}
|
||||
|
||||
// Process each line looking for function/sub definitions
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
const trimmedLine = line.trim();
|
||||
|
||||
|
||||
// Skip empty lines
|
||||
if (trimmedLine === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip commented lines
|
||||
if (/^\s*(!|\\)/.test(trimmedLine)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this line starts a function definition
|
||||
const functionMatch = /^\s*(FUNCTION|DEF|SUB)\s+/i.exec(line);
|
||||
if (!functionMatch) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if the function keyword is commented out
|
||||
if (isKeywordCommentedOut(line, functionMatch)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// console.log('Current line: ', trimmedLine);
|
||||
|
||||
// Extract the function type and name
|
||||
const defType = functionMatch[1].toUpperCase() as 'FUNCTION' | 'SUB' | 'DEF';
|
||||
|
||||
// console.log('functionMatch: ', functionMatch);
|
||||
// console.log('Definition type: ', defType);
|
||||
|
||||
// Find the identifier after the function keyword
|
||||
const afterKeyword = line.substring(functionMatch[0].length).trim();
|
||||
const nameMatch = identifierRegex.exec(afterKeyword);
|
||||
|
||||
// console.log('afterKeyword: ', afterKeyword);
|
||||
// console.log('nameMatch: ', nameMatch);
|
||||
|
||||
if (!nameMatch) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this is not an external declaration
|
||||
if (/\bEXTERNAL\s*.*$/i.test(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const functionName = nameMatch[0];
|
||||
const startPosition = new vscode.Position(i, line.indexOf(functionMatch[1]));
|
||||
|
||||
// Find the end of this function
|
||||
const endLineIndex = findFunctionEnd(i, defType);
|
||||
const endPosition = new vscode.Position(endLineIndex, lines[endLineIndex].length);
|
||||
|
||||
// Create the full range for the function
|
||||
const fullRange = new vscode.Range(startPosition, endPosition);
|
||||
|
||||
// Create a selection range (just the function name)
|
||||
const nameStartCol = line.indexOf(functionName);
|
||||
const namePosition = new vscode.Position(i, nameStartCol);
|
||||
const nameEndPosition = new vscode.Position(i, nameStartCol + functionName.length);
|
||||
const selectionRange = new vscode.Range(namePosition, nameEndPosition);
|
||||
|
||||
// Extract parameters
|
||||
let parameters: string[] = [];
|
||||
const afterName = afterKeyword.substring(nameMatch[0].length).trim();
|
||||
|
||||
// Check if there are parentheses after the function name
|
||||
const parenMatch = /^\s*\(\s*(.*?)\s*\)/.exec(afterName);
|
||||
if (parenMatch) {
|
||||
// Extract parameter string and parse it
|
||||
const paramString = parenMatch[1];
|
||||
parameters = parseParameters(paramString);
|
||||
}
|
||||
|
||||
// Create symbol kind
|
||||
const symbolKind = defType === 'SUB' ? vscode.SymbolKind.Method : vscode.SymbolKind.Function;
|
||||
|
||||
// Create detail string with parameters
|
||||
let detail = defType;
|
||||
if (parameters.length > 0) {
|
||||
detail += `(${parameters.join(', ')})`;
|
||||
}
|
||||
|
||||
const symbol = new vscode.DocumentSymbol(
|
||||
functionName,
|
||||
detail,
|
||||
symbolKind,
|
||||
fullRange,
|
||||
selectionRange
|
||||
);
|
||||
|
||||
symbols.push(symbol);
|
||||
}
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
||||
// Updated hover provider - now shows parameter information
|
||||
const hoverProvider: vscode.HoverProvider = {
|
||||
provideHover(
|
||||
document: vscode.TextDocument,
|
||||
@@ -412,40 +770,30 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const word = document.getText(wordRange);
|
||||
|
||||
// Search for the function definition in current document
|
||||
const currentDocDefs = parseFunctionDefinitions(document);
|
||||
let definition = currentDocDefs.find(def => def.name.toLowerCase() === word.toLowerCase());
|
||||
|
||||
// If not found locally, search in open documents
|
||||
if (!definition) {
|
||||
for (const openDoc of vscode.workspace.textDocuments) {
|
||||
if (openDoc.uri.toString() === document.uri.toString()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (openDoc.languageId === '4690basic') {
|
||||
const definitions = parseFunctionDefinitions(openDoc);
|
||||
definition = definitions.find(def => def.name.toLowerCase() === word.toLowerCase());
|
||||
|
||||
if (definition) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const word = document.getText(wordRange).toLowerCase();
|
||||
const definitions = symbolIndex.get(word);
|
||||
|
||||
if (!definitions || definitions.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (definition) {
|
||||
const typeLabel = definition.type === 'SUB' ? 'Subroutine' : 'Function';
|
||||
const content = new vscode.MarkdownString();
|
||||
content.appendCodeblock(`${definition.type} ${definition.name}`, '4690basic');
|
||||
content.appendText(`\n${typeLabel}: ${definition.name}`);
|
||||
|
||||
return new vscode.Hover(content, wordRange);
|
||||
// Prefer definition from current document, otherwise use first one
|
||||
const definition = definitions.find(def => def.location.uri.toString() === document.uri.toString()) || definitions[0];
|
||||
|
||||
const content = new vscode.MarkdownString();
|
||||
|
||||
// Build function signature with parameters
|
||||
let signature = `${definition.type} ${definition.name}`;
|
||||
if (definition.parameterCount > 0) {
|
||||
signature += `(${definition.parameters.join(', ')})`;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
content.appendCodeblock(signature, '4690basic');
|
||||
|
||||
const path = vscode.workspace.name ? definition.location.uri.path.slice(definition.location.uri.path.indexOf(vscode.workspace.name)) : 'Archivo fuente no encontrado';
|
||||
content.appendMarkdown(`***\n\`${path}\``);
|
||||
|
||||
return new vscode.Hover(content, wordRange);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -455,8 +803,14 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
vscode.languages.registerDefinitionProvider(selector, definitionProvider),
|
||||
vscode.languages.registerWorkspaceSymbolProvider(workspaceSymbolProvider),
|
||||
vscode.languages.registerDocumentSymbolProvider(selector, documentSymbolProvider),
|
||||
vscode.languages.registerHoverProvider(selector, hoverProvider)
|
||||
vscode.languages.registerHoverProvider(selector, hoverProvider),
|
||||
saveWatcher,
|
||||
fsWatcher
|
||||
);
|
||||
}
|
||||
|
||||
export function deactivate() {}
|
||||
export function deactivate() {
|
||||
// Clear the indexes on deactivation
|
||||
symbolIndex.clear();
|
||||
fileIndex.clear();
|
||||
}
|
||||
@@ -3,23 +3,15 @@
|
||||
"name": "4690 BASIC",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "string.quoted.double",
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"patterns": [
|
||||
{
|
||||
"match": ".",
|
||||
"name": "string.quoted.double"
|
||||
}
|
||||
]
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
},
|
||||
{
|
||||
"name": "string.regexp",
|
||||
"match": "\\b[\\w\\.]+:"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"include": "#function-decl"
|
||||
},
|
||||
@@ -44,12 +36,6 @@
|
||||
{
|
||||
"include": "#math-function"
|
||||
},
|
||||
{
|
||||
"include": "#string-function"
|
||||
},
|
||||
{
|
||||
"include": "#variable-assignment"
|
||||
},
|
||||
{
|
||||
"include": "#if-statement"
|
||||
},
|
||||
@@ -74,9 +60,6 @@
|
||||
{
|
||||
"include": "#keywords"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
},
|
||||
{
|
||||
"include": "#stmt-w-parameters"
|
||||
},
|
||||
@@ -98,11 +81,27 @@
|
||||
{
|
||||
"include": "#number-literal"
|
||||
},
|
||||
{
|
||||
"include": "#string-function"
|
||||
},
|
||||
{
|
||||
"include": "#identifier"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.line",
|
||||
"match": "!.*|\\bREM.*|\\bREMARK.*"
|
||||
}
|
||||
]
|
||||
},
|
||||
"strings": {
|
||||
"name": "string.quoted.double",
|
||||
"begin": "\"",
|
||||
"end": "\""
|
||||
},
|
||||
"line-continuation": {
|
||||
"name": "meta.line.continuation",
|
||||
"match": "\\\\(.*)\\n",
|
||||
@@ -112,14 +111,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.line",
|
||||
"match": "!.*|REM.*|REMARK.*"
|
||||
}
|
||||
]
|
||||
},
|
||||
"function-decl": {
|
||||
"name": "meta.function",
|
||||
"begin": "(?i)\\b(FUNCTION|DEF)\\s+((\\?|[a-zA-Z])([a-zA-Z0-9#.]*)[\\$#%]?)",
|
||||
@@ -184,7 +175,7 @@
|
||||
},
|
||||
"subroutine-end": {
|
||||
"name": "keyword.control",
|
||||
"match": "END SUB|end sub"
|
||||
"match": "(?i)END\\s+SUB"
|
||||
},
|
||||
"integer-decl": {
|
||||
"begin": "(INTEGER|integer)((\\*)(1|2|4))?",
|
||||
@@ -206,7 +197,7 @@
|
||||
},
|
||||
{
|
||||
"name": "entity.name.function",
|
||||
"match": "(\\?|[a-zA-Z])([a-zA-Z0-9#.]*)([\\$#%])?",
|
||||
"match": "(\\?|[a-zA-Z])([a-zA-Z0-9#\\.]*)([\\$#%])?",
|
||||
"captures": {
|
||||
"3": {
|
||||
"name": "keyword.operator"
|
||||
@@ -283,7 +274,7 @@
|
||||
}
|
||||
},
|
||||
"real-decl": {
|
||||
"begin": "REAL|real",
|
||||
"begin": "(?i)REAL\\s+",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "storage.type"
|
||||
@@ -365,25 +356,7 @@
|
||||
},
|
||||
"math-function": {
|
||||
"name": "support.function.arithmetic",
|
||||
"match": "(?i)\\b(ABS|CHR\\$|FLOAT|INT%?|MOD|PEEK|SGN|SHIFT|STR\\$|TAB)\\b[^%\\$\\.]"
|
||||
},
|
||||
"variable-assignment": {
|
||||
"name": "meta.assignment",
|
||||
"match": "^\\s*(\\?|[a-zA-Z])([a-zA-Z0-9#.]*)([\\$#%])?\\s+(=)",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "variable.name"
|
||||
},
|
||||
"2": {
|
||||
"name": "variable.name"
|
||||
},
|
||||
"3": {
|
||||
"name": "keyword.operator"
|
||||
},
|
||||
"4": {
|
||||
"name": "keyword.operator.arithmetic"
|
||||
}
|
||||
}
|
||||
"match": "(?i)\\b(ABS|CHR\\$|FLOAT|INT%?|MOD|PEEK|SGN|SHIFT|STR\\$|TAB)(?=\\s*\\()"
|
||||
},
|
||||
"numeric-expression": {
|
||||
"name": "meta.expression.numeric",
|
||||
@@ -405,24 +378,28 @@
|
||||
]
|
||||
},
|
||||
"identifier": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "variable.name",
|
||||
"match": "\\b(\\?|[a-zA-Z])([a-zA-Z0-9#.]*)[\\$#%]?\\b"
|
||||
"name": "meta.identifier",
|
||||
"match": "((\\?|[a-zA-Z])([a-zA-Z0-9#\\.]*))([\\$#%])?",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "variable.name"
|
||||
},
|
||||
"4": {
|
||||
"name": "keyword.operator"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"number-literal": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.numeric",
|
||||
"match": "(?i)\\b([+-]?[0-9.]+)(E[+-]?[0-9]+)?[hb]?\\b"
|
||||
"match": "(?i)\\b([+-]?[0-9\\.ABCDEF]+)(E[+-]?[0-9]+)?[HB]?\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arithmetic-operator": {
|
||||
"name": "keyword.operator.arithmetic",
|
||||
"match": "[\\+-\\/\\^\\*]"
|
||||
"match": "[\\+-\\/\\^\\*#]"
|
||||
},
|
||||
"relational-operator": {
|
||||
"name": "keyword.operator.relational",
|
||||
@@ -430,27 +407,17 @@
|
||||
},
|
||||
"logical-operator": {
|
||||
"name": "keyword.operator.logical",
|
||||
"match": "\\b(NOT|AND|OR|XOR)\\b"
|
||||
"match": "(?i)\\b(NOT|AND|OR|XOR)\\b"
|
||||
},
|
||||
"string-operator": {
|
||||
"name": "keyword.operator",
|
||||
"match": "[+]"
|
||||
},
|
||||
"string-function": {
|
||||
"begin": "(?i)\\b(ASC|LEN|PACK\\$|TRANSLATE\\$|UCASE\\$|UNPACK\\$|VAL|MID\\$|LEFT\\$|RIGHT\\$|MATCH)\\b",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "support.function.string"
|
||||
},
|
||||
"0": {
|
||||
"name": "meta.function-call.begin"
|
||||
}
|
||||
},
|
||||
"end": "\\(",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.parameters.start"
|
||||
}
|
||||
"name": "support.function.builtin",
|
||||
"match": "(?i)\\b(ASC|LEN|PACK\\$|TRANSLATE\\$|UCASE\\$|UNPACK\\$|VAL|MID\\$|LEFT\\$|RIGHT\\$|MATCH|SUBSTR|STRING\\$)(?=\\s*\\()",
|
||||
"captures": {
|
||||
"1": { "name": "support.function.builtin"}
|
||||
}
|
||||
},
|
||||
"string-expression": {
|
||||
@@ -542,7 +509,7 @@
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.control",
|
||||
"match": "(?i)\\b(GOSUB|RETURN|GOTO|WHILE|WEND|NEXT|ON|ERROR|STOP|RANDOMIZE|CHAIN|COMMON|CALL|EXIT SUB|FORM)\\b[^%\\$\\.]"
|
||||
"match": "(?i)\\b(GOSUB|RETURN|GOTO|WHILE|WEND|NEXT|ON|ERROR|STOP|RANDOMIZE|CHAIN|COMMON|CALL|EXIT\\s+SUB|EXIT\\s+FUNCTION|FORM)\\b[^%\\$\\.]"
|
||||
},
|
||||
{
|
||||
"name": "support.function",
|
||||
@@ -550,17 +517,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"strings": {
|
||||
"name": "string.quoted.double.4690basic",
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.character.escape.4690basic",
|
||||
"match": "\\\\."
|
||||
}
|
||||
]
|
||||
},
|
||||
"single-stmts": {
|
||||
"name": "support.function",
|
||||
"match": "(COMMAND$|CONCHAR%|CONSOLE|DATE$)"
|
||||
@@ -585,24 +541,16 @@
|
||||
{
|
||||
"include": "#identifier"
|
||||
},
|
||||
{
|
||||
"name": "punctuation.separator.parameter",
|
||||
"match": ","
|
||||
},
|
||||
{
|
||||
"name": "punctuation.separator.option",
|
||||
"match": ";"
|
||||
},
|
||||
{
|
||||
"match": "\\s+",
|
||||
"name": "text.whitespace"
|
||||
}
|
||||
],
|
||||
"end": "$"
|
||||
"end": "(?<!\\\\)($|\\n)"
|
||||
},
|
||||
"open-close": {
|
||||
"name": "support.function",
|
||||
"match": "(?i)OPEN|CLOSE|KEYED|RECL|AS"
|
||||
"match": "(?i)\\b(OPEN|CLOSE|KEYED|RECL|AS[^\\$])\\b"
|
||||
},
|
||||
"access-stmt": {
|
||||
"match": "(ACCESS)\\s+((NOREAD|NOWRITE|NODEL)(\\s*,\\s*(NOREAD|NOWRITE|NODEL)){0,2})",
|
||||
@@ -702,9 +650,6 @@
|
||||
{
|
||||
"include": "#number-literal"
|
||||
},
|
||||
{
|
||||
"include": "#number-literal"
|
||||
},
|
||||
{
|
||||
"include": "#arithmetic-operator"
|
||||
},
|
||||
@@ -732,6 +677,9 @@
|
||||
"name": "keyword.control",
|
||||
"match": "(?i)(BEGIN)"
|
||||
},
|
||||
{
|
||||
"include": "#identifier"
|
||||
},
|
||||
{
|
||||
"include": "#line-continuation"
|
||||
},
|
||||
@@ -743,7 +691,7 @@
|
||||
"name": "text.whitespace"
|
||||
}
|
||||
],
|
||||
"end": "(?<!\\\\)\\n"
|
||||
"end": "(?<!\\\\)(\\n)"
|
||||
},
|
||||
"if-statement-end": {
|
||||
"name": "meta.if.end",
|
||||
@@ -811,7 +759,9 @@
|
||||
"name": "meta.for",
|
||||
"begin": "(?i)\\bFOR\\s+",
|
||||
"beginCaptures": {
|
||||
"0": { "name": "keyword.control" }
|
||||
"0": {
|
||||
"name": "keyword.control"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
@@ -832,6 +782,9 @@
|
||||
},
|
||||
{
|
||||
"include": "#number-literal"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
}
|
||||
],
|
||||
"end": "(?<!\\\\)\\n"
|
||||
|
||||
@@ -10,7 +10,7 @@ const path = require('path');
|
||||
/** @type WebpackConfig */
|
||||
const extensionConfig = {
|
||||
target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
||||
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
|
||||
mode: 'production', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
|
||||
|
||||
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
output: {
|
||||
|
||||
Reference in New Issue
Block a user