mantoni / eslint_d.js

Speed up eslint to accelerate your development workflow
MIT License
1.1k stars 69 forks source link

Vim integration autofix command in Neovim doesn't replace buffer content with autofixed buffer content #145

Closed sethidden closed 3 years ago

sethidden commented 3 years ago

In README.md, in the automatic-fixing section for Vim there's this line:

"_ Autofix entire buffer with eslint_d: nnoremap \<leader>f mF:%!eslint_d --stdin --fix-to-stdout\<CR>`F source

Here's a repro setup script

git clone https://github.com/3nuc/zio gh-repro-nvim-autofix
cd gh-repro-nvim-autofix
npm ci #eslint-plugin-vue
nvim -nu clean_eslint_d_init.vim src/components/VkLoader.vue #disable nvim plugins + minimal \f init.vim

I'm using Neovim and testing on https://github.com/3nuc/zio on this file: https://github.com/3nuc/zio/blob/master/src/components/VkLoader.vue

On lines 11-15 there are lots of returns. Eslint in the repo I'm testing on is configured to complain about that and offer an autofix

Yet if you do \<leader>f on that file, nothing will happen (I also tried :e! after that to make sure I'm viewing the freshest version of the file)

An approach that works is to call: :!eslint_d % --fix in that case the line breaks on 11-15 are removed and only one line break is preserved - which is the expected result of running \f but for some reason I can't get that to happen

eslint_d ver: v7.18.0 (eslint_d v9.1.2) npx eslint (workspace eslint ver): v7.14.0

nvim --version NVIM v0.5.0-dev Build type: RelWithDebInfo LuaJIT 2.1.0-beta3 Compilation: /usr/bin/cc -g -O2 -fdebug-prefix-map=/build/neovim-HFgaFt/neovim-0.5.0+ubuntu2+git202101190021-f9b311054-d569569c9=. -fstack-protector-strong -Wformat -Werror=format-security -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -O2 -g -Og -g -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion -Wmissing-prototypes -Wimplicit-fallthrough -Wvla -fstack-protector-strong -fno-common -fdiagnostics-color=auto -DINCLUDE_GENERATED_DECLARATIONS -D_GNU_SOURCE -DNVIM_MSGPACK_HAS_FLOAT32 -DNVIM_UNIBI_HAS_VAR_FROM -DMIN_LOG_LEVEL=3 -I/build/neovim-HFgaFt/neovim-0.5.0+ubuntu2+git202101190021-f9b311054-d569569c9/build/config -I/build/neovim-HFgaFt/neovim-0.5.0+ubuntu2+git202101190021-f9b311054-d569569c9/src -I/build/neovim-HFgaFt/neovim-0.5.0+ubuntu2+git202101190021-f9b311054-d569569c9/.deps/usr/include -I/usr/include -I/build/neovim-HFgaFt/neovim-0.5.0+ubuntu2+git202101190021-f9b311054-d569569c9/build/src/nvim/auto -I/build/neovim-HFgaFt/neovim-0.5.0+ubuntu2+git202101190021-f9b311054-d569569c9/build/include Compiled by buildd@lgw01-amd64-050 Features: +acl +iconv +tui See ":help feature-compile" system vimrc file: "$VIM/sysinit.vim" fall-back for $VIM: "/usr/share/nvim" Run :checkhealth for more info
mantoni commented 3 years ago

Thank you for reporting and providing so much detail 🙏

My first best guess is that this has the same root cause as #142. I'm working on moving to the new ESLint class implementation, but didn't get to finish it yet. I'll post here once this has been released.

mantoni commented 3 years ago

v10.0.0 is out which uses the new ESLint API. Can you check if this fixes your issue?

sethidden commented 3 years ago

Unfortunately, with v7.18.0 (eslint_d v10.0.0) I'm getting the same issue as before - running \f (I also rebound to another key to make sure) with the command from readme just shows "X lines filtered", but the "remove " prettier warning stays in the buffer (again, I used :e! to make sure I'm viewing the most recent version of the file).

:!eslint_d % --fix then :e! still produces the desired result - removes extraneous CR's

ie. the setup script from the OP still reproduces the issue

sethidden commented 3 years ago

Ok, so it just doesn't work with Vue. .ts files are fine.

Here's the script I'm using to test:

cat ~/dev/zio/src/components/VkLoader.vue | node ~/dev/ghmisc/eslint_d.js/bin/eslint_d.js --config ~/dev/zio/.eslintrc.js --stdin --fix-to-stdout
eslint_d stop

Turns out that in https://github.com/mantoni/eslint_d.js/blob/master/lib/linter.js#L210 results[0].output is undefined so text (input) is returned - so that's the source of the issue where autofixes are not applied, since eslint_d just returns what it received on the input

Here's the results object from ESLint: https://gist.github.com/3nuc/65c7e915deeb60c45b91a0fa84f2f889

As you can see, it immediately fails on the first character of the input (\<template>), so it seems like the vue eslint plugin is not passed to new ESLint(options) ?

mantoni commented 3 years ago

@3nuc Can you check if passing --stdin-filename fixes the issue with vue for you?

sethidden commented 3 years ago

Yes!

nnoremap <leader>f mF:%!eslint_d --stdin --fix-to-stdout --stdin-filename %<CR>`F

Works for me, and in repro script from OP too.

Thanks :)

sethidden commented 3 years ago

@mantoni Any changes needed to readme.md since this fixes the issue? I don't want to replace the current command since it works in most cases. Should there be a separate "Vim with Vue" section that lists the --stdin-filename variant?

mantoni commented 3 years ago

Yes, a readme addition would be nice. It's not editor specific though. Would you like to contribute to the documentation?

sethidden commented 3 years ago

If you use Neovim LSP with nvim-lspconfig, there's a better way than the vim-centric command from the docs (the lsp way won't flicker the screen or change the scrolling position) You can just register eslint_d as a formatter for the LSP, then call the vim builtin lsp.buf.formatting_sync function

nvim_lsp.diagnosticls.setup{ ```lua nvim_lsp.diagnosticls.setup{ filetypes = { "javascript", "typescript", "vue" }, init_options = { filetypes = { javascript = "eslint", typescript = "eslint", vue = "eslint", }, linters = { eslint = { sourceName = "eslint", command = "eslint_d", rootPatterns = { ".eslintrc", ".eslintrc.json", ".eslintrc.cjs", ".eslintrc.js", ".eslintrc.yml", ".eslintrc.yaml", "package.json" }, debounce = 100, args = { "--stdin", "--stdin-filename", "%filepath", "--format", "json", }, parseJson = { errorsRoot = "[0].messages", line = "line", column = "column", endLine = "endLine", endColumn = "endColumn", security = "severity", message = "${message} [${ruleId}]", }, securities = { [1] = "warning", [2] = "error", } }, }, formatters = { eslint_d = { command = "eslint_d", args = { "--stdin", "--fix-to-stdout", "--stdin-filename", "%filepath" }, isStdout = true, doesWriteToFile = false, } }, formatFiletypes = { javascript = "eslint_d", typescript = "eslint_d", vue = "eslint_d", } } } EOF ```

After you do that, just set the map for formatting then use it nnoremap <leader>fx :lua vim.lsp.buf.formatting_sync(nil, 1000)<cr>

EDIT: I've reverted to using the command from the readme. For some reason my config in 3nuc/dotfiles attaches diagnosticls in vue files but not in ts files, so formatting ts files doesn't work (but does in vue)