stevearc / conform.nvim

Lightweight yet powerful formatter plugin for Neovim
MIT License
3.18k stars 162 forks source link

Python Ruff formatter deletes all lines of the file #98

Closed sumarokov-vp closed 1 year ago

sumarokov-vp commented 1 year ago

Not each time, but very often Ruff formatter delete all file (after save format and manually format). If I make some changes, not delete, but if i try to format the same code second time, all lines cleared from file

conform.lua:

return {
  "stevearc/conform.nvim",
  enabled = true,
  event = { "BufReadPre", "BufNewFile" },
  config = function()
    local conform = require("conform")

    conform.setup({
      formatters_by_ft = {
        javascript = { "prettier" },
        typescript = { "prettier" },
        javascriptreact = { "prettier" },
        typescriptreact = { "prettier" },
        svelte = { "prettier" },
        css = { "prettier" },
        html = { "prettier" },
        json = { "prettier" },
        yaml = { "prettier" },
        markdown = { "prettier" },
        graphql = { "prettier" },
        lua = { "stylua" },
        python = { "isort", "ruff_format" },
      },
      format_on_save = {
        lsp_fallback = true,
        async = false,
        timeout_ms = 1000,
      },
    })

    vim.keymap.set({ "n", "v" }, "<leader>mp", function() -- Make prettier
      conform.format({
        lsp_fallback = true,
        async = false,
        timeout_ms = 1000,
      })
    end, { desc = "Format file or range (in visual mode)" })
  end,
}

:ConformInfo

Log file: /Users/vladimirsumarokov/.local/state/nvim/conform.log

Formatters for this buffer:
LSP: null-ls
isort ready (python)
ruff_format ready (python)

Other formatters:
prettier unavailable: Command not found
stylua unavailable: Command not found

Example python:

from telebot import TeleBot, types

bot = TeleBot("TOKEN")

@bot.message_handler(commands=["withdraw"])
def command_withdraw(message: types.Message):
    return message
stevearc commented 1 year ago

I can't reproduce the error. To get to the bottom of this I'm going to need one of two things:

  1. A minimal config file (example in the bug report template) with clear repro instructions
  2. Trace logs from when you have reproduced the error. Set log_level = vim.log.levels.TRACE, reproduce the error, then get the recent contents of the log file.
sumarokov-vp commented 1 year ago
  1. A minimal config file (example in the bug report template) with clear repro instructions Sorry, I cant find bug report template

There is a trace logs when error occurring:

          09:24:08[DEBUG] Run CWD: /Users/vladimirsumarokov/dev/easy_p2p
          09:24:08[DEBUG] ruff_format exited with code 0
          09:24:08[TRACE] Output lines: { "" }
          09:24:08[TRACE] Applying formatting to /Users/vladimirsumarokov/dev/easy_p2p/example.py
          09:24:08[TRACE] Comparing lines { "from telebot import TeleBot, types", "", 'bot = TeleBot("TOKEN")', "", "", '@bot.message_handler(commands=["withdraw"])', "def command_withdraw(message: types.Message):", "    return message" } and { "" }
          09:24:08[TRACE] Diff indices { { 1, 1, 0, 0 }, { 3, 6, 1, 0 } }
          09:24:08[TRACE] Applying text edits: { {
              newText = "",
              range = {
                ["end"] = {
                  character = 0,
                  line = 1
                },
                start = {
                  character = 0,
                  line = 0
                }
              }
            }, {
              newText = "",
              range = {
                ["end"] = {
                  character = 0,
                  line = 8
                },
                start = {
                  character = 0,
                  line = 2
                }
              }
            } }
          09:24:08[TRACE] Done formatting /Users/vladimirsumarokov/dev/easy_p2p/example.py
sumarokov-vp commented 1 year ago

