rcarriga / nvim-notify

A fancy, configurable, notification manager for NeoVim
MIT License
2.97k stars 78 forks source link

Question: attempting to update a notification from captured build output #176

Closed Sammyalhashe closed 1 year ago

Sammyalhashe commented 1 year ago

So I am attempting to to update a single notification from captured output from a build. I was just looking for feedback on going about it because currently I have it synchronously creating one notification per update from the build after following the docs + wiki.

Please feel free to close this if it's not appropriate for this place.

I currently have this:

local custom_notify = function(data, level)
    return notify.async(data, level, {
        title = "Runner",
        render = "compact",
        animation = "slide",
        timeout = false,
        hide_from_history = false
    })
end

local client_notifs = {}

local get_notif_data = function(id)
    if not client_notifs[id] then
        client_notifs[id] = {}
    end
    return client_notifs[id]
end

local replace = function (id, data, level)
    local notif_data = get_notif_data(id)
    print(notif_data["notification"])
    if not notif_data["notification"] then
        notif_data["notification"] = custom_notify(data, level)
        return
    end
    notif_data["notification"] = notify.async(data, level, {
        hide_from_history = true,
        replace = notif_data["notification"]
    })
end

-- split_instr is the build command in this context and args are the build commands args
job:new({
    split_instr[1], args,
    on_stdout = function (err, data)
        if not err then
            -- I am blindly putting in an id of 1 so hopefully it refers to the same notification
            replace(1, data, vim.log.levels.INFO)
        end
    end,
    on_exit = function(j, return_val)
        replace(1, "command " .. instr .. " done")
        if return_val ~= 0 then
            notify(j:result(), vim.log.levels.ERROR)
        end
    end
}):sync(1000000)

As I said currently now this creates a new notification per each captured output and am looking for feedback here. Again, feel free to close if this is not appropriate.

rcarriga commented 1 year ago

As your snippet is incomplete I can't reliably tell why it's not working but I've created a similar snippet that avoids the use of module level state (I don't maintain the wiki so I can't guarantee the quality :sweat_smile:). Also the use of the async function is unnecessary and on_exit doesn't seem to run in an async context so it caused errors so I removed the async usage.

local notify = require("notify")
local Job = require("plenary.job")

local function job_with_notify(cmd)
  local notification

  local notify_output = vim.schedule_wrap(function(data, level)
    if not notification then
      notification = notify(data, level, {
        title = "Runner",
        render = "compact",
        timeout = false,
      })
      return
    end
    notification = notify.notify(data, level, {
      hide_from_history = true,
      replace = notification,
    })
  end)

  Job:new({
    command = table.remove(cmd, 1),
    args = cmd,
    on_stdout = function(err, data)
      if not err then
        notify_output(data)
      end
    end,
    on_exit = function(j, return_val)
      notify_output("command done")
      if return_val ~= 0 then
        notify(j:result(), vim.log.levels.ERROR)
      end
    end,
  }):start()
end

job_with_notify({"bash", "-c", "for i in {1..3}; do echo hello $i; sleep 1; done;"})
Sammyalhashe commented 1 year ago

This works perfectly thank you! :D