Skip to content

Commit d9be09d

Browse files
committed
Update utils and enhance README for version 0.8.0
- Added `divide` and `sutract` functions to utils.res for additional arithmetic operations. - Incremented version number in package.json to 0.8.0. - Introduced a new command to toggle value usage count display in the extension. - Updated README.md to include details on the new value usage count feature and its inline annotation functionality.
1 parent df131f3 commit d9be09d

File tree

5 files changed

+183
-2
lines changed

5 files changed

+183
-2
lines changed

test/rescript/src/utils.res

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
let add = (a, b) => a + b
2-
let multiply = (a, b) => a * b
2+
let multiply = (a, b) => a * b
3+
let divide = (a, b) => a / b
4+
let sutract = (a, b) => a - b

vscode-rescriptdep/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,24 @@ A Visual Studio Code extension for visualizing dependencies between ReScript mod
77
- **Full Dependency Graph Visualization**: View the complete dependency graph of your ReScript project
88
- **Module-Focused Views**: Focus on a specific module and see its direct dependencies and dependents
99
- **Unused Module Detection**: Identify modules that have no dependents to help locate potential dead code
10+
1011
- **Interactive Graph**: Click on modules to navigate through dependencies
12+
- **Value Usage Count**: See how many times each let binding is used, directly in the editor
1113
- **High Performance**: Uses digest-based caching to improve performance for large projects
1214

1315
<div style="display: flex; justify-content: space-between;">
1416
<img src="https://github.com/mununki/rescriptdep/raw/main/vscode-rescriptdep/images/rescriptdep_screenshot_0.png" alt="ReScript Dependency Visualization" width="49%">
1517
<img src="https://github.com/mununki/rescriptdep/raw/main/vscode-rescriptdep/images/rescriptdep_screenshot_1.png" alt="Module Dependency View" width="49%">
1618
</div>
1719

20+
## Value Usage Count Annotation
21+
22+
This extension also shows how many times each value (e.g., a function or let binding) is used across your project. When you place your cursor on a `let ... =` declaration in a `.res` file, an inline annotation will appear at the end of the line, such as `Used 0 times`. This helps you quickly identify unused or rarely used values.
23+
24+
<div align="center">
25+
<img src="https://github.com/mununki/rescriptdep/raw/main/vscode-rescriptdep/images/rescriptdep_screenshot_2.png" alt="Value Usage Count Annotation" width="60%">
26+
</div>
27+
1828
## Platform Support
1929

2030
Currently, this extension is supported on:
@@ -62,6 +72,10 @@ This extension doesn't require any specific settings.
6272

6373
## Release Notes
6474

75+
### 0.8.0
76+
77+
- Show value usage count as an inline annotation for let bindings.
78+
6579
### 0.7.0
6680

6781
- Added new command "ReScript: Show Unused Modules" to display modules without dependents
43.3 KB
Loading

vscode-rescriptdep/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "vscode-bibimbob",
33
"displayName": "Bibimbob",
44
"description": "A tool to analyze dependencies between ReScript modules",
5-
"version": "0.7.0",
5+
"version": "0.8.0",
66
"publisher": "mununki",
77
"license": "MIT",
88
"icon": "images/rescriptdep_icon.png",
@@ -42,6 +42,10 @@
4242
{
4343
"command": "bibimbob.showUnusedModules",
4444
"title": "Bibimbob: Show Unused Modules"
45+
},
46+
{
47+
"command": "bibimbob.toggleValueUsageCount",
48+
"title": "Bibimbob: Toggle Value Usage Count"
4549
}
4650
]
4751
},

vscode-rescriptdep/src/extension.ts

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ let currentPanel: vscode.WebviewPanel | undefined = undefined;
1515
let currentDotContent: string = '';
1616
let currentIsFocusedMode: boolean = false;
1717
let currentCenterModule: string | undefined = undefined;
18+
// Track toggle state for value usage count display
19+
let isValueUsageCountEnabled: boolean = true;
20+
// Store the current usage count decoration
21+
let usageCountDecoration: vscode.TextEditorDecorationType | undefined = undefined;
22+
let lastDecoratedLine: number | undefined = undefined;
1823

