Skip to content

Add Code Actions support (textDocument/codeAction) #749

@polarmutex

Description

@polarmutex

Feature Request: Code Actions / Quick Fixes (LSP 3.17)

Description

Implement textDocument/codeAction capability to provide context-aware quick fixes and refactorings for common beancount operations.

Use Cases

Quick Fixes (CodeActionKind::QUICKFIX)

Unbalanced Transactions:

  • Action: "Balance transaction automatically"
  • Calculate missing amount and add balancing posting
  • Triggered by diagnostic: "Transaction is not balanced"

Missing Account Declarations:

  • Action: "Create account 'Assets:Bank:Checking'"
  • Generate open directive with appropriate date
  • Triggered by diagnostic: "Account is not open"

Missing Commodity:

  • Action: "Declare commodity 'AAPL'"
  • Generate commodity directive
  • Triggered by diagnostic: "Unknown commodity"

Invalid Account Names:

  • Action: "Fix account name capitalization"
  • Correct to match existing account
  • Suggest similar accounts if typo detected

Refactorings (CodeActionKind::REFACTOR)

Transaction Operations:

  • "Add balancing posting" - Insert calculated posting to balance
  • "Split transaction" - Convert to multiple transactions
  • "Merge postings" - Combine multiple postings to same account
  • "Convert currency" - Apply price conversion to posting

Account Operations:

  • "Generate balance assertion" - Query balance and insert assertion
  • "Add budget entry" - Create budget directive for account
  • "Close account" - Generate close directive with appropriate date

Batch Operations:

  • "Format all amounts" - Align decimal points
  • "Normalize account names" - Fix capitalization across file
  • "Add missing tags" - Suggest tags based on payee/account patterns

Implementation Details

File: crates/lsp/src/providers/code_action.rs

Pattern:

pub fn code_actions(
    snapshot: LspServerStateSnapshot,
    params: CodeActionParams,
) -> Result<Option<CodeActionResponse>> {
    let mut actions = vec![];
    
    // Diagnostic-based quick fixes
    for diagnostic in &params.context.diagnostics {
        if diagnostic.message.contains("unbalanced") {
            actions.push(CodeAction {
                title: "Balance transaction automatically".to_string(),
                kind: Some(CodeActionKind::QUICKFIX),
                edit: Some(calculate_balancing_edit(params.range)),
                diagnostics: Some(vec![diagnostic.clone()]),
                ..Default::default()
            });
        }
        
        if diagnostic.message.contains("not open") {
            let account = extract_account_from_diagnostic(diagnostic);
            actions.push(CodeAction {
                title: format!("Create account '{}'", account),
                kind: Some(CodeActionKind::QUICKFIX),
                edit: Some(generate_account_open_edit(&account)),
                diagnostics: Some(vec![diagnostic.clone()]),
                ..Default::default()
            });
        }
    }
    
    // Context-aware refactorings
    let node = get_node_at_position(params.range.start);
    match node.kind() {
        "txn" => {
            if !is_balanced(&node) {
                actions.push(balance_transaction_action());
            }
            actions.push(split_transaction_action());
        }
        "account" => {
            actions.push(generate_balance_assertion_action());
            actions.push(create_budget_entry_action());
        }
        _ => {}
    }
    
    Ok(Some(actions))
}

Capability Registration

Update crates/lsp/src/capabilities.rs:

code_action_provider: Some(CodeActionProviderCapability::Options(
    CodeActionOptions {
        code_action_kinds: Some(vec![
            CodeActionKind::QUICKFIX,
            CodeActionKind::REFACTOR,
        ]),
        resolve_provider: Some(false),
        ..Default::default()
    }
)),

Priority

HIGH - Dramatically improves productivity for common beancount tasks

Implementation Phases

Phase 1: Basic Quick Fixes

  • Balance transaction
  • Create missing account
  • Fix account typos

Phase 2: Advanced Quick Fixes

  • Declare missing commodity
  • Fix date format
  • Correct metadata syntax

Phase 3: Refactorings

  • Split/merge transactions
  • Generate balance assertions
  • Currency conversions
  • Batch formatting

Dependencies

  • May need to call bean-check or bean-query for balance calculations
  • Consider caching account list for faster suggestion matching
  • May integrate with existing diagnostic system

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions