ui.lua

  1--- ### UI toggle functions.
  2--
  3--  DESCRIPTION:
  4--  While you could technically delete this file, we encourage you
  5--  to keep it as it takes a lot of complexity out of `../4-mappings.lua`.
  6
  7--    Functions:
  8--      -> change_number
  9--      -> set_indent
 10--      -> toggle_animations
 11--      -> toggle_autoformat
 12--      -> toggle_autopairs
 13--      -> toggle_background
 14--      -> toggle_buffer_autoformat
 15--      -> toggle_buffer_inlay_hints
 16--      -> toggle_buffer_semantic_tokens
 17--      -> toggle_buffer_syntax
 18--      -> toggle_codelens
 19--      -> toggle_coverage_signs
 20--      -> toggle_cmp
 21--      -> toggle_conceal
 22--      -> toggle_diagnostics
 23--      -> toggle_foldcolumn
 24--      -> toggle_inlay_hints
 25--      -> toggle_lsp_signature
 26--      -> toggle_paste
 27--      -> toggle_signcolumn
 28--      -> toggle_spell
 29--      -> toggle_statusline
 30--      -> toggle_tabline
 31--      -> toggle_ui_notifications
 32--      -> toggle_url_effect
 33--      -> toggle_wrap
 34--      -> toggle_zen_mode
 35
 36
 37local M = {}
 38local utils = require("base.utils")
 39local function bool2str(bool) return bool and "on" or "off" end
 40
 41--- Change the number display modes
 42function M.change_number()
 43  local number = vim.wo.number                 -- local to window
 44  local relativenumber = vim.wo.relativenumber -- local to window
 45  if not number and not relativenumber then
 46    vim.wo.number = true
 47  elseif number and not relativenumber then
 48    vim.wo.relativenumber = true
 49  elseif number and relativenumber then
 50    vim.wo.number = false
 51  else -- not number and relativenumber
 52    vim.wo.relativenumber = false
 53  end
 54  utils.notify(string.format("number %s, relativenumber %s", bool2str(vim.wo.number), bool2str(vim.wo.relativenumber)))
 55end
 56
 57--- Set the indent and tab related numbers
 58function M.set_indent()
 59  local input_avail, input = pcall(vim.fn.input, "Set indent value (>0 expandtab, <=0 noexpandtab): ")
 60  if input_avail then
 61    local indent = tonumber(input)
 62    if not indent or indent == 0 then return end
 63    vim.bo.expandtab = (indent > 0) -- local to buffer
 64    indent = math.abs(indent)
 65    vim.bo.tabstop = indent         -- local to buffer
 66    vim.bo.softtabstop = indent     -- local to buffer
 67    vim.bo.shiftwidth = indent      -- local to buffer
 68    utils.notify(string.format("indent=%d %s", indent, vim.bo.expandtab and "expandtab" or "noexpandtab"))
 69  end
 70end
 71
 72--- Toggle animations
 73function M.toggle_animations()
 74  if vim.g.minianimate_disable then
 75    vim.g.minianimate_disable = false
 76  else
 77    vim.g.minianimate_disable = true
 78  end
 79
 80  local state = vim.g.minianimate_disable
 81  utils.notify(string.format("animations %s", bool2str(not state)))
 82end
 83
 84--- Toggle auto format
 85function M.toggle_autoformat()
 86  vim.g.autoformat_enabled = not vim.g.autoformat_enabled
 87  utils.notify(string.format("Global autoformatting %s", bool2str(vim.g.autoformat_enabled)))
 88end
 89
 90--- Toggle autopairs
 91function M.toggle_autopairs()
 92  local ok, autopairs = pcall(require, "nvim-autopairs")
 93  if ok then
 94    if autopairs.state.disabled then
 95      autopairs.enable()
 96    else
 97      autopairs.disable()
 98    end
 99    vim.g.autopairs_enabled = autopairs.state.disabled
