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

bug: incorrect args sequence for ruff format with prepend_args #453

Closed
1 task done
bissakov opened this issue Jun 10, 2024 · 1 comment
Closed
1 task done

bug: incorrect args sequence for ruff format with prepend_args #453

bissakov opened this issue Jun 10, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@bissakov
Copy link

Neovim version (nvim -v)

NVIM v0.10.0 Build type: Release LuaJIT 2.1.1713484068

Operating system/version

Windows 10 Pro N

Add the debug logs

  • I have set log_level = vim.log.levels.DEBUG and pasted the log contents below.

Log file

Log file: D:\Work\ruff_format_bug\.repro\\state\nvim-data\conform.log
          14:38:23[DEBUG] Run command: { "ruff", "--line-length", "80", "format", "--force-exclude", "--stdin-filename", "D:/Work/ruff_format_bug/main.py", "-" }
          14:38:23[DEBUG] Run default CWD: D:\Work\ruff_format_bug
          14:38:23[INFO] ruff_format exited with code 1
          14:38:23[DEBUG] ruff_format stdout: { "main.py:1:5: E999 SyntaxError: Simple statements must be separated by newlines or semicolons", "Found 1 error.", "" }
          14:38:23[DEBUG] ruff_format stderr: { "warning: `ruff <path>` is deprecated. Use `ruff check <path>` instead.", "warning: Ignoring file format in favor of standard input.", "error: Failed to parse main.py:1:5: Simple statements must be separated by newlines or semicolons", "" }
          14:38:23[ERROR] Formatter 'ruff_format' error: warning: `ruff <path>` is deprecated. Use `ruff check <path>` instead.
          warning: Ignoring file format in favor of standard input.
          error: Failed to parse main.py:1:5: Simple statements must be separated by newlines or semicolons

Formatters for this buffer:
ruff_format ready (python) D:\Work\ruff_format_bug\.repro\\data\nvim-data\mason\bin\ruff.CMD

Describe the bug

When specifying the prepend_args property, the final arguments of ruff format are added before format command.

{ "ruff", "--line-length", "80", "format", "--force-exclude", "--stdin-filename", "D:\\Work\\google_ads\\src\\ad.py", "-" }

Should be:

{ "ruff", "format", "--line-length", "80", "--force-exclude", "--stdin-filename", "D:\\Work\\google_ads\\src\\ad.py", "-" }

Or:

{ "ruff", "format", "--force-exclude", "--stdin-filename", "D:\\Work\\google_ads\\src\\ad.py", "-", "--line-length", "80" }

What is the severity of this bug?

tolerable (can work around it)

Steps To Reproduce

  1. nvim -u repro.lua /path/to/test.yaml
  2. Open any Python file.
  3. Try to save the file.
  4. Get the error from BufWritePre autocmd
  5. Open :ConformInfo
  6. See that ruff format argument sequence is incorrect

Expected Behavior

Successful format using ruff format

Minimal example file

Any clean/dirty Python file.

def main():


    a    =1
    b=2

    print (a    +b)

if __name__ == '__main__':
    main()

Minimal init.lua

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify('./.repro', ':p')

-- set stdpaths to use .repro
for _, name in ipairs { 'config', 'data', 'state', 'cache' } do
  vim.env[('XDG_%s_HOME'):format(name:upper())] = root .. '/' .. name
end

-- bootstrap lazy
local lazypath = root .. '/plugins/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system {
    'git',
    'clone',
    '--filter=blob:none',
    '--single-branch',
    'https://github.com/folke/lazy.nvim.git',
    lazypath,
  }
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  'folke/tokyonight.nvim',
  {
    'hrsh7th/nvim-cmp',
    event = 'InsertEnter',
    opts = function(_, opts)
      opts.sources = opts.sources or {}
      table.insert(opts.sources, {
        name = 'lazydev',
        group_index = 0,
      })
    end,
    dependencies = {
      {
        'L3MON4D3/LuaSnip',
        build = (function()
          if vim.fn.has 'win32' == 1 or vim.fn.executable 'make' == 0 then
            return
          end
          return 'make install_jsregexp'
        end)(),
        dependencies = {},
      },
      'saadparwaiz1/cmp_luasnip',
      'hrsh7th/cmp-nvim-lsp',
      'hrsh7th/cmp-path',
    },
    config = function()
      local cmp = require 'cmp'
      local luasnip = require 'luasnip'
      luasnip.config.setup {}

      cmp.setup {
        snippet = {
          expand = function(args)
            luasnip.lsp_expand(args.body)
          end,
        },
        completion = { completeopt = 'menu,menuone,noinsert' },
        mapping = cmp.mapping.preset.insert {
          ['<C-n>'] = cmp.mapping.select_next_item(),
          ['<C-p>'] = cmp.mapping.select_prev_item(),
          ['<C-b>'] = cmp.mapping.scroll_docs(-4),
          ['<C-f>'] = cmp.mapping.scroll_docs(4),
          ['<C-y>'] = cmp.mapping.confirm { select = true },
          ['<C-Space>'] = cmp.mapping.complete {},

          ['<C-l>'] = cmp.mapping(function()
            if luasnip.expand_or_locally_jumpable() then
              luasnip.expand_or_jump()
            end
          end, { 'i', 's' }),
          ['<C-h>'] = cmp.mapping(function()
            if luasnip.locally_jumpable(-1) then
              luasnip.jump(-1)
            end
          end, { 'i', 's' }),
        },
        sources = {
          { name = 'nvim_lsp' },
          { name = 'luasnip' },
          { name = 'path' },
        },
      }
    end,
  },
  {
    'neovim/nvim-lspconfig',
    dependencies = {
      { 'williamboman/mason.nvim', config = true },
      'williamboman/mason-lspconfig.nvim',
      'WhoIsSethDaniel/mason-tool-installer.nvim',
      { 'j-hui/fidget.nvim', opts = {} },
    },
    config = function()
      vim.api.nvim_create_autocmd('LspAttach', {
        group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }),
        callback = function(event)
          local map = function(keys, func, desc)
            vim.keymap.set('n', keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc })
          end
          map('gd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition')
          map('gr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences')
          map(
            'gI',
            require('telescope.builtin').lsp_implementations,
            '[G]oto [I]mplementation'
          )
          map(
            '<leader>D',
            require('telescope.builtin').lsp_type_definitions,
            'Type [D]efinition'
          )
          map(
            '<leader>ds',
            require('telescope.builtin').lsp_document_symbols,
            '[D]ocument [S]ymbols'
          )
          map(
            '<leader>ws',
            require('telescope.builtin').lsp_dynamic_workspace_symbols,
            '[W]orkspace [S]ymbols'
          )
          map('<leader>rn', vim.lsp.buf.rename, '[R]e[n]ame')
          map('<leader>ca', vim.lsp.buf.code_action, '[C]ode [A]ction')
          map('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration')
          local client = vim.lsp.get_client_by_id(event.data.client_id)
          if
            client
            and client.supports_method(vim.lsp.protocol.Methods.textDocument_documentHighlight)
          then
            local highlight_augroup =
              vim.api.nvim_create_augroup('kickstart-lsp-highlight', { clear = false })
            vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
              buffer = event.buf,
              group = highlight_augroup,
              callback = vim.lsp.buf.document_highlight,
            })

            vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, {
              buffer = event.buf,
              group = highlight_augroup,
              callback = vim.lsp.buf.clear_references,
            })

            vim.api.nvim_create_autocmd('LspDetach', {
              group = vim.api.nvim_create_augroup('kickstart-lsp-detach', { clear = true }),
              callback = function(event)
                vim.lsp.buf.clear_references()
                vim.api.nvim_clear_autocmds {
                  group = 'kickstart-lsp-highlight',
                  buffer = event.buf,
                }
              end,
            })
          end

          if
            client
            and client.supports_method(vim.lsp.protocol.Methods.textDocument_inlayHint)
          then
            map('<leader>th', function()
              vim.lsp.inlay_hint.enable(
                not vim.lsp.inlay_hint.is_enabled { bufnr = event.buf }
              )
            end, '[T]oggle Inlay [H]ints')
          end
        end,
      })

      local capabilities = vim.lsp.protocol.make_client_capabilities()
      capabilities = vim.tbl_deep_extend(
        'force',
        capabilities,
        require('cmp_nvim_lsp').default_capabilities()
      )

      local servers = {
        lua_ls = {
          settings = {
            Lua = {
              diagnostics = {
                globals = {
                  'vim',
                  'require',
                },
              },
              completion = {
                callSnippet = 'Replace',
              },
            },
          },
        },
      }

      require('mason').setup()

      local ensure_installed = vim.tbl_keys(servers or {})
      vim.list_extend(ensure_installed, {
        'ruff',
      })
      local excluded_servers = { 'ruff' }
      require('mason-tool-installer').setup { ensure_installed = ensure_installed }

      require('mason-lspconfig').setup {
        handlers = {
          function(server_name)
            if vim.tbl_contains(excluded_servers, server_name) then
              return
            end

            local server = servers[server_name] or {}
            server.capabilities =
              vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {})

            require('lspconfig')[server_name].setup(server)
          end,
        },
      }
    end,
  },
  {
    'stevearc/conform.nvim',
    event = { 'BufWritePre' },
    cmd = { 'ConformInfo' },
    keys = {
      {
        '<leader>f',
        function()
          require('conform').format {
            async = true,
            lsp_fallback = true,
          }
        end,
        mode = '',
        desc = '[F]ormat buffer',
      },
    },
    config = function()
      require('conform').setup {
        log_level = vim.log.levels.DEBUG,
        notify_on_error = true,
        format_on_save = function(bufnr)
          local disable_filetypes = { c = true, cpp = true }
          return {
            timeout_ms = 500,
            lsp_fallback = not disable_filetypes[vim.bo[bufnr].filetype],
          }
        end,
        format_after_save = {
          lsp_fallback = true,
        },
        formatters_by_ft = {
          lua = { 'stylua' },
          python = {
            'ruff_format',
          },
        },
      }
    end,
  },
}
require('lazy').setup(plugins, {
  root = root .. '/plugins',
})

