neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

ex_cmd.lua (5437B)


      1 local api = vim.api
      2 local lsp = vim.lsp
      3 
      4 local M = {}
      5 
      6 --- @param msg string
      7 local function echo_err(msg)
      8  api.nvim_echo({ { msg } }, true, { err = true })
      9 end
     10 
     11 --- @return string[]
     12 local function get_client_names()
     13  return vim
     14    .iter(lsp.get_clients())
     15    :map(function(client)
     16      return client.name
     17    end)
     18    :unique()
     19    :totable()
     20 end
     21 
     22 --- @return string[]
     23 local function get_config_names()
     24  local config_names = vim
     25    .iter(api.nvim_get_runtime_file('lsp/*.lua', true))
     26    --- @param path string
     27    :map(function(path)
     28      local file_name = path:match('[^/]*.lua$')
     29      return file_name:sub(0, #file_name - 4)
     30    end)
     31    :totable()
     32 
     33  --- @diagnostic disable-next-line
     34  vim.list_extend(config_names, vim.tbl_keys(lsp.config._configs))
     35 
     36  return vim
     37    .iter(config_names)
     38    :unique()
     39    --- @param name string
     40    :filter(function(name)
     41      return name ~= '*'
     42    end)
     43    :totable()
     44 end
     45 
     46 --- @param filter fun(string):boolean
     47 --- @return fun():string[]
     48 local function filtered_config_names(filter)
     49  return function()
     50    return vim.iter(get_config_names()):filter(filter):totable()
     51  end
     52 end
     53 
     54 local complete_args = {
     55  enable = filtered_config_names(function(name)
     56    return not lsp.is_enabled(name)
     57  end),
     58  disable = filtered_config_names(function(name)
     59    return lsp.is_enabled(name)
     60  end),
     61  restart = get_client_names,
     62  stop = get_client_names,
     63 }
     64 
     65 --- @param names string[]
     66 --- @param enable? boolean
     67 local function checked_enable(names, enable)
     68  for _, name in ipairs(names) do
     69    if name:find('*') == nil and lsp.config[name] ~= nil then
     70      lsp.enable(name, enable)
     71    else
     72      echo_err(("No client config named '%s'"):format(name))
     73    end
     74  end
     75 end
     76 
     77 --- @param config_names string[]
     78 local function ex_lsp_enable(config_names)
     79  -- Default to enabling all clients matching the filetype of the current buffer.
     80  if #config_names == 0 then
     81    local filetype = vim.bo.filetype
     82    for _, name in ipairs(get_config_names()) do
     83      local success, result = pcall(function()
     84        return lsp.config[name]
     85      end)
     86      if success then
     87        local filetypes = result.filetypes
     88        if filetypes == nil or vim.list_contains(filetypes, filetype) then
     89          table.insert(config_names, name)
     90        end
     91      else
     92        echo_err(result --[[@as string]])
     93      end
     94    end
     95    if #config_names == 0 then
     96      if filetype == '' then
     97        echo_err('Current buffer has no filetype')
     98      else
     99        echo_err(("No configs for filetype '%s'"):format(filetype))
    100      end
    101      return
    102    end
    103  end
    104 
    105  checked_enable(config_names)
    106 end
    107 
    108 --- @param config_names string[]
    109 local function ex_lsp_disable(config_names)
    110  -- Default to disabling all clients attached to the current buffer.
    111  if #config_names == 0 then
    112    config_names = vim
    113      .iter(lsp.get_clients { bufnr = api.nvim_get_current_buf() })
    114      :map(function(client)
    115        return client.name
    116      end)
    117      :filter(function(name)
    118        return lsp.config[name] ~= nil
    119      end)
    120      :totable()
    121    if #config_names == 0 then
    122      echo_err('No configs with clients attached to current buffer')
    123      return
    124    end
    125  end
    126 
    127  checked_enable(config_names, false)
    128 end
    129 
    130 --- @param client_names string[]
    131 --- @return vim.lsp.Client[]
    132 local function get_clients_from_names(client_names)
    133  -- Default to all active clients attached to the current buffer.
    134  if #client_names == 0 then
    135    local clients = lsp.get_clients { bufnr = api.nvim_get_current_buf() }
    136    if #clients == 0 then
    137      echo_err('No clients attached to current buffer')
    138    end
    139    return clients
    140  else
    141    return vim
    142      .iter(client_names)
    143      :map(function(name)
    144        local clients = lsp.get_clients { name = name }
    145        if #clients == 0 then
    146          echo_err(("No active clients named '%s'"):format(name))
    147        end
    148        return clients
    149      end)
    150      :flatten()
    151      :totable()
    152  end
    153 end
    154 
    155 --- @param client_names string[]
    156 local function ex_lsp_restart(client_names)
    157  local clients = get_clients_from_names(client_names)
    158 
    159  for _, client in ipairs(clients) do
    160    client:_restart(client.exit_timeout)
    161  end
    162 end
    163 
    164 --- @param client_names string[]
    165 local function ex_lsp_stop(client_names)
    166  local clients = get_clients_from_names(client_names)
    167 
    168  for _, client in ipairs(clients) do
    169    client:stop(client.exit_timeout)
    170  end
    171 end
    172 
    173 local actions = {
    174  enable = ex_lsp_enable,
    175  disable = ex_lsp_disable,
    176  restart = ex_lsp_restart,
    177  stop = ex_lsp_stop,
    178 }
    179 
    180 local available_subcmds = vim.tbl_keys(actions)
    181 
    182 --- Implements command: `:lsp {subcmd} {name}?`.
    183 --- @param args string
    184 M.ex_lsp = function(args)
    185  local fargs = api.nvim_parse_cmd('lsp ' .. args, {}).args
    186  if not fargs then
    187    return
    188  end
    189  local subcmd = fargs[1]
    190  if not vim.list_contains(available_subcmds, subcmd) then
    191    echo_err(("Invalid subcommand '%s'"):format(subcmd))
    192    return
    193  end
    194 
    195  local clients = { unpack(fargs, 2) }
    196 
    197  actions[subcmd](clients)
    198 end
    199 
    200 --- Completion logic for `:lsp` command
    201 --- @param line string content of the current command line
    202 --- @return string[] list of completions
    203 function M.lsp_complete(line)
    204  local split = vim.split(line, '%s+')
    205  if #split == 2 then
    206    return available_subcmds
    207  else
    208    local subcmd = split[2]
    209    return vim
    210      .iter(complete_args[subcmd]())
    211      --- @param n string
    212      :map(function(n)
    213        return vim.fn.escape(n, ' \t')
    214      end)
    215      :totable()
    216  end
    217 end
    218 
    219 return M