1924
export function activate(context: vscode.ExtensionContext) {
2025
// Command for full dependency graph
@@ -32,9 +37,124 @@ export function activate(context: vscode.ExtensionContext) {
3237
await generateDependencyGraph(context, false, true);
3338
});
3439

40+
// Command to toggle value usage count display
41+
let toggleValueUsageCountCommand = vscode.commands.registerCommand('bibimbob.toggleValueUsageCount', () => {
42+
isValueUsageCountEnabled = !isValueUsageCountEnabled;
43+
vscode.window.showInformationMessage(`Value usage count display is now ${isValueUsageCountEnabled ? 'enabled' : 'disabled'}.`);
44+
// Optionally trigger update/decorate here in later steps
45+
});
46+
3547
context.subscriptions.push(fullGraphCommand);
3648
context.subscriptions.push(focusModuleCommand);
3749
context.subscriptions.push(unusedModulesCommand);
50+
context.subscriptions.push(toggleValueUsageCountCommand);
51+
52+
// Listen for .res file open or change events
53+
vscode.workspace.onDidOpenTextDocument(async (document) => {
54+
if (isValueUsageCountEnabled && document.languageId === 'rescript' && document.fileName.endsWith('.res')) {
55+
await handleValueUsageCount(document);
56+
}
57+
});
58+
vscode.workspace.onDidChangeTextDocument(async (event) => {
59+
const document = event.document;
60+
if (isValueUsageCountEnabled && document.languageId === 'rescript' && document.fileName.endsWith('.res')) {
61+
await handleValueUsageCount(document);
62+
}
63+
});
64+
65+
// Listen for cursor movement in .res files
66+
vscode.window.onDidChangeTextEditorSelection(async (event) => {
67+
if (!isValueUsageCountEnabled) return;
68+
const editor = event.textEditor;
69+
const document = editor.document;
70+
if (document.languageId !== 'rescript' || !document.fileName.endsWith('.res')) return;
71+
72+
// Get current cursor line
73+
const position = editor.selection.active;
74+
const lineText = document.lineAt(position.line).text;
75+
console.log('[Bibimbob] Cursor moved. Line:', position.line, 'Text:', lineText);
76+
77+
// Match let ... = pattern
78+
// Example: let foo =, let bar: int =, let baz: type =
79+
const letLineRegex = /^\s*let\s+([a-zA-Z_][a-zA-Z0-9_]*)\b[^=]*=/;
80+
const match = letLineRegex.exec(lineText);
81+
82+
// Remove previous decoration if cursor moved away
83+
if (usageCountDecoration && (lastDecoratedLine !== position.line || !match)) {
84+
console.log('[Bibimbob] Removing previous decoration');
85+
editor.setDecorations(usageCountDecoration, []);
86+
usageCountDecoration.dispose();
87+
usageCountDecoration = undefined;
88+
lastDecoratedLine = undefined;
89+
}
90+
91+
if (match) {
92+
const valueName = match[1];
93+
console.log('[Bibimbob] Detected let declaration:', valueName);
94+
const fileName = document.fileName;
95+
const moduleName = path.basename(fileName, '.res');
96+
97+
// Find CLI path and bsDir
98+
const workspaceFolders = vscode.workspace.workspaceFolders;
99+
if (!workspaceFolders) {
100+
console.log('[Bibimbob] No workspace folders found');
101+
return;
102+
}
103+
const context = { extensionPath: vscode.extensions.getExtension('mununki.vscode-bibimbob')?.extensionPath || '' } as vscode.ExtensionContext;
104+
const cliPath = await findRescriptDepCLI(context);
105+
const workspaceRoot = workspaceFolders[0].uri.fsPath;
106+
const projectRoot = await findProjectRootForFile(fileName, workspaceRoot) || workspaceRoot;
107+
const bsDir = path.join(projectRoot, 'lib', 'bs');
108+
109+
// Run CLI to get usage count (add -f dot flag)
110+
const args = ['-m', moduleName, '-vb', valueName, '-f', 'dot', bsDir];
111+
let usageCount = '?';
112+
try {
113+
console.log('[Bibimbob] Running CLI:', cliPath, args);
114+
const result = await runRescriptDep(cliPath, args);
115+
console.log('[Bibimbob] CLI output:', result);
116+
// Improved regex: match all [label="...\ncount: N"]
117+
const allCounts = Array.from(result.matchAll(/\[label=\"[^\"]*\\ncount: (\d+)\"\]/g));
118+
if (allCounts.length > 0) {
119+
allCounts.forEach((m, i) => {
120+
console.log(`[Bibimbob] Matched DOT line #${i + 1}:`, m[0], 'Count:', m[1]);
121+
});
122+
const total = allCounts.reduce((sum, m) => sum + parseInt(m[1], 10), 0);
123+
usageCount = String(total);
124+
console.log('[Bibimbob] Summed usage count:', usageCount);
125+
} else {
126+
usageCount = '?';
127+
console.log('[Bibimbob] Could not parse any usage count from DOT output. Full output:', result);
128+
}
129+
} catch (err) {
130+
usageCount = 'error';
131+
console.log('[Bibimbob] CLI call failed:', err);
132+
}
133+
134+
// Create and show decoration at the end of the let declaration line
135+
const decoText = `Used ${usageCount} times`;
136+
// Dispose previous decoration if exists
137+
if (usageCountDecoration) {
138+
editor.setDecorations(usageCountDecoration, []);
139+
usageCountDecoration.dispose();
140+
}
141+
usageCountDecoration = vscode.window.createTextEditorDecorationType({
142+
isWholeLine: true,
143+
after: {
144+
contentText: decoText,
145+
color: '#b5cea8',
146+
margin: '0 0 0 16px',
147+
fontStyle: 'italic',
148+
},
149+
});
150+
const decoLine = position.line;
151+
editor.setDecorations(usageCountDecoration, [
152+
{ range: new vscode.Range(decoLine, 0, decoLine, 0) }
153+
]);
154+
lastDecoratedLine = position.line;
155+
console.log('[Bibimbob] Decoration set for line', decoLine, '(after let declaration)');
156+
}
157+
});
38158
}
39159

40160
// Helper function to get current module name from active editor
@@ -2388,3 +2508,44 @@ async function findModuleInProject(moduleName: string): Promise<{ path: string,
23882508

23892509
return null;
23902510
}
2511+
2512+
// Helper: Detect let v and run CLI for each value, print result to console
2513+
async function handleValueUsageCount(document: vscode.TextDocument) {
2514+
const text = document.getText();
2515+
const fileName = document.fileName;
2516+
const moduleName = path.basename(fileName, '.res');
2517+
2518+
// Find all let value declarations (simple regex, not perfect)
2519+
// Matches: let v, let v: type, let v =, let v: type =
2520+
const letRegex = /let\s+([a-zA-Z_][a-zA-Z0-9_]*)\b/g;
2521+
let match;
2522+
const foundValues: Set<string> = new Set();
2523+
while ((match = letRegex.exec(text)) !== null) {
2524+
foundValues.add(match[1]);
2525+
}
2526+
2527+
if (foundValues.size === 0) return;
2528+
2529+
// Find CLI path
2530+
const workspaceFolders = vscode.workspace.workspaceFolders;
2531+
if (!workspaceFolders) return;
2532+
const context = { extensionPath: vscode.extensions.getExtension('mununki.vscode-bibimbob')?.extensionPath || '' } as vscode.ExtensionContext;
2533+
const cliPath = await findRescriptDepCLI(context);
2534+
2535+
// Find bsDir (project root)
2536+
const workspaceRoot = workspaceFolders[0].uri.fsPath;
2537+
const projectRoot = await findProjectRootForFile(fileName, workspaceRoot) || workspaceRoot;
2538+
const bsDir = path.join(projectRoot, 'lib', 'bs');
2539+
2540+
// For each value, run CLI and print result
2541+
for (const valueName of foundValues) {
2542+
const args = ['-m', moduleName, '-vb', valueName, bsDir];
2543+
try {
2544+
const result = await runRescriptDep(cliPath, args);
2545+
// Print usage count result to console (for now)
2546+
console.log(`[Bibimbob] Usage count for ${moduleName}.${valueName}:`, result.trim());
2547+
} catch (err) {
2548+
console.warn(`[Bibimbob] Failed to get usage count for ${moduleName}.${valueName}:`, err);
2549+
}
2550+
}
2551+
}

0 commit comments

Comments
 (0)