11import * as vscode from 'vscode' ;
22
33export class LedgerAccountCompletion implements vscode . CompletionItemProvider {
4- accounts : string [ ] = [ ] ;
4+ private accounts : Set < string > = new Set ( ) ;
5+ private disposables : vscode . Disposable [ ] = [ ] ;
56
6- constructor ( ) {
7- const defaultAccountsFile = vscode . Uri . joinPath ( vscode . extensions . getExtension ( 'parsa2820.ledger-cli' ) ! . extensionUri , 'examples' , 'accounts.ledger' ) . fsPath ;
8- const accountFiles = vscode . workspace . getConfiguration ( 'ledger' ) . get < string [ ] > ( 'accountFiles' , [ ] ) ;
9- if ( accountFiles . length === 0 ) {
10- accountFiles . push ( defaultAccountsFile ) ;
11- }
12- accountFiles . forEach ( file => {
13- this . loadAccountFile ( this . resolveFilePath ( file ) ) . then ( accounts => {
14- this . accounts . push ( ...accounts ) ;
15- } ) ;
7+ constructor ( context : vscode . ExtensionContext ) {
8+ // Initial load
9+ this . loadAllAccounts ( ) ;
10+
11+ // Watch for configuration changes
12+ const configWatcher = vscode . workspace . onDidChangeConfiguration ( ( event ) => {
13+ if ( event . affectsConfiguration ( 'ledger.accountFiles' ) ) {
14+ this . loadAllAccounts ( ) ;
15+ }
1616 } ) ;
17+ this . disposables . push ( configWatcher ) ;
18+
19+ // Watch for .ledger file changes in workspace
20+ const fileWatcher = vscode . workspace . createFileSystemWatcher ( '**/*.ledger' , false , false , false ) ;
21+ fileWatcher . onDidChange ( ( ) => this . loadAllAccounts ( ) ) ;
22+ fileWatcher . onDidCreate ( ( ) => this . loadAllAccounts ( ) ) ;
23+ fileWatcher . onDidDelete ( ( ) => this . loadAllAccounts ( ) ) ;
24+ this . disposables . push ( fileWatcher ) ;
25+
26+ context . subscriptions . push ( ...this . disposables ) ;
27+ }
28+
29+ private async loadAllAccounts ( ) : Promise < void > {
30+ const newAccounts = new Set < string > ( ) ;
31+
32+ // Find all .ledger files in workspace
33+ const ledgerFiles = await vscode . workspace . findFiles ( '**/*.ledger' , '**/node_modules/**' , 1000 ) ;
34+
35+ // Load from found files
36+ for ( const fileUri of ledgerFiles ) {
37+ const accounts = await this . loadAccountFile ( fileUri . fsPath ) ;
38+ accounts . forEach ( account => newAccounts . add ( account ) ) ;
39+ }
40+
41+ // Also load from configured account files
42+ const configuredFiles = vscode . workspace . getConfiguration ( 'ledger' ) . get < string [ ] > ( 'accountFiles' , [ ] ) ;
43+ for ( const file of configuredFiles ) {
44+ const resolvedPath = this . resolveFilePath ( file ) ;
45+ const accounts = await this . loadAccountFile ( resolvedPath ) ;
46+ accounts . forEach ( account => newAccounts . add ( account ) ) ;
47+ }
48+
49+ // Load default accounts file if no files found
50+ if ( newAccounts . size === 0 && ledgerFiles . length === 0 && configuredFiles . length === 0 ) {
51+ const extension = vscode . extensions . getExtension ( 'parsa2820.ledger-cli' ) ;
52+ if ( extension ) {
53+ const defaultAccountsFile = vscode . Uri . joinPath ( extension . extensionUri , 'examples' , 'accounts.ledger' ) . fsPath ;
54+ const accounts = await this . loadAccountFile ( defaultAccountsFile ) ;
55+ accounts . forEach ( account => newAccounts . add ( account ) ) ;
56+ }
57+ }
58+
59+ this . accounts = newAccounts ;
60+ console . log ( `Ledger: Loaded ${ this . accounts . size } accounts` ) ;
1761 }
1862
1963 provideCompletionItems ( document : vscode . TextDocument , position : vscode . Position , token : vscode . CancellationToken , context : vscode . CompletionContext ) : vscode . ProviderResult < vscode . CompletionList < vscode . CompletionItem > | vscode . CompletionItem [ ] > {
20- return this . accounts . map ( account => new vscode . CompletionItem ( account , vscode . CompletionItemKind . Variable ) ) ;
64+ return Array . from ( this . accounts ) . map ( account => new vscode . CompletionItem ( account , vscode . CompletionItemKind . Variable ) ) ;
2165 }
2266
2367 resolveCompletionItem ?( item : vscode . CompletionItem , token : vscode . CancellationToken ) : vscode . ProviderResult < vscode . CompletionItem > {
2468 throw new Error ( 'Method not implemented.' ) ;
2569 }
2670
27- private resolveFilePath ( file : string ) {
71+ private resolveFilePath ( file : string ) : string {
2872 if ( file . startsWith ( '~' ) ) {
2973 const homeDir = process . env . HOME || process . env . USERPROFILE || '' ;
3074 return file . replace ( '~' , homeDir ) ;
@@ -42,19 +86,19 @@ export class LedgerAccountCompletion implements vscode.CompletionItemProvider {
4286 const fileUri = vscode . Uri . file ( filePath ) ;
4387 const fileData = await vscode . workspace . fs . readFile ( fileUri ) ;
4488 const fileText = Buffer . from ( fileData ) . toString ( 'utf8' ) ;
45- return this . loadAccounts ( fileText ) ;
89+ return this . parseAccounts ( fileText ) ;
4690 } catch ( error ) {
47- console . error ( `Error reading account file ${ filePath } :` , error ) ;
91+ console . debug ( `Error reading account file ${ filePath } :` , error ) ;
4892 return [ ] ;
4993 }
5094 }
5195
52- private loadAccounts ( fileText : string ) : string [ ] {
96+ private parseAccounts ( fileText : string ) : string [ ] {
5397 const accounts : string [ ] = [ ] ;
5498 const lines = fileText . split ( / \r ? \n / ) ;
5599 for ( const line of lines ) {
56100 if ( this . isAccountDeclarationLine ( line ) ) {
57- const account = this . extractAccountDeclarationLineEntry ( line ) ;
101+ const account = this . extractAccountName ( line ) ;
58102 if ( account ) {
59103 accounts . push ( account ) ;
60104 }
@@ -64,19 +108,19 @@ export class LedgerAccountCompletion implements vscode.CompletionItemProvider {
64108 }
65109
66110 private isAccountDeclarationLine ( text : string ) : boolean {
67- return this . getAccountDeclarationPattern ( ) . test ( text ) ;
111+ return this . getAccountPattern ( ) . test ( text ) ;
68112 }
69113
70- private extractAccountDeclarationLineEntry ( text : string ) : string | null {
71- const pattern = this . getAccountDeclarationPattern ( ) ;
114+ private extractAccountName ( text : string ) : string | null {
115+ const pattern = this . getAccountPattern ( ) ;
72116 const match = pattern . exec ( text ) ;
73117 if ( match && match . groups ) {
74118 return match . groups [ 'account' ] . trim ( ) ;
75119 }
76120 return null ;
77121 }
78122
79- private getAccountDeclarationPattern ( ) : RegExp {
123+ private getAccountPattern ( ) : RegExp {
80124 const accountNamePattern = / (?< account > [ \[ \( ] ? [ A - Z a - z 0 - 9 : _ \- ] + ) [ \] \) ] ? / ;
81125 const commentPattern = / \s * (?< comment > [ ; # % \| \* ] .* ) ? / ;
82126 return new RegExp (
@@ -86,4 +130,8 @@ export class LedgerAccountCompletion implements vscode.CompletionItemProvider {
86130 "$"
87131 ) ;
88132 }
133+
134+ dispose ( ) : void {
135+ this . disposables . forEach ( d => d . dispose ( ) ) ;
136+ }
89137}
0 commit comments