Skip to content

Commit

Permalink
feat: adding a command runner for ledger reports
Browse files Browse the repository at this point in the history
  • Loading branch information
wllfaria committed Aug 20, 2024
1 parent 04645c5 commit 803f432
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 25 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ to your liking.
new_posting_today = { "td" },
new_commodity = { "cm" },
},
reports = {}
},
diagnostics = {
lsp_diagnostics = true,
Expand Down Expand Up @@ -92,6 +93,19 @@ to your liking.
- The `snippets` section defines keymaps or triggers for snippets. If you're using
native as your snippet engine, this will set the actual keymap in Neovim. You can
disable a snippet by either removing it from the list or removing its triggers.
- The `reports` section defines keymaps for running ledger reports, it will define
a keymap that runs the given ledger command string. Techinically, anything that
outputs to stdout could be used here.

Define your own reports by filling in the reports keymaps like this:
```lua
keymaps = {
reports = {
{ key = "<leader>bal", name = "Balance", command = "ledger --strict -f main.ledger bal" },
{ key = "<leader>bud", name = "Budget", command = "ledger --strict -f main.ledger budget" },
}
}
```
- The `diagnostics` field lets you customize how diagnostics work in Ledger:
- `lsp_diagnostics` sets diagnostics using vim.diagnostic.set, so it works like an
LSP diagnostic, populating your workspace diagnostics.
Expand All @@ -105,6 +119,7 @@ to your liking.
- Autocompletion for account names, powered by nvim-cmp
- Snippets for common actions (creating postings, accounts, commodities, etc.)
- Diagnostics for undeclared commodities and accounts
- Running user defined reports without leaving neovim
- And a few other things that I still have to code

## Related projects
Expand Down
69 changes: 63 additions & 6 deletions lua/ledger/commands.lua
Original file line number Diff line number Diff line change
@@ -1,15 +1,72 @@
local files = require("ledger.files")

local M = {}

--- @class LedgerCommands
--- @field augroup integer
--- @field output_augroup integer
local LedgerCommands = {}
LedgerCommands.__index = LedgerCommands

--- @type LedgerCommands
local instance

function LedgerCommands:create_augroup()
function LedgerCommands:create_augroups()
self.augroup = vim.api.nvim_create_augroup("Ledger", {})
self.output_augroup = vim.api.nvim_create_augroup("LedgerOutput", {})
end

--- @param buf integer
function LedgerCommands:set_up_output_buffer(buf)
vim.api.nvim_buf_create_user_command(buf, "LedgerOutputClose", function()
vim.api.nvim_buf_delete(buf, { force = true, unload = true })
end, {})

vim.api.nvim_buf_set_keymap(buf, "n", "q", ":LedgerOutputClose<CR>", {})

vim.api.nvim_create_autocmd("BufLeave", {
group = self.output_augroup,
buffer = buf,
callback = function()
vim.cmd("LedgerOutputClose")
end,
})
end

--- @param command string
function LedgerCommands:run_report(command)
local cwd = files.cwd()
local command_args = vim.split(command, " ")

vim.cmd("split")
vim.cmd("enew")

local buf = vim.api.nvim_get_current_buf()

vim.bo[buf].buftype = "nofile"
vim.bo[buf].swapfile = false
vim.bo[buf].bufhidden = "wipe"
self:set_up_output_buffer(buf)

local ok, result = pcall(vim.system, command_args, { cwd = cwd })

if not ok then
local message = {
"Something went wrong. Failed to run report command:",
command,
"",
"With stdout message:",
result,
}
vim.api.nvim_buf_set_lines(buf, 0, -1, false, message)
return
end

local result_output = result:wait().stdout
if not result_output then
error("ledger command should always return output")
return
end
vim.api.nvim_buf_set_lines(buf, 0, -1, false, vim.split(result_output, "\n"))

vim.api.nvim_set_option_value("modifiable", false, { buf = buf })
end

function LedgerCommands:setup_autocommands()
Expand Down Expand Up @@ -52,8 +109,8 @@ function LedgerCommands:setup_autocommands()
end

function M.setup()
instance = setmetatable({}, LedgerCommands)
return instance
local self = setmetatable({}, LedgerCommands)
return self
end

return M
28 changes: 25 additions & 3 deletions lua/ledger/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,18 @@ local M = {}
--- @field new_posting_today string[]
--- @field new_commodity string[]

--- @class ledger.ReportKeymap
--- @field name string
--- @field key string
--- @field command string

--- @class ledger.Keymaps
--- @field snippets ledger.SnippetKeymaps
--- @field reports ledger.ReportKeymap[]

--- @class ledger.PartialKeymaps
--- @field snippets? ledger.SnippetKeymaps
--- @field reports? ledger.ReportKeymap[]

--- @class ledger.CompletionSource
--- @field enabled boolean
Expand All @@ -27,7 +37,7 @@ local M = {}
--- @field extensions string[]?
--- @field completion ledger.Completion?
--- @field snippets ledger.Snippet?
--- @field keymaps ledger.Keymaps?
--- @field keymaps ledger.PartialKeymaps?
--- @field diagnostics ledger.Diagnostics?

--- @class ledger.Diagnostics
Expand All @@ -44,6 +54,9 @@ local M = {}
local LedgerConfig = {}
LedgerConfig.__index = LedgerConfig

--- @type ledger.Config
local instance = nil

--- @class ledger.Snippet
local LedgerConfigSnippets = {}
LedgerConfigSnippets.__index = LedgerConfigSnippets
Expand Down Expand Up @@ -130,14 +143,22 @@ local function get_default_config()
new_posting_today = { "td" },
new_commodity = { "cm" },
},
reports = {},
},
}

return default_config
end

--- @type ledger.Config
local instance = nil
--- set keymaps for running reports
function LedgerConfig:set_keymaps()
local commands = require("ledger.commands").setup()
for _, keymap in pairs(self.keymaps.reports) do
vim.keymap.set("n", keymap.key, function()
commands:run_report(keymap.command)
end)
end
end

--- Config is a singleton, allowing us to call `get` as many times as we
--- want and always getting the same instance, so we don't have to pass
Expand All @@ -150,6 +171,7 @@ function M.setup(overrides)
local default = get_default_config()
local with_overrides = vim.tbl_deep_extend("force", default, overrides or {})
instance = setmetatable(with_overrides, LedgerConfig)
instance:set_keymaps()
end
return instance
end
Expand Down
32 changes: 17 additions & 15 deletions lua/ledger/diagnostics.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,26 @@ function M.get_missing_commodities()

for filename, postings in pairs(context.postings) do
for _, posting in pairs(postings) do
local commodity_name = posting.commodity.text
local has_commodity = false

for _, accounts in pairs(context.commodities) do
if vim.tbl_contains(accounts, commodity_name) then
has_commodity = true
if posting.commodity then
local commodity_name = posting.commodity.text
local has_commodity = false

for _, accounts in pairs(context.commodities) do
if vim.tbl_contains(accounts, commodity_name) then
has_commodity = true
end
end
end

if not has_commodity then
if not missing_accounts[filename] then
missing_accounts[filename] = {}
if not has_commodity then
if not missing_accounts[filename] then
missing_accounts[filename] = {}
end
table.insert(missing_accounts[filename], {
filename = filename,
text = commodity_name,
range = posting.account.range,
})
end
table.insert(missing_accounts[filename], {
filename = filename,
text = commodity_name,
range = posting.account.range,
})
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lua/ledger/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function M.setup(overrides)
end

local commands = require("ledger.commands").setup()
commands:create_augroup()
commands:create_augroups()
commands:setup_autocommands()

local context = require("ledger.context").new(files.cwd())
Expand Down

0 comments on commit 803f432

Please sign in to comment.