Skip to content
Sebastian Lyng Johansen edited this page May 27, 2025 · 16 revisions

Tips and tricks

I ideally want this plugin to be pretty minimal, and mostly just a wrapper to start the roslyn server. I am not envisioning some big dev kit like vscode's plugin C# dev kit. I might add some custom handlers for the roslyn server, but I don't want to add everything.

This will be a wiki with some tips and tricks that I will probably update if there is some requests that I don't want to add to this plugin, but instead think the users can add to their config if they want this

Diagnostic refresh

Currently, the diagnostics are a bit of a hack, and they might not always update correctly. However, it is possible to retrieve them as often as you would like with something like this:

vim.api.nvim_create_autocmd({ "InsertLeave" }, {
    pattern = "*",
    callback = function()
        local clients = vim.lsp.get_clients({ name = "roslyn" })
        if not clients or #clients == 0 then
            return
        end

        local buffers = vim.lsp.get_buffers_by_client_id(clients[1].id)
        for _, buf in ipairs(buffers) do
            vim.lsp.util._refresh("textDocument/diagnostic", { bufnr = buf })
        end
    end,
})

Just change the InsertLeave event to whichever events you would like

Remove unnecessary using directives

This is already provided with the code actions if you have the cursor over the using statements. I therefore will not add a special command for this. If you however want this, you could do something like this:

vim.api.nvim_create_user_command("CSFixUsings", function()
    local bufnr = vim.api.nvim_get_current_buf()

    local clients = vim.lsp.get_clients({ name = "roslyn" })
    if not clients or vim.tbl_isempty(clients) then
        vim.notify("Couldn't find client", vim.log.levels.ERROR, { title = "Roslyn" })
        return
    end

    local client = clients[1]
    local action = {
        kind = "quickfix",
        data = {
            CustomTags = { "RemoveUnnecessaryImports" },
            TextDocument = { uri = vim.uri_from_bufnr(bufnr) },
            CodeActionPath = { "Remove unnecessary usings" },
            Range = {
                ["start"] = { line = 0, character = 0 },
                ["end"] = { line = 0, character = 0 },
            },
            UniqueIdentifier = "Remove unnecessary usings",
        },
    }

    client:request("codeAction/resolve", action, function(err, resolved_action)
        if err then
            vim.notify("Fix using directives failed", vim.log.levels.ERROR, { title = "Roslyn" })
            return
        end
        vim.lsp.util.apply_workspace_edit(resolved_action.edit, client.offset_encoding)
    end)
end, { desc = "Remove unnecessary using directives" })

textDocument/_vs_onAutoInsert

Image

vim.api.nvim_create_autocmd("LspAttach", {
  callback = function(args)
    local client = vim.lsp.get_client_by_id(args.data.client_id)
    local bufnr = args.buf

    if client and (client.name == "roslyn" or client.name == "roslyn_ls") then
      vim.api.nvim_create_autocmd("InsertCharPre", {
        desc = "Roslyn: Trigger an auto insert on '/'.",
        buffer = bufnr,
        callback = function()
          local char = vim.v.char

          if char ~= "/" then
            return
          end

          local row, col = unpack(vim.api.nvim_win_get_cursor(0))
          row, col = row - 1, col + 1
          local uri = vim.uri_from_bufnr(bufnr)

          local params = {
            _vs_textDocument = { uri = uri },
            _vs_position = { line = row, character = col },
            _vs_ch = char,
            _vs_options = {
              tabSize = vim.bo[bufnr].tabstop,
              insertSpaces = vim.bo[bufnr].expandtab,
            },
          }

          -- NOTE: We should send textDocument/_vs_onAutoInsert request only after
          -- buffer has changed.
          vim.defer_fn(function()
            client:request(
              ---@diagnostic disable-next-line: param-type-mismatch
              "textDocument/_vs_onAutoInsert",
              params,
              function(err, result, _)
                if err or not result then
                  return
                end

                vim.snippet.expand(result._vs_textEdit.newText)
              end,
              bufnr
            )
          end, 1)
        end,
      })
    end
  end,
})
Clone this wiki locally