Skip to content

Commit c282247

Browse files
Parsa2820Copilot
andcommitted
Bump version to 1.0.0 and enhance account completion
Co-authored-by: GitHub Copilot <copilot@github.com> Co-authored-by: Copilot <copilot@github.com>
1 parent fad6eef commit c282247

5 files changed

Lines changed: 95 additions & 33 deletions

File tree

CHANGELOG.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,29 @@ All notable changes to the "ledger-cli" extension will be documented in this fil
44

55
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
66

7-
## [0.0.1] - 2025-07-16
7+
## [1.0.0] - 2026-05-01
88

9-
- Initial release
9+
### Added
10+
- Automatic discovery of `.ledger` files in workspace and subdirectories
11+
- File system watchers to automatically update accounts when files change
12+
- Configuration watchers to reload accounts when settings change
1013

11-
## [0.0.2] - 2025-07-17
12-
- Improved formatting
13-
- Added transaction status cycling command
14+
### Improved
15+
- Fixed async account loading to ensure completions are available immediately
16+
- Better deduplication of accounts using Set data structure
17+
- Enhanced error handling with debug logging
18+
19+
### Features
20+
- Account auto-completion now searches workspace recursively for all `.ledger` files
21+
- Support for `ledger.accountFiles` setting for additional account sources
22+
- Fallback to default example accounts if no files found
1423

1524
## [0.0.3] - 2025-09-17
1625
- Implemented account auto completion
1726

18-
## [0.0.4] - TBD
19-
- Added snippets for common ledger entries
27+
## [0.0.2] - 2025-07-17
28+
- Improved formatting
29+
- Added transaction status cycling command
30+
31+
## [0.0.1] - 2025-07-16
32+
- Initial release

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.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"type": "git",
77
"url": "https://github.com/parsa2820/vscode-ledger-cli.git"
88
},
9-
"version": "0.0.3",
9+
"version": "1.0.0",
1010
"publisher": "parsa2820",
1111
"engines": {
1212
"vscode": "^1.102.0"
@@ -89,4 +89,4 @@
8989
"@vscode/test-cli": "^0.0.11",
9090
"@vscode/test-electron": "^2.5.2"
9191
}
92-
}
92+
}

src/completion.ts

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,74 @@
11
import * as vscode from 'vscode';
22

33
export 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-Za-z0-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
}

src/extension.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ export function activate(context: vscode.ExtensionContext) {
1010
const formatterRegistration = vscode.languages.registerDocumentFormattingEditProvider('ledger', new LedgerDocumentFormatter());
1111
context.subscriptions.push(formatterRegistration);
1212

13-
const completionRegistration = vscode.languages.registerCompletionItemProvider('ledger', new LedgerAccountCompletion());
13+
const completionProvider = new LedgerAccountCompletion(context);
14+
const completionRegistration = vscode.languages.registerCompletionItemProvider('ledger', completionProvider);
1415
context.subscriptions.push(completionRegistration);
1516

1617
registerCommands(context);

0 commit comments

Comments
 (0)