Skip to content

Commit 9104409

Browse files
ready to publish 0.2.3
1 parent 69975d3 commit 9104409

File tree

4 files changed

+232
-10
lines changed

4 files changed

+232
-10
lines changed

raz-adapters/vscode/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

raz-adapters/vscode/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@
148148
"command": "raz.runSpecificOverride",
149149
"title": "Run Specific Override",
150150
"category": "RAZ"
151+
},
152+
{
153+
"command": "raz.debugGlobalOverrides",
154+
"title": "Debug Global Overrides",
155+
"category": "RAZ"
151156
}
152157
],
153158
"keybindings": [

raz-adapters/vscode/src/extension.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import * as vscode from "vscode";
55
import * as path from "node:path";
66
import * as fs from "node:fs";
7+
import * as os from "node:os";
78
import * as https from "node:https";
89
import * as zlib from "node:zlib";
910
import * as tar from "tar";
11+
import * as toml from "toml";
1012
import { exec } from "node:child_process";
1113
import { registerTaskProvider, executeRazAsTask } from "./taskProvider";
1214
import { executeWithDebuggingSupport, registerDebugCommands } from "./debugger";
@@ -860,6 +862,102 @@ export async function activate(
860862
})
861863
);
862864

865+
// Register debug command
866+
context.subscriptions.push(
867+
vscode.commands.registerCommand('raz.debugGlobalOverrides', async () => {
868+
const globalRazPath = path.join(os.homedir(), '.raz');
869+
const globalOverridePath = path.join(globalRazPath, 'overrides.toml');
870+
871+
const outputChannel = ensureOutputChannel();
872+
outputChannel.clear();
873+
outputChannel.show();
874+
875+
outputChannel.appendLine('=== Debug Global Overrides ===');
876+
outputChannel.appendLine(`Global override path: ${globalOverridePath}`);
877+
outputChannel.appendLine(`File exists: ${fs.existsSync(globalOverridePath)}`);
878+
879+
if (fs.existsSync(globalOverridePath)) {
880+
try {
881+
const content = fs.readFileSync(globalOverridePath, 'utf8');
882+
const data = toml.parse(content);
883+
884+
outputChannel.appendLine(`\nParsed TOML successfully`);
885+
outputChannel.appendLine(`Top-level keys: ${Object.keys(data).join(', ')}`);
886+
887+
if (data.overrides) {
888+
const overrideKeys = Object.keys(data.overrides);
889+
outputChannel.appendLine(`\nFound ${overrideKeys.length} total overrides`);
890+
891+
// Get workspace paths for filtering
892+
const workspaceFolders = vscode.workspace.workspaceFolders;
893+
const workspacePaths = workspaceFolders ? workspaceFolders.map(folder => folder.uri.fsPath) : [];
894+
outputChannel.appendLine(`\nWorkspace paths: ${workspacePaths.join(', ')}`);
895+
896+
let relevantCount = 0;
897+
for (const key of overrideKeys) {
898+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
899+
const override = (data.overrides as Record<string, any>)[key];
900+
const filePath = override?.metadata?.file_path;
901+
const isRelevant = filePath && workspacePaths.some(wp => filePath.startsWith(wp));
902+
903+
if (isRelevant) {
904+
relevantCount++;
905+
}
906+
907+
// Apply the same function name extraction logic as the tree provider
908+
let functionName = override?.metadata?.function_name;
909+
const originalFunctionName = functionName;
910+
911+
if (!functionName || functionName === 'unknown') {
912+
const keyParts = key.split(':');
913+
if (keyParts.length >= 2) {
914+
const lastPart = keyParts[keyParts.length - 1];
915+
if (lastPart && !lastPart.startsWith('L') && !/^\d+$/.test(lastPart)) {
916+
functionName = lastPart;
917+
} else if (keyParts.length >= 3) {
918+
const potentialFunction = keyParts[keyParts.length - 2];
919+
if (potentialFunction && !potentialFunction.startsWith('L') && !/^\d+$/.test(potentialFunction)) {
920+
functionName = potentialFunction;
921+
}
922+
}
923+
}
924+
925+
if (!functionName || functionName === 'unknown') {
926+
const overrideConfigKey = override?.override_config?.key || '';
927+
const isTestRelated = key.includes('doctest') ||
928+
overrideConfigKey === 'test' ||
929+
overrideConfigKey.includes('test') ||
930+
key.includes(':L'); // Line-based overrides are often doctests
931+
932+
if (isTestRelated) {
933+
const fileName = filePath?.split('/').pop()?.replace('.rs', '') || 'doctest';
934+
functionName = `${fileName}_doctest`;
935+
} else {
936+
functionName = 'unknown';
937+
}
938+
}
939+
}
940+
941+
outputChannel.appendLine(`\n- ${key}`);
942+
outputChannel.appendLine(` Type: ${typeof override}`);
943+
outputChannel.appendLine(` Has metadata: ${override && override.metadata ? 'Yes' : 'No'}`);
944+
outputChannel.appendLine(` Has override_config: ${override && override.override_config ? 'Yes' : 'No'}`);
945+
outputChannel.appendLine(` File: ${filePath || 'unknown'}`);
946+
outputChannel.appendLine(` Relevant to workspace: ${isRelevant ? 'Yes' : 'No'}`);
947+
outputChannel.appendLine(` Original function name: ${originalFunctionName || 'undefined'}`);
948+
outputChannel.appendLine(` Extracted function name: ${functionName}`);
949+
outputChannel.appendLine(` Override config key: ${override?.override_config?.key || 'undefined'}`);
950+
}
951+
952+
outputChannel.appendLine(`\nRelevant overrides: ${relevantCount}/${overrideKeys.length}`);
953+
}
954+
} catch (error) {
955+
outputChannel.appendLine(`\nError parsing TOML: ${error}`);
956+
}
957+
}
958+
})
959+
);
960+
863961
// Watch for changes to .raz/overrides.toml files
864962
const watcher = vscode.workspace.createFileSystemWatcher('**/.raz/overrides.toml');
865963
watcher.onDidChange(() => overrideTreeProvider.refresh());