100    utils.notify(string.format("autopairs %s", bool2str(not autopairs.state.disabled)))
101  else
102    utils.notify "autopairs not available"
103  end
104end
105
106--- Toggle background="dark"|"light"
107function M.toggle_background()
108  vim.go.background = vim.go.background == "light" and "dark" or "light"
109  utils.notify(string.format("background=%s", vim.go.background))
110end
111
112--- Toggle buffer local auto format
113function M.toggle_buffer_autoformat(bufnr)
114  bufnr = bufnr or 0
115  local old_val = vim.b[bufnr].autoformat_enabled
116  if old_val == nil then old_val = vim.g.autoformat_enabled end
117  vim.b[bufnr].autoformat_enabled = not old_val
118  utils.notify(string.format("Buffer autoformatting %s", bool2str(vim.b[bufnr].autoformat_enabled)))
119end
120
121--- Toggle LSP inlay hints (buffer)
122-- @param bufnr? number the buffer to toggle the clients on
123function M.toggle_buffer_inlay_hints(bufnr)
124  bufnr = bufnr or 0
125  vim.b[bufnr].inlay_hints_enabled = not vim.b[bufnr].inlay_hints_enabled
126  vim.lsp.inlay_hint.enable(vim.b[bufnr].inlay_hints_enabled, { bufnr = bufnr })
127  utils.notify(string.format("Buffer inlay hints %s", bool2str(vim.b[bufnr].inlay_hints_enabled)))
128end
129
130--- Toggle buffer semantic token highlighting for all language servers that support it
131--@param bufnr? number the buffer to toggle the clients on
132function M.toggle_buffer_semantic_tokens(bufnr)
133  bufnr = bufnr or 0
134  vim.b[bufnr].semantic_tokens_enabled = not vim.b[bufnr].semantic_tokens_enabled
135  for _, client in ipairs(vim.lsp.get_clients({ bufnr = bufnr })) do
136    if client.server_capabilities.semanticTokensProvider then
137      vim.lsp.semantic_tokens[vim.b[bufnr].semantic_tokens_enabled and "start" or "stop"](bufnr, client.id)
138      utils.notify(string.format("Buffer lsp semantic highlighting %s", bool2str(vim.b[bufnr].semantic_tokens_enabled)))
139    end
140  end
141end
142
143--- Toggle syntax highlighting and treesitter
144function M.toggle_buffer_syntax(bufnr)
145  -- HACK: this should just be `bufnr = bufnr or 0` but it looks like
146  --       `vim.treesitter.stop` has a bug with `0` being current.
147  bufnr = (bufnr and bufnr ~= 0) and bufnr or vim.api.nvim_win_get_buf(0)
148  local ts_avail, parsers = pcall(require, "nvim-treesitter.parsers")
149  if vim.bo[bufnr].syntax == "off" then
150    if ts_avail and parsers.has_parser() then vim.treesitter.start(bufnr) end
151    vim.bo[bufnr].syntax = "on"
152    if not vim.b.semantic_tokens_enabled then M.toggle_buffer_semantic_tokens(bufnr, true) end
153  else
154    if ts_avail and parsers.has_parser() then vim.treesitter.stop(bufnr) end
155    vim.bo[bufnr].syntax = "off"
156    if vim.b.semantic_tokens_enabled then M.toggle_buffer_semantic_tokens(bufnr, true) end
157  end
158  utils.notify(string.format("syntax %s", bool2str(vim.bo[bufnr].syntax)))
159end
160
161--- Toggle codelens
162function M.toggle_codelens(bufnr)
163  bufnr = bufnr or 0
164  vim.g.codelens_enabled = not vim.g.codelens_enabled
165  if vim.g.codelens_enabled then
166    vim.lsp.codelens.refresh({ bufnr = bufnr })
167  else
168    vim.lsp.codelens.clear()
169  end
170  utils.notify(string.format("CodeLens %s", bool2str(vim.g.codelens_enabled)))
171end
172
173--- Toggle coverage signs
174function M.toggle_coverage_signs(bufnr)
175  bufnr = bufnr or 0
176  vim.b[bufnr].coverage_signs_enabled = not vim.b[bufnr].coverage_signs_enabled
177  if vim.b[bufnr].coverage_signs_enabled then
178    utils.notify("Coverage signs on:" ..
179                 "\n\n- Git signs will be temporary disabled." ..
180                 "\n- Diagnostic signs won't be automatically disabled.")
181    vim.cmd("Gitsigns toggle_signs")
182    require("coverage").load(true)
183  else
184    utils.notify("Coverage signs off:\n\n- Git signs re-enabled.")
185    require("coverage").hide()
186    vim.cmd("Gitsigns toggle_signs")
187  end
188end
189
190--- Toggle cmp entrirely
191function M.toggle_cmp()
192  vim.g.cmp_enabled = not vim.g.cmp_enabled
193  local ok, _ = pcall(require, "cmp")
194  utils.notify(ok and string.format("completion %s", bool2str(vim.g.cmp_enabled)) or "completion not available")
195end
196
197--- Toggle conceal=2|0
198function M.toggle_conceal()
199  vim.opt.conceallevel = vim.opt.conceallevel:get() == 0 and 2 or 0
200  utils.notify(string.format("conceal %s", bool2str(vim.opt.conceallevel:get() == 2)))
201end
202
203--- Toggle diagnostics
204function M.toggle_diagnostics()
205  vim.g.diagnostics_mode = (vim.g.diagnostics_mode - 1) % 4
206  vim.diagnostic.config(require("base.utils.lsp").diagnostics[vim.g.diagnostics_mode])
207  if vim.g.diagnostics_mode == 0 then
208    utils.notify "diagnostics off"
209  elseif vim.g.diagnostics_mode == 1 then
210    utils.notify "only status diagnostics"
211  elseif vim.g.diagnostics_mode == 2 then
212    utils.notify "virtual text off"
213  else
214    utils.notify "all diagnostics on"
215  end
216end
217
218local last_active_foldcolumn
219--- Toggle foldcolumn=0|1
220function M.toggle_foldcolumn()
221  local curr_foldcolumn = vim.wo.foldcolumn
222  if curr_foldcolumn ~= "0" then last_active_foldcolumn = curr_foldcolumn end
223  vim.wo.foldcolumn = curr_foldcolumn == "0" and (last_active_foldcolumn or "1") or "0"
224  utils.notify(string.format("foldcolumn=%s", vim.wo.foldcolumn))
225end
226
227--- Toggle LSP inlay hints (global)
228-- @param bufnr? number the buffer to toggle the clients on
229function M.toggle_inlay_hints(bufnr)
230  bufnr = bufnr or 0
231  vim.g.inlay_hints_enabled = not vim.g.inlay_hints_enabled -- flip global state
232  vim.b.inlay_hints_enabled = not vim.g.inlay_hints_enabled -- sync buffer state
233  vim.lsp.buf.inlay_hint.enable(vim.g.inlay_hints_enabled, { bufnr = bufnr }) -- apply state
234  utils.notify(string.format("Global inlay hints %s", bool2str(vim.g.inlay_hints_enabled)))
235end
236
237--- Toggle lsp signature
238function M.toggle_lsp_signature()
239  local state = require('lsp_signature').toggle_float_win()
240  utils.notify(string.format("lsp signature %s", bool2str(state)))
241end
242
243--- Toggle paste
244function M.toggle_paste()
245  vim.opt.paste = not vim.opt.paste:get() -- local to window
246  utils.notify(string.format("paste %s", bool2str(vim.opt.paste:get())))
247end
248
249--- Toggle signcolumn="auto"|"no"
250function M.toggle_signcolumn()
251  if vim.wo.signcolumn == "no" then
252    vim.wo.signcolumn = "yes"
253  elseif vim.wo.signcolumn == "yes" then
254    vim.wo.signcolumn = "auto"
255  else
256    vim.wo.signcolumn = "no"
257  end
258  utils.notify(string.format("signcolumn=%s", vim.wo.signcolumn))
259end
260
261--- Toggle spell
262function M.toggle_spell()
263  vim.wo.spell = not vim.wo.spell -- local to window
264  utils.notify(string.format("spell %s", bool2str(vim.wo.spell)))
265end
266
267--- Toggle laststatus=3|2|0
268function M.toggle_statusline()
269  local laststatus = vim.opt.laststatus:get()
270  local status
271  if laststatus == 0 then
272    vim.opt.laststatus = 2
273    status = "local"
274  elseif laststatus == 2 then
275    vim.opt.laststatus = 3
276    status = "global"
277  elseif laststatus == 3 then
278    vim.opt.laststatus = 0
279    status = "off"
280  end
281  utils.notify(string.format("statusline %s", status))
282end
283
284--- Toggle showtabline=2|0
285function M.toggle_tabline()
286  vim.opt.showtabline = vim.opt.showtabline:get() == 0 and 2 or 0
287  utils.notify(string.format("tabline %s", bool2str(vim.opt.showtabline:get() == 2)))
288end
289
290--- Toggle notifications for UI toggles
291function M.toggle_ui_notifications()
292  vim.g.notifications_enabled = not vim.g.notifications_enabled
293  utils.notify(string.format("Notifications %s", bool2str(vim.g.notifications_enabled)))
294end
295
296--- Toggle URL/URI syntax highlighting rules
297function M.toggle_url_effect()
298  vim.g.url_effect_enabled = not vim.g.url_effect_enabled
299  require("base.utils").set_url_effect()
300  utils.notify(string.format("URL effect %s", bool2str(vim.g.url_effect_enabled)))
301end
302
303--- Toggle wrap
304function M.toggle_wrap()
305  vim.wo.wrap = not vim.wo.wrap -- local to window
306  utils.notify(string.format("wrap %s", bool2str(vim.wo.wrap)))
307end
308
309--- Toggle zen mode
310function M.toggle_zen_mode(bufnr)
311  bufnr = bufnr or 0
312  if not vim.b[bufnr].zen_mode then
313    vim.b[bufnr].zen_mode = true
314  else
315    vim.b[bufnr].zen_mode = false
316  end
317  utils.notify(string.format("zen mode %s", bool2str(vim.b[bufnr].zen_mode)))
318  vim.cmd "ZenMode"
319end
320
321return M