👻

neovimプラグイン開発メモ: スピナーを表示する

2024/12/04に公開

plenaryを使ったコマンドの非同期実行中など、vimのコマンドラインの部分にスピナーを表示するときの実装。

-- スピナーの表示
-- spinnerをstopする関数をreturnする。
local function show_spinner(message)
  local spinner_chars = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" }
  if message ~= nil then
    for i, char in ipairs(spinner_chars) do
      spinner_chars[i] = char .. " " .. message
    end
  end
  local spinner_index = 1
  local spinner_active = true

  local function update_spinner()
    if not spinner_active then
      return
    end
    vim.schedule(function()
      api.nvim_command("redraw")
      api.nvim_echo({ { spinner_chars[spinner_index], "@markup.strong" } }, false, {})
    end)
    spinner_index = (spinner_index % #spinner_chars) + 1
    -- 100ms後にupdate_spinnerを実行する
    --update_spinner()
    vim.defer_fn(update_spinner, 100)
  end

  update_spinner()

  return function()
    spinner_active = false
    vim.schedule(function()
      api.nvim_command("redraw")
      -- スピナークリア
      api.nvim_echo({ { "", "Normal" } }, false, {})
    end)
  end
end

利用例

function sleeptest()
  local ui = require("neosf.message_ui")
  ui.open()
  M.shutdown = ui.close_window
  local message = "実行中..."
  local stop_spinner = show_spinner(message)
  local result = plenary_cmd("sleep", { "3" }, ui.set_lines)
  ui.close_window()
  M.shutdown = nil
  stop_spinner()
  return result
end

Discussion