@@ -15,6 +15,11 @@ let currentPanel: vscode.WebviewPanel | undefined = undefined;
1515let currentDotContent : string = '' ;
1616let currentIsFocusedMode : boolean = false ;
1717let 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
1924export 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 * l e t \s + ( [ a - z A - Z _ ] [ a - z A - Z 0 - 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 ( / \[ l a b e l = \" [ ^ \" ] * \\ n c o u n t : ( \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 = / l e t \s + ( [ a - z A - Z _ ] [ a - z A - Z 0 - 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