local Row = require("lsp.codelens.row") local log = require("log") ---@class ow.lsp.codelens.RefreshTask ---@field session ow.lsp.codelens.Session ---@field aborted boolean ---@field private cancels fun()[] local RefreshTask = {} RefreshTask.__index = RefreshTask ---@param session ow.lsp.codelens.Session ---@return ow.lsp.codelens.RefreshTask function RefreshTask.new(session) return setmetatable({ session = session, aborted = false, cancels = {}, }, RefreshTask) end ---@param cancel fun() function RefreshTask:track(cancel) table.insert(self.cancels, cancel) end function RefreshTask:abort() self.aborted = true for _, cancel in ipairs(self.cancels) do pcall(cancel) end self.cancels = {} end ---@param client vim.lsp.Client ---@param lens lsp.CodeLens ---@param row ow.lsp.codelens.Row function RefreshTask:resolve(client, lens, row) local method = vim.lsp.protocol.Methods.codeLens_resolve local _, req_id = client:request( method, lens, ---@param resolved lsp.CodeLens? function(err, resolved) if self.aborted then return end if err then log.warning( "client %d: %s failed: %s", client.id, method, err.message ) end row:resolve(resolved) row:render(self.session.buf) end, self.session.buf ) if req_id then self:track(function() client:cancel_request(req_id) end) end end ---@param rows table ---@param client vim.lsp.Client? ---@param lens lsp.CodeLens function RefreshTask:process_lens(rows, client, lens) local row = rows[lens.range.start.line] if not row then row = Row.new(lens.range.start.line) rows[lens.range.start.line] = row end if lens.command then row:add(lens) return end if not client or not client:supports_method(vim.lsp.protocol.Methods.codeLens_resolve) then return end row:expect() self:resolve(client, lens, row) end ---@param responses table function RefreshTask:process_responses(responses) local method = vim.lsp.protocol.Methods.textDocument_codeLens local session = self.session local new_rows = {} for client_id, response in pairs(responses) do if response.err then log.warning( "client %d: %s failed: %s", client_id, method, response.err.message ) end if not response.err and type(response.result) == "table" then local client = vim.lsp.get_client_by_id(client_id) for _, lens in ipairs(response.result) do self:process_lens(new_rows, client, lens) end end end session.rows = new_rows session:render() end function RefreshTask:run() local method = vim.lsp.protocol.Methods.textDocument_codeLens local params = { textDocument = vim.lsp.util.make_text_document_params(self.session.buf), } local cancel = vim.lsp.buf_request_all( self.session.buf, method, params, function(responses) if self.aborted then return end self:process_responses(responses) end ) self:track(cancel) end return RefreshTask