vim.cmd.colorscheme 'tokyonight'

local conform = require 'conform'
conform.formatters.ruff_format = {
  prepend_args = {
    '--line-length',
    '80',
  },
}

vim.api.nvim_create_autocmd('BufWritePre', {
  pattern = '*',
  callback = function(args)
    conform.format { bufnr = args.buf }
  end,
})

vim.api.nvim_create_autocmd('TextYankPost', {
  desc = 'Highlight when yanking (copying) text',
  group = vim.api.nvim_create_augroup('kickstart-highlight-yank', { clear = true }),
  callback = function()
    vim.highlight.on_yank()
  end,
})

Additional context

The issue can be bypassed by overriding the arguments by putting custom arguments anywhere after format:

conform.formatters.ruff_format = {
  args = {
    'format',
    '--line-length',
    '80',
    '--force-exclude',
    '--stdin-filename',
    '$FILENAME',
    '-',
  },
}

Alternatively, a new property append_args can be added to conform.FormatterConfigOverride:

---@field append_args? string|string[]|fun(self: conform.FormatterConfig, ctx: conform.Context): string|string[]

And in merge_formatter_configs as the functionality is already there:

---@param config conform.FormatterConfig
---@param override conform.FormatterConfigOverride
---@return conform.FormatterConfig
M.merge_formatter_configs = function(config, override)
  local ret = vim.tbl_deep_extend('force', config, override)
  if override.prepend_args then
    M.add_formatter_args(ret, override.prepend_args, { append = false })
  elseif override.append_args then
    M.add_formatter_args(ret, override.append_args, { append = true })
  end
  return ret
end
@bissakov bissakov added the bug Something isn't working label Jun 10, 2024
@stevearc
Copy link
Owner

Added support for append_args

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants