nvim-coverage icon indicating copy to clipboard operation
nvim-coverage copied to clipboard

Coverage data is not automatically loaded when running Coverage* commands

Open lukepafford opened this issue 1 year ago • 3 comments

Description

First off, pretty damn nifty plugin. I Just started ramping up with NeoVim, and I try to create a "toggle" mapping for every plugin that contains its own "on/off" actions.

If I want to turn on the coverage report in my code files, I have to first run CoverageLoad, and then run CoverageToggle. This is two commands, rather than one. Ok, not the end of the world, let's just map these two commands to a single mapping:

keys = {
  { "<leader>cot", 
    function()
      local cov = require("coverage")
      cov.load()
      cov.toggle()
    end, desc = "Coverage Toggle"
  },
}

Unfortunately, this doesn't work. I suspect the reason is because CoverageLoad is performing IO, and CoverageToggle finishes running before CoverageLoad completes. I have created a workaround that waits half a second, and produces consistent results:

-- My hacky-ish nvim-coverage.lua config for lazy.nvim
local function waitUntilLoaded()
    local coverageLoaded = false

    return function(cov, f)
        if not coverageLoaded then
            cov.load()
            coverageLoaded = true

            local timer = vim.loop.new_timer()
            timer:start(500, 0, function()
                vim.schedule(function()
                    f()
                end)
            end
            )
        else
            f()
        end
    end
end


WaitUntilLoaded = waitUntilLoaded()

local function toggle(cov)
    return WaitUntilLoaded(cov, cov.toggle)
end

local function summary(cov)
    return WaitUntilLoaded(cov, cov.summary)
end

return {
    "andythigpen/nvim-coverage",
    lazy = true,
    dependencies = {
        'nvim-lua/plenary.nvim',
        'nvim-neotest/neotest',
    },
    keys = {
        { "<leader>cos", function() local cov = require("coverage") summary(cov) end, desc = "Coverage Summary" },
        { "<leader>cot", function() local cov = require("coverage") toggle(cov) end, desc = "Coverage Toggle"},
    },
    config = function()
        require("coverage").setup({
            auto_reload = true,
        })
    end
}

While this works for me, this feels like something that nvim-coverage should do natively, and with a less hacky solution than just sleeping for half a second.

You would probably want to emit an event when CoverageLoad completes, and Coverage* commands would listen for that event (I don't know how this is done in the NeoVim API, I'm just a newborn lua scripter 🥲)

Acceptance Criteria

  • nvim-coverage automatically loads coverage data when performing Coverage commands for the first time

lukepafford avatar Oct 15 '23 23:10 lukepafford

does the following work for your use case?

keys = {
  { "<leader>cot", 
    function()
      local cov = require("coverage")
      cov.load(true)
    end, desc = "Coverage Toggle"
  },
}

passing true to the load function will place the signs after they are loaded

andythigpen avatar Oct 25 '23 22:10 andythigpen

Unfortunately that is still a bit buggy. Here is my revised config:

Revised Buggy Config

return {
    "andythigpen/nvim-coverage",
    lazy = true,
    dependencies = {
        'nvim-lua/plenary.nvim',
        'nvim-neotest/neotest',
    },
    keys = {
        {
            "<leader>cos",
            function()
                local cov = require("coverage")
                cov.load()
                cov.summary()
            end,
            desc = "Coverage Summary"
        },
        {
            "<leader>cot",
            function()
                local cov = require("coverage")
                cov.load(true)
            end,
            desc = "Coverage Toggle"
        },
        -- { "<leader>cos", function() local cov = require("coverage") summary(cov) end, desc = "Coverage Summary" },
        -- { "<leader>cot", function() local cov = require("coverage") toggle(cov) end, desc = "Coverage Toggle"},
    },
    config = function()
        local cov = require("coverage").setup({
            auto_reload = true
        })
    end
}

Toggle Issues

Running <leader>cot will turn the coverage on with this configuration, however re-running the toggle command doesn't turn it off.

Summary Issues

Running <leader>cos will fail on the first attempt with the error "Coverage report not loaded", and then works after the 2nd+ attempts. I assume this is the case because the first load command is running asynchronously and hasn't completed yet.


My current config in the original post is still working fine for me, so this isn't super important, it just seems unintuitive for new plugin users.

lukepafford avatar Oct 26 '23 17:10 lukepafford

Hi,

If it's of help to anyone, I did something like this:

local coverage = require("coverage")

local show_coverage = false

function toggle_coverage(ev)
  show_coverage = not show_coverage
  coverage.load(show_coverage)
end

local function load_cb()
  if show_coverage then
    coverage.show()
  else
    coverage.hide()
  end
end

-- Setup coverage
coverage.setup({
  auto_reload = true,
  load_coverage_cb = load_cb,
})

-- Auto-load for python
vim.api.nvim_create_autocmd('FileType', {
  pattern = 'python',
  desc = 'Auto-load coverage in python projects',
  callback = coverage.load,
})

And in my keymap file:

local keymap = vim.api.nvim_set_keymap

-- Coverage
keymap('n', '<leader>cs', ':CoverageSummary<CR>', { noremap = true })
keymap('n', '<leader>cv', '', { noremap = true, callback = toggle_coverage })

It works well for my purposes.

  • When I open a python file .coverage is auto-loaded, but not displayed in the signcolumn
  • <leader>cv toggles display (and reloads .coverage, technically)
  • When I re-run the testsuite, the signs update, if they are visible (and they stay visible/hidden)

@andythigpen Thanks for the nice plugin! :ok_hand:

l1nd3r0th avatar Jan 04 '24 18:01 l1nd3r0th