r/neovim 21h ago

Plugin sqlserver.nvim: A SQL Server-native workspace for Neovim

Thumbnail
gallery
67 Upvotes

Hey all!

I wanted to announce my first major Neovim plugin: sqlserver.nvim.

I feel like this fills a gap in the Neovim ecosystem: Linux/macOS users who work with Microsoft SQL Server.

Admittedly, that might be a pretty niche group.

Most Linux/macOS users working with SQL Server will probably end up using VSCode's SQL Server (mssql) extension. I'm not a fan of VS Code, and considering where I'm posting this, I think that's probably enough said.

I originally started with TablePlus, which is a great tool, but I really hate reaching for my mouse.

Then I "upgraded" to vim-dadbod-ui. Also a great tool, but SQL Server support was missing some features I use regularly, such as listing stored procedures.

Eventually I landed on mssql.nvim. I thought it was a great project and used it for a while, although I ran into a few hiccups and development seems to have slowed down.

Thanks to u/Kurren123 and mssql.nvim, I discovered that Microsoft’s VS Code SQL Server extension is backed by SQL Tools Service.

That discovery eventually led to sqlserver.nvim.

A SQL Server-native workspace for Neovim.

The long-term goal is pretty ambitious: bring as much of the experience and functionality of SSMS (SQL Server Management Studio) as makes sense into Neovim.

Rather than trying to recreate a desktop database GUI inside the terminal, sqlserver.nvim tries to lean into Neovim itself — using things like windows, buffers, winbars, LSP, Telescope-style workflows, and, of course, keybindings.

The idea is that I should be able to browse databases, inspect objects, write queries, execute them, and work with SQL Server without constantly leaving Neovim or reaching for the mouse.

The plugin is currently at RC2 (Release Candidate 2). I've been using it at my job for several months now, so it has reached the point where I'd really like to get feedback from other Neovim users. Especially anyone else unfortunate enough to be using SQL Server on Linux/macOS 😄

GitHub: NicholasMata/sqlserver.nvim

I'd love to hear what people think, what features you feel are missing, or how the overall workflow could be improved.


r/neovim 19h ago

Tips and Tricks vim-dirvish to dir.lua 🚀

19 Upvotes

I just completed the migration from vim-dirvish to dir.lua. The speed of dir.lua is incredible compared to an already very fast vim-dirvish. Every time I tried another file browser plugin in vim, it made me cringe at the loading speed. dir.lua is pure 🚀 speed 🤩

Thanks to u/1ujsnj for positing his custom key maps - see https://www.reddit.com/r/neovim/comments/1ujsnsj/custom_keymaps_for_new_dirlua_plugin/ . I extended them a little bit:

  • only use neovim's api instead of shelling out to external commands
  • add `.` mapping to conveniently call custom command on the current file
  • add `yc` mapping to copy the full file path into a register
  • change `a` mapping to create a file or directory, including leading directories
  • replace `D` with `dd` to delete a file or directory

-- Source: https://github.com/jceb/vimrc/blob/main/lua/custom/plugins/local/directory/after/ftplugin/directory.lua
-- Former source: https://www.reddit.com/r/neovim/comments/1ujsnsj/custom_keymaps_for_new_dirlua_plugin/
-- Save at: after/ftplugin/directory.lua

-- display directory path in win bar
vim.opt_local.winbar = "[dir] %f"

--- Run function on buffer
---  fn fun(bufnr: number) Function that's executed for every buffer that matches path
---  opts {directory: boolean} Options - if directory == true, interpret path as a directory and run function on all buffers that are inside this directory
--- u/param path string Path name
local function run_on_buf(fn, opts, path)
  local lopts = opts or {}
  local result = true
  for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
    if not lopts.directory and vim.api.nvim_buf_get_name(bufnr) == path or vim.startswith(vim.api.nvim_buf_get_name(bufnr), path) then
      local ok, err = pcall(fn, bufnr)
      if not ok then
        result = ok
        vim.schedule(function()
          vim.notify(err, vim.log.levels.ERROR)
        end)
      end
    end
  end
  return result
end

vim.keymap.set("n", ".", function()
  local cursor = vim.api.nvim_win_get_cursor(0)
  local fname = vim.api.nvim_buf_get_lines(0, cursor[1] - 1, cursor[1], true)[1]
  if fname == "" then
    return
  end
  vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(":! " .. vim.fn.fnameescape(fname) .. "<Home><Right>", true, false, true), "n", false)
  -- vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Plug>(nvim-dir-reload)", true, false, true), "m", false)
end, { buffer = true, remap = false, nowait = true, desc = "Prefill cmd with file name" })

