stevearc / conform.nvim

Lightweight yet powerful formatter plugin for Neovim
MIT License
2.9k stars 152 forks source link

Documentation: Simple recipe/example for custom formatter as a function #497

Open caleskog opened 1 month ago

caleskog commented 1 month ago

I was working with C++ and OpenMP, and I stumbled upon an annoying non-optional behavior of clang-format regarding pragmas. I looked into the documentation for clang-format, but it was impossible to change it. So I tried to fix it using comform.nvim instead. Essentially, I want to indent the #pragma omp ... lines so it matches the rest of the code.

Problem: The problem is that there is almost no documentation for custom formatters as functions. One can look at the injected.lua code, but it is cluttered with code specific to that formatter.

Suggestion: Adding a recipe for a simple function-based formatter. This hack solution for the clang-format issue is inspired by the GitHub repo: MedicineYeh/p-clang-format.

require('conform').setup({
  formatters = {
    ['clang-fmt-pre'] = {
      ---Replace all `#pragma omp ...` with `//#pragma omp ...`
        format = function(self, ctx, lines, callback)
          -- Use this variable if options should be possible
          local _ = self.options
          local format_erros = nil
          local formatted_lines = vim.deepcopy(lines)
          local pattern = '^%s*#pragma omp'
          for i, line in ipairs(lines) do
            if line:match(pattern) then
              local fmt_line = line:gsub(pattern, '//#pragma omp')
              formatted_lines[i] = fmt_line
          end
        end
      callback(format_erros, formatted_lines)
      end
    },
    ['clang-fmt-post'] = {
      ---Replace all `//#pragma omp ...` with `#pragma omp ...`
      format = function(self, ctx, lines, callback)
        -- Use this variable if options should be possible
        local _ = self.options
        local format_erros = nil
        local formatted_lines = vim.deepcopy(lines)
        local pattern = '//%s#pragma omp'
        for i, line in ipairs(formatted_lines) do
          if line:match(pattern) then
            formatted_lines[i] = line:gsub(pattern, '#pragma omp')
          end
        end
      callback(format_erros, formatted_lines)
      end,
    },
  },
  formatters_by_ft = {
    cpp = { 'clang-fmt-pre', 'clang-format', 'clang-fmt-post' },
  },
)}
stevearc commented 1 month ago

In 2270fa1 I refactored trim_whitespace and trim_newlines to use the lua function format instead of awk. Would those serve as sufficient examples?

caleskog commented 1 month ago

Yes, they are perfect. Might be good to reference those two in the README.md, too, so it's easy to find. Like including it under the Options section. As the format option is not mentioned.