raz-adapters/vscode/src/overrideTreeProvider.ts

Lines changed: 127 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as vscode from 'vscode';
22
import * as path from 'path';
33
import * as fs from 'fs';
4+
import * as os from 'os';
45
import * as toml from 'toml';
56
import { getAllRazDirectories } from './utils/workspace';
67

@@ -42,9 +43,9 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
4243
if (!element) {
4344
// Root level - show all projects with .raz directories
4445
return Promise.resolve(this.getRazProjects());
45-
} else if (element.contextValue === 'razProject') {
46+
} else if (element.contextValue === 'razProject' || element.contextValue === 'razGlobalProject') {
4647
// For projects, show overrides
47-
return Promise.resolve(this.getProjectChildren(element.filePath!));
48+
return Promise.resolve(this.getProjectChildren(element.filePath!, element.contextValue === 'razGlobalProject'));
4849
} else if (element.contextValue === 'razOverride') {
4950
// Show override details as children
5051
return Promise.resolve(this.getOverrideDetails(element));
@@ -59,6 +60,55 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
5960
const items: OverrideItem[] = [];
6061
const workspaceRoots = new Set<string>();
6162

63+
// Add global overrides section first
64+
const globalRazPath = path.join(os.homedir(), '.raz');
65+
const globalOverridePath = path.join(globalRazPath, 'overrides.toml');
66+
67+
if (fs.existsSync(globalOverridePath)) {
68+
// For global overrides, the overrides.toml is directly in .raz folder
69+
let globalOverrideCount = 0;
70+
try {
71+
const content = fs.readFileSync(globalOverridePath, 'utf8');
72+
const data = toml.parse(content);
73+
74+
if (data.overrides) {
75+
// Filter global overrides to only those relevant to current workspace
76+
const workspaceFolders = vscode.workspace.workspaceFolders;
77+
const workspacePaths = workspaceFolders ? workspaceFolders.map(folder => folder.uri.fsPath) : [];
78+
79+
let relevantCount = 0;
80+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
81+
for (const [, override] of Object.entries(data.overrides as Record<string, any>)) {
82+
if (override && override.metadata && override.metadata.file_path) {
83+
const filePath = override.metadata.file_path;
84+
// Check if this file is within any workspace folder
85+
const isRelevant = workspacePaths.some(workspacePath =>
86+
filePath.startsWith(workspacePath)
87+
);
88+
if (isRelevant) {
89+
relevantCount++;
90+
}
91+
}
92+
}
93+
globalOverrideCount = relevantCount;
94+
}
95+
} catch (error) {
96+
console.error('Error counting global overrides:', error);
97+
}
98+
99+
if (globalOverrideCount > 0) {
100+
const globalItem = new OverrideItem(
101+
`Standalone (${globalOverrideCount} override${globalOverrideCount !== 1 ? 's' : ''})`,
102+
vscode.TreeItemCollapsibleState.Collapsed,
103+
'razGlobalProject',
104+
globalRazPath
105+
);
106+
globalItem.iconPath = new vscode.ThemeIcon('globe');
107+
globalItem.tooltip = `${globalRazPath}\n${globalOverrideCount} standalone override${globalOverrideCount !== 1 ? 's' : ''}`;
108+
items.push(globalItem);
109+
}
110+
}
111+
62112
// First pass: identify all workspace roots
63113
for (const dir of razDirs) {
64114
const cargoTomlPath = path.join(dir, 'Cargo.toml');
@@ -80,6 +130,11 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
80130
continue;
81131
}
82132

133+
// Skip the global .raz directory (home directory) since we handle it separately as "Standalone"
134+
if (dir === os.homedir()) {
135+
continue;
136+
}
137+
83138
// Skip if this directory is inside a workspace (will be handled by workspace)
84139
let isInsideWorkspace = false;
85140
for (const wsRoot of workspaceRoots) {
@@ -166,13 +221,17 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
166221
return items;
167222
}
168223

169-
private getProjectChildren(projectPath: string): OverrideItem[] {
224+
private getProjectChildren(projectPath: string, isGlobal = false): OverrideItem[] {
170225
// Simply get the overrides for this project
171-
return this.getProjectOverrides(projectPath);
226+
return this.getProjectOverrides(projectPath, isGlobal);
172227
}
173228

174-
private getProjectOverrides(projectPath: string): OverrideItem[] {
175-
const overridePath = path.join(projectPath, '.raz', 'overrides.toml');
229+
private getProjectOverrides(projectPath: string, isGlobal = false): OverrideItem[] {
230+
// For global overrides, the path is different
231+
const overridePath = isGlobal
232+
? path.join(projectPath, 'overrides.toml')
233+
: path.join(projectPath, '.raz', 'overrides.toml');
234+
176235
if (!fs.existsSync(overridePath)) {
177236
return [];
178237
}
@@ -183,9 +242,68 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
183242
const items: OverrideItem[] = [];
184243

185244
if (data.overrides) {
186-
for (const [, override] of Object.entries(data.overrides as Record<string, OverrideEntry>)) {
245+
// Get workspace paths for filtering
246+
const workspaceFolders = vscode.workspace.workspaceFolders;
247+
const workspacePaths = workspaceFolders ? workspaceFolders.map(folder => folder.uri.fsPath) : [];
248+
249+
// For global overrides, each key is the override ID and contains the full override object
250+
for (const [overrideKey, override] of Object.entries(data.overrides as Record<string, OverrideEntry>)) {
251+
if (!override || typeof override !== 'object') {
252+
continue;
253+
}
254+
255+
// For global overrides, only show those relevant to current workspace
256+
if (isGlobal && override.metadata && override.metadata.file_path) {
257+
const filePath = override.metadata.file_path;
258+
const isRelevant = workspacePaths.some(workspacePath =>
259+
filePath.startsWith(workspacePath)
260+
);
261+
if (!isRelevant) {
262+
continue;
263+
}
264+
}
265+
187266
const metadata = override.metadata;
188-
const functionName = metadata.function_name || 'unknown';
267+
268+
// Try to extract a better function name
269+
let functionName = metadata.function_name;
270+
271+
if (!functionName || functionName === 'unknown') {
272+
// Try to extract from the override key
273+
const keyParts = overrideKey.split(':');
274+
if (keyParts.length >= 2) {
275+
const lastPart = keyParts[keyParts.length - 1];
276+
// Check if it looks like a function name (not just a line number)
277+
if (lastPart && !lastPart.startsWith('L') && !/^\d+$/.test(lastPart)) {
278+
functionName = lastPart;
279+
} else if (keyParts.length >= 3) {
280+
// Maybe it's file:line:function format
281+
const potentialFunction = keyParts[keyParts.length - 2];
282+
if (potentialFunction && !potentialFunction.startsWith('L') && !/^\d+$/.test(potentialFunction)) {
283+
functionName = potentialFunction;
284+
}
285+
}
286+
}
287+
288+
// If still no good name, check if it's a doctest or test
289+
if (!functionName || functionName === 'unknown') {
290+
const overrideConfigKey = override.override_config?.key || '';
291+
const isTestRelated = overrideKey.includes('doctest') ||
292+
overrideConfigKey === 'test' ||
293+
overrideConfigKey.includes('test') ||
294+
overrideKey.includes(':L'); // Line-based overrides are often doctests
295+
296+
if (isTestRelated) {
297+
// Try to extract from file path for doctests
298+
const filePath = metadata.file_path || '';
299+
const fileName = filePath.split('/').pop()?.replace('.rs', '') || 'doctest';
300+
functionName = `${fileName}_doctest`;
301+
} else {
302+
functionName = 'unknown';
303+
}
304+
}
305+
}
306+
189307
const line = metadata.original_line || 0;
190308

191309
// Create main override item with just function name
@@ -251,6 +369,7 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
251369
}
252370
}
253371

372+
console.log(`Returning ${items.length} items for ${isGlobal ? 'global' : 'project'} overrides`);
254373
return items.sort((a, b) => a.label.localeCompare(b.label));
255374
} catch (error) {
256375
console.error('Failed to parse overrides:', error);

0 commit comments

Comments
 (0)