Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tools/vscode_extension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ The extension provides the following configuration options:
])
- `objwatch-log-viewer.indentRainbowErrorColor`: Color used to highlight indentation errors (default: "rgba(128,32,32,0.3)")
- `objwatch-log-viewer.indentRainbowIndicatorStyle`: Style of indentation indicators (default: "classic", options: "classic", "light")
- `objwatch-log-viewer.stickyScrollMaxLineCount`: Maximum number of lines to show in sticky scroll for deep nested structures (default: 32, range: 1-128)

## Log Format

Expand Down
1 change: 1 addition & 0 deletions tools/vscode_extension/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
])
- `objwatch-log-viewer.indentRainbowErrorColor`:用于高亮缩进错误的颜色(默认值:"rgba(128,32,32,0.3)")
- `objwatch-log-viewer.indentRainbowIndicatorStyle`:缩进指示器的样式(默认值:"classic",选项:"classic"、"light")
- `objwatch-log-viewer.stickyScrollMaxLineCount`:粘滞滚动中显示的最大行数,用于深度嵌套结构(默认值:32,范围:1-128)

## 日志格式

Expand Down
18 changes: 15 additions & 3 deletions tools/vscode_extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"name": "objwatch-log-viewer",
"displayName": "ObjWatch Log Viewer",
"description": "Enhanced viewer for ObjWatch debugging logs with syntax highlighting and folding support",
"version": "0.1.2",
"version": "0.1.3",
"engines": {
"vscode": "^1.80.0"
"vscode": "^1.87.0"
},
"categories": [
"Programming Languages",
Expand Down Expand Up @@ -47,6 +47,11 @@
"default": true,
"description": "Enable code folding for ObjWatch logs"
},
"objwatch-log-viewer.highlightEventTypes": {
"type": "boolean",
"default": true,
"description": "Highlight different event types with different colors"
},
"objwatch-log-viewer.enableIndentRainbow": {
"type": "boolean",
"default": true,
Expand Down Expand Up @@ -75,6 +80,13 @@
],
"default": "classic",
"description": "Style of indentation indicators"
},
"objwatch-log-viewer.stickyScrollMaxLineCount": {
"type": "number",
"default": 32,
"minimum": 1,
"maximum": 128,
"description": "Maximum number of lines to show in sticky scroll for deep nested structures"
}
}
}
Expand All @@ -93,7 +105,7 @@
},
"devDependencies": {
"@types/node": "^20.18.1",
"@types/vscode": "^1.80.0",
"@types/vscode": "^1.87.0",
"@vscode/vsce": "^3.7.0",
"typescript": "^5.3.0",
"eslint": "^8.56.0"
Expand Down
191 changes: 175 additions & 16 deletions tools/vscode_extension/src/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,26 @@ let indentDecorationTypes = [];
let indentErrorDecorationType = null;
let activeEditor = null;

// Global variables for event type highlighting
let eventTypeDecorationTypes = {};
let eventTypeHighlightEnabled = true;

/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
console.log('ObjWatch Log Viewer extension is now active!');

// Apply sticky scroll settings for deep nested structures
applyStickyScrollSettings();

// Initialize indent rainbow functionality
initializeIndentRainbow();

// Initialize event type highlighting
initializeEventTypeDecorations();
applyHighlightEventTypes();

// Listen for editor changes
activeEditor = vscode.window.activeTextEditor;
if (activeEditor && activeEditor.document.languageId === 'objwatch') {
Expand All @@ -26,21 +37,26 @@ function activate(context) {
activeEditor = editor;
if (editor && editor.document.languageId === 'objwatch') {
triggerUpdateIndentDecorations();
triggerUpdateEventTypeDecorations();
}
}, null, context.subscriptions);

vscode.workspace.onDidChangeTextDocument(event => {
if (activeEditor && event.document === activeEditor.document &&
activeEditor.document.languageId === 'objwatch') {
triggerUpdateIndentDecorations();
triggerUpdateEventTypeDecorations();
}
}, null, context.subscriptions);

vscode.workspace.onDidChangeConfiguration(configChangeEvent => {
if (configChangeEvent.affectsConfiguration('objwatch-log-viewer')) {
applyStickyScrollSettings();
initializeIndentRainbow();
applyHighlightEventTypes();
if (activeEditor && activeEditor.document.languageId === 'objwatch') {
triggerUpdateIndentDecorations();
triggerUpdateEventTypeDecorations();
}
}
}, null, context.subscriptions);
Expand All @@ -59,36 +75,61 @@ function activate(context) {
// Skip comment lines
if (text.startsWith('#')) continue;

// Get indentation level (4 spaces per level)
// Get indentation level (4 spaces per level) and process ID
const fullLine = document.lineAt(line).text;
// Handle both regular and multi-process log formats
const match = fullLine.match(/^(?:\[#\d+\])?(\s*)(\d+\s+)(\s*)/);
// Improved regex to correctly capture process ID and indentation
const match = fullLine.match(/^(\s*)(?:\[(#\d+)\]\s*)?(\d+\s+)(.*)$/);
let indentLevel = 0;
if (match && match[3]) {
indentLevel = match[3].length / 4;
let processId = null;
if (match) {
processId = match[2]; // Extract process ID if present
// Calculate indentation level based on leading spaces (4 spaces per level)
const leadingSpaces = match[1].length;
indentLevel = Math.floor(leadingSpaces / 4);
}

// Check for run events (start folding)
if (text.includes('run ')) {
stack.push({ line, indentLevel });
stack.push({ line, indentLevel, processId });
}
// Check for end events (end folding)
else if (text.includes('end ')) {
// Find matching start event
// Find matching start event with same process ID and indentation
// Use a temporary stack to preserve non-matching items
const tempStack = [];
let foundMatch = false;

while (stack.length > 0) {
const top = stack.pop();
if (top.indentLevel < indentLevel) {
// Push back if indentation doesn't match
stack.push(top);
// Check if process IDs match (both undefined/null or same value)
const processMatch = (!top.processId && !processId) ||
(top.processId === processId);

// Check if indentation levels match exactly and process IDs match
if (top.indentLevel === indentLevel && processMatch) {
// Create folding range for matching pair
ranges.push(new vscode.FoldingRange(
top.line,
line,
vscode.FoldingRangeKind.Region
));
foundMatch = true;
break;
} else {
// Keep non-matching items in temporary stack
tempStack.push(top);
}
// Create folding range
ranges.push(new vscode.FoldingRange(
top.line,
line,
vscode.FoldingRangeKind.Region
));
break;
}

// Restore non-matching items back to stack
while (tempStack.length > 0) {
stack.push(tempStack.pop());
}

// If no match found, continue to next line
if (!foundMatch) {
continue;
}
}
}
Expand Down Expand Up @@ -165,6 +206,36 @@ function deactivate() {
console.log('ObjWatch Log Viewer extension is now deactivated!');
}

// Apply sticky scroll settings for deep nested structures
function applyStickyScrollSettings() {
const config = vscode.workspace.getConfiguration('objwatch-log-viewer');
const maxLineCount = config.get('stickyScrollMaxLineCount', 32);

// Update editor sticky scroll settings
vscode.workspace.getConfiguration('editor').update('stickyScroll.maxLineCount', maxLineCount, vscode.ConfigurationTarget.Global);

console.log(`Sticky scroll max line count set to: ${maxLineCount}`);
}

// Apply highlight event types settings
function applyHighlightEventTypes() {
const config = vscode.workspace.getConfiguration('objwatch-log-viewer');
const highlightEventTypes = config.get('highlightEventTypes', true);

// Update global flag
eventTypeHighlightEnabled = highlightEventTypes;

// Clear existing event type decorations if disabled
if (!highlightEventTypes) {
clearEventTypeDecorations();
} else if (activeEditor && activeEditor.document.languageId === 'objwatch') {
// Re-apply decorations if enabled
triggerUpdateEventTypeDecorations();
}

console.log(`Event type highlighting ${highlightEventTypes ? 'enabled' : 'disabled'}`);
}

// Initialize indent rainbow functionality
function initializeIndentRainbow() {
// Clean up previous decorations
Expand Down Expand Up @@ -225,6 +296,94 @@ function triggerUpdateIndentDecorations() {
indentUpdateTimeout = setTimeout(updateIndentDecorations, 100);
}

// Clear event type decorations
function clearEventTypeDecorations() {
Object.values(eventTypeDecorationTypes).forEach(decorationType => {
if (activeEditor) {
activeEditor.setDecorations(decorationType, []);
}
decorationType.dispose();
});
eventTypeDecorationTypes = {};
}

// Initialize event type decorations
function initializeEventTypeDecorations() {
// Clear existing decorations
clearEventTypeDecorations();

// Define font colors for different event types
const eventTypeColors = {
'run': '#4CAF50', // Green - Start of execution (positive, beginning)
'end': '#9E9E9E', // Gray - End of execution (neutral, completion)
'upd': '#2196F3', // Blue - Variable creation (informative, new)
'apd': '#FF9800', // Orange - Add to data structure (warning, modification)
'pop': '#F44336' // Red - Remove from data structure (danger, deletion)
};

// Create decoration types for each event type
Object.entries(eventTypeColors).forEach(([eventType, color]) => {
eventTypeDecorationTypes[eventType] = vscode.window.createTextEditorDecorationType({
color: color,
fontWeight: 'bold'
});
});
}

// Trigger update of event type decorations
let eventTypeUpdateTimeout = null;
function triggerUpdateEventTypeDecorations() {
if (eventTypeUpdateTimeout) {
clearTimeout(eventTypeUpdateTimeout);
}
eventTypeUpdateTimeout = setTimeout(updateEventTypeDecorations, 100);
}

// Update event type decorations
function updateEventTypeDecorations() {
if (!activeEditor || !eventTypeHighlightEnabled || Object.keys(eventTypeDecorationTypes).length === 0) {
return;
}

const document = activeEditor.document;
const decorators = {};

// Initialize decorator arrays for each event type
Object.keys(eventTypeDecorationTypes).forEach(eventType => {
decorators[eventType] = [];
});

// Process each line
for (let lineNum = 0; lineNum < document.lineCount; lineNum++) {
const line = document.lineAt(lineNum);
const lineText = line.text;

// Match event types in the line - handle both regular and multi-process log formats
// Updated regex to match event types that appear after line numbers (with or without spaces)
const eventMatch = lineText.match(/^(?:\s*(?:\[#\d+\]\s*)?\d+\s*)(run|end|upd|apd|pop)\b/);
if (eventMatch) {
const eventType = eventMatch[1];
const eventStart = lineText.indexOf(eventType);
const eventEnd = eventStart + eventType.length;

if (decorators[eventType]) {
const startPos = new vscode.Position(lineNum, eventStart);
const endPos = new vscode.Position(lineNum, eventEnd);
decorators[eventType].push({
range: new vscode.Range(startPos, endPos)
});
}
}
}

// Apply decorations
Object.entries(eventTypeDecorationTypes).forEach(([eventType, decorationType]) => {
if (activeEditor && decorators[eventType]) {
activeEditor.setDecorations(decorationType, decorators[eventType]);
}
});
}

// Update indent decorations
function updateIndentDecorations() {
if (!activeEditor || !indentDecorationTypes.length) {
Expand Down
24 changes: 24 additions & 0 deletions tools/vscode_extension/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2020",
"outDir": "out",
"lib": [
"ES2020"
],
"sourceMap": true,
"rootDir": "src",
"strict": true,
"allowJs": true,
"checkJs": false
},
"include": [
"src/**/*.js",
"src/**/*.ts"
],
"exclude": [
"node_modules",
".vscode-test",
"out"
]
}