my settings:

      log_level = vim.log.levels.TRACE,
      formatters_by_ft = {
        javascript = { "prettier" },
        typescript = { "prettier" },
        javascriptreact = { "prettier" },
        typescriptreact = { "prettier" },
        svelte = { "prettier" },
        css = { "prettier" },
        html = { "prettier" },
        json = { "prettier" },
        yaml = { "prettier" },
        markdown = { "prettier" },
        graphql = { "prettier" },
        lua = { "stylua" },
        python = { "isort", "ruff_format" },
      },
      -- format_on_save = {
      --   lsp_fallback = true,
      --   async = false,
      --   timeout_ms = 1000,
      -- },
    })

    vim.keymap.set({ "n", "v" }, "<leader>mp", function() -- Make prettier
      conform.format({
        lsp_fallback = true,
        async = false,
        timeout_ms = 1000,
      })
stevearc commented 1 year ago

What version of ruff are you using? I'm using 0.0.292 and it still works fine. Also, could you include more of the log file? The logs displayed in ConformInfo are just the most recent lines, but TRACE logs are very verbose and won't all fit. You'll need to actually open the log file and copy the relevant lines to get all of the context for running isort and then ruff. Critically, the output of isort is missing as well as the ruff command being run.

milisims commented 1 year ago

I'm having an issue with lines being removed due to isort, probably related.

Test file:

import numpy as np

from A import B
import C

Output if I use conform.format() (works as expected):

import C
import numpy as np
from A import B

Output if I use conform.format({range = {start={1, 0}, ["end"]={4,8}}}) (whole file as range):

import C

I tracked it down to apply_format, in particular indices_in_range here is evaluating to false, so it does the deletion but not the insertion, shown in the lack of a second text edit for the call with a range. If I bypass that line (just saying if true for this test), it works exactly as expected.

trace for no range (conform.format()):

15:06:37[DEBUG] Running formatters on ~/test.py: { "isort" }
15:06:37[INFO] Run isort on ~/test.py
15:06:37[TRACE] Input lines: { "import numpy as np", "", "from A import B", "import C" }
15:06:37[DEBUG] Run command: { "isort", "--stdout", "--filename", "~/test.py", "-" }
15:06:38[DEBUG] isort exited with code 0
15:06:38[TRACE] Output lines: { "import C", "import numpy as np", "from A import B" }
15:06:38[TRACE] Applying formatting to ~/test.py
15:06:38[TRACE] Comparing lines { "import numpy as np", "", "from A import B", "import C" } and { "import C", "import numpy as np", "from A import B" }
15:06:38[TRACE] Diff indices { { 1, 3, 0, 0 }, { 4, 0, 2, 2 } }
15:06:38[TRACE] Applying text edits: { {
    newText = "",
    range = {
      ["end"] = {
        character = 0,
        line = 3
      },
      start = {
        character = 0,
        line = 0
      }
    }
  }, {
    newText = "import numpy as np\nfrom A import B",
    range = {
      ["end"] = {
        character = 0,
        line = 4
      },
      start = {
        character = 0,
        line = 4
      }
    }
  } }
15:06:38[TRACE] Done formatting ~/test.py

trace with a range (conform.format({range = {start={1, 0}, ["end"]={4,8}}})):

15:06:33[DEBUG] Running formatters on ~/test.py: { "isort" }
15:06:33[INFO] Run isort on ~/test.py
15:06:33[TRACE] Input lines: { "import numpy as np", "", "from A import B", "import C" }
15:06:33[DEBUG] Run command: { "isort", "--stdout", "--filename", "~/test.py", "-" }
15:06:33[DEBUG] isort exited with code 0
15:06:33[TRACE] Output lines: { "import C", "import numpy as np", "from A import B" }
15:06:33[TRACE] Applying formatting to ~/test.py
15:06:33[TRACE] Comparing lines { "import numpy as np", "", "from A import B", "import C" } and { "import C", "import numpy as np", "from A import B" }
15:06:33[TRACE] Diff indices { { 1, 3, 0, 0 }, { 4, 0, 2, 2 } }
15:06:33[TRACE] Applying text edits: { {
    newText = "",
    range = {
      ["end"] = {
        character = 0,
        line = 3
      },
      start = {
        character = 0,
        line = 0
      }
    }
  } }
15:06:33[TRACE] Done formatting ~/test.py
a1401358759 commented 1 year ago

I also encountered this situation.

sumarokov-vp commented 1 year ago

In last updates everything working ok

mesa123123 commented 11 months ago

Hey I've begun having this exact issue now: Heres my conform.nvim logs:


`10:09:27[DEBUG] Running formatters on /home/bowmanpete/dev/SN/openopps/conftest.py: { "black", "isort" }
10:09:27[INFO] Run black on /home/bowmanpete/dev/SN/openopps/conftest.py
10:09:27[TRACE] Input lines: { <Files lines> }
10:09:27[TRACE] Diff indices { { 1, 5, 0, 0 }, { 7, 448, 1, 0 } }
10:09:27[TRACE] Applying text edits: { {
    newText = "",
    range = {
      ["end"] = {
        character = 0,
        line = 5
      },
      start = {
        character = 0,
        line = 0
      }
    }
  }, {
    newText = "",
    range = {
      ["end"] = {
        character = 0,
        line = 454
      },
      start = {
        character = 0,
        line = 6
      }
    }
  } }
10:09:27[TRACE] Done formatting /home<FILES>

Whats gone wrong all of a sudden?