Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formatter does not reflect changes to the buffer #87

Closed
creativenull opened this issue Sep 29, 2023 · 2 comments
Closed

Formatter does not reflect changes to the buffer #87

creativenull opened this issue Sep 29, 2023 · 2 comments
Labels
Troubleshooting Tip Show a troubleshooting tip

Comments

@creativenull
Copy link
Owner

creativenull commented Sep 29, 2023

Problem

If you ran any formatter that does not take a stdin (Also see #78 and #64) then you will run into problems where you won't see your formatted code changes.

The unfortunate part is that you will have to save the file and then run :edit! to see those changes, since those formatters will only work on files saved on the system.

Solution

One solution would be to run the format command after save, for example (for a better version see the last code block):

local function efm_fmt(buf)
  local matched_clients = vim.lsp.get_active_clients({ name = 'efm', bufnr = buf })

  if vim.tbl_isempty(matched_clients) then
    return
  end

  local win_state = vim.call('winsaveview')

  vim.lsp.buf.format({ name = 'efm' })

  vim.cmd('silent edit!')
  vim.call('winrestview', win_state)
end

You will need winsaveview() and winrestview() so that the cursor and window position is saved before formatting the file. silent is needed so it does not error if it fails, we want to handle it gracefully.

Add this to your on_attach:

local function on_attach(client, buf)
  vim.keymap.set('n', '<Leader>lf', function() efm_fmt(buf) end, { buffer = buf, desc = 'Format the buffer' })

  -- ...
end

Or to your autocmd to format on save:

local lsp_fmt_group = vim.api.nvim_create_augroup('LspFormattingGroup', {})
vim.api.nvim_create_autocmd('BufWritePost', {
  group = lsp_fmt_group,
  callback = function(ev)
    efm_fmt(ev.buf)
  end,
})

Final Solution Code

We can take this one step further and account for when a formatter has formatStdin = false and only call :edit! or just format as is.

local function fmt_with_edit()
  local win_state = vim.call('winsaveview')

  vim.lsp.buf.format({ name = 'efm' })

  vim.cmd('edit!')
  vim.call('winrestview', win_state)
end

local function efm_fmt(buf)
  local matched_clients = vim.lsp.get_active_clients({ name = 'efm', bufnr = buf })

  if vim.tbl_isempty(matched_clients) then
    return
  end

  local efm = matched_clients[1]
  local ft = vim.api.nvim_buf_get_option(buf, 'filetype')
  local formatters = efm.config.settings.languages[ft]

  local matches = vim.tbl_filter(function(fmt)
    return not fmt.formatStdin
  end, formatters)

  if not vim.tbl_isempty(matches) then
    fmt_with_edit()
  else
    vim.lsp.buf.format({ name = 'efm' })
  end
end
@creativenull creativenull added the Troubleshooting Tip Show a troubleshooting tip label Sep 29, 2023
@creativenull creativenull pinned this issue Sep 29, 2023
@creativenull
Copy link
Owner Author

Anyone is free to provide any tips on this should it need modification!

@Uaitt
Copy link

Uaitt commented May 9, 2024

If you are using an auto-save plugin and you want to format the current buffer with a formatter that does not take stdin input, you can try this approach:

local function efm_fmt_with_auto_save()
  -- check if efm is available in the current buffer

  vim.lsp.buf.format({ name = "efm", async = false })
  vim.api.nvim_feedkeys("n", "n", true)
  vim.api.nvim_feedkeys("<CR>", "n", true)
  vim.cmd("edit!")
end

Hope this helps somebody 😃.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Troubleshooting Tip Show a troubleshooting tip
Projects
None yet
Development

No branches or pull requests

2 participants