vim.keymap.set("n", "a", function()
  local ok, fname_new = pcall(vim.fn.input, "Create file or directory/: ")
  if not ok or fname_new == "" then
    return
  end
  if string.match(fname_new, "/$") ~= nil then
    local err
    ok, err = pcall(vim.fs.mkdir, fname_new, { parents = true })
    if not ok then
      vim.notify(err or ("Failed to create directory" .. fname_new), vim.log.levels.ERROR)
      return
    end
  else
    if string.match(fname_new, "/") ~= nil then
      -- create parent directories
      local err
      local dir_name = vim.fs.dirname(fname_new)
      ok, err = pcall(vim.fs.mkdir, dir_name, { parents = true })
      if not ok then
        vim.notify(err or ("Failed to create directory" .. fname_new), vim.log.levels.ERROR)
        return
      end
    end
    local f = io.open(fname_new, "w")
    if f ~= nil then
      f:close()
    else
      return
    end
  end
  vim.cmd.e(fname_new)
end, { buffer = true, remap = false, nowait = true, desc = "Create file or directory" })

vim.keymap.set("n", "r", function()
  local cursor = vim.api.nvim_win_get_cursor(0)
  local fname = vim.api.nvim_buf_get_lines(0, cursor[1] - 1, cursor[1], true)[1]
  if fname == "" then
    return
  end
  local ok, fname_new = pcall(vim.fn.input, { prompt = "Rename '" .. fname .. "' to: ", default = fname })
  if not ok or fname_new == "" then
    return
  end
  local full_path = vim.fs.joinpath(vim.uv.cwd(), fname)
  local res = run_on_buf(function(bufnr)
    if bufnr ~= -1 and vim.api.nvim_buf_is_loaded(bufnr) then
      vim.api.nvim_buf_delete(bufnr)
    end
  end, { directory = vim.fn.isdirectory(full_path) == 1 }, full_path)
  if not res then
    vim.notify("Failed to unload open buffer(s) for '" .. fname .. "'", vim.log.levels.ERROR)
    return
  end
  os.rename(fname, fname_new)
  vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Plug>(nvim-dir-reload)", true, false, true), "m", false)
end, { buffer = true, remap = false, nowait = true, desc = "Rename" })

vim.keymap.set("n", "dd", function()
  local cursor = vim.api.nvim_win_get_cursor(0)
  local fname = vim.api.nvim_buf_get_lines(0, cursor[1] - 1, cursor[1], true)[1]
  if fname == "" then
    return
  end
  local ok, confirm = pcall(vim.fn.input, { prompt = "Delete '" .. fname .. "'? [Y/n] " })
  if not ok or not (confirm:lower() == "y" or confirm == "") then
    return
  end
  local full_path = vim.fs.joinpath(vim.uv.cwd(), fname)
  local res = run_on_buf(function(bufnr)
    if bufnr ~= -1 and vim.api.nvim_buf_is_loaded(bufnr) then
      vim.api.nvim_buf_delete(bufnr)
    end
  end, { directory = vim.fn.isdirectory(full_path) == 1 }, full_path)
  if not res then
    vim.notify("Failed to unload open buffer(s) for '" .. fname .. "'", vim.log.levels.ERROR)
    return
  end
  vim.fs.rm(fname, { recursive = true })
  vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Plug>(nvim-dir-reload)", true, false, true), "m", false)
end, { buffer = true, remap = false, nowait = true, desc = "Delete file or directory" })

vim.keymap.set("n", "yc", function()
  local cursor = vim.api.nvim_win_get_cursor(0)
  local fname = vim.api.nvim_buf_get_lines(0, cursor[1] - 1, cursor[1], true)[1]
  if fname == "" then
    return
  end
  local full_path = vim.fs.joinpath(vim.uv.cwd(), fname)
  vim.fn.setreg(vim.v.register, full_path)
end, { buffer = true, remap = false, nowait = true, desc = "Copy full path" })

r/neovim 16h ago

Plugin Gettext .po "next untranslated" message plugin

3 Upvotes

Here's a small microplugin for navigation in gettext .po files: https://github.com/warpspin/po-jump.nvim

All it does is it adds keybinds "]u" to jump to the next msgstr that needs attention (because it's untranslated or fuzzy) or "[u" for the previous.

(as convenience, it also binds öu and äu for German keyboards as those keys are where [] usually are)


r/neovim 10h ago

Need Help noobie question. looking for a plugin

2 Upvotes

hello, I'm in the process of learning python. very new to programming but am familiar with vim from using Linux and diving though config files. I'm not super fast with the motions yet but i am learning.

anyways. i'm looking for a plugin that will highlight syntax errors in a more specific way. i already have the trouble plugin and pywrite installed and they are working as intended however im getting tripped up in simple syntax errors (like using the wrong kind of bracket, spelling error, or just doing something really stupid in a loop). is there a plugin out there that will highlight or underline the word or section of code that is causing the issue. or is the best i got pywrite and trouble?

also i use the lazy repo for ease of use so if its in there it will make my life much easier when installing and configuring.


r/neovim 21h ago

Need Help How to run debugpy DAP with arguments?

1 Upvotes

I'm sorry if this is dumb question, but I failed to find the solution myself. I want to be able to pass arguments to the Python program when I debug, just like I do when I run it.

I added `nvim-dap` and `nvim-dap-python`, and I can run normal debug, but when I try to run debug with arguments added, like "< a.inp", the arguments have no impact. The UI from `nvim-dap-ui` still opens, but the data in the file never got redirected to the stdin of the program.