helix icon indicating copy to clipboard operation
helix copied to clipboard

Use eslint for typescript

Open willparsons opened this issue 2 years ago • 12 comments

Is it possible to change the language server of typescript to eslint?

I tried making a user-level languages.toml to overwrite the typescript language to use eslint but it just acted as though no language server existed.

willparsons avatar Jul 28 '22 19:07 willparsons

What does your hx --health typescript say? And logs?

kirawi avatar Jul 28 '22 21:07 kirawi

eslint isn't actually a language server but a linter?

archseer avatar Jul 29 '22 04:07 archseer

@archseer there is also an eslint language server. It is quite common nowadays to use it along with tsserver, which is what vscode does.

It allows code actions to fix eslint issues. It even can act as a super fast code formatter by reading your prettier rules.

It is available on npm: https://github.com/hrsh7th/vscode-langservers-extracted

jacksonludwig avatar Jul 29 '22 11:07 jacksonludwig

Health is all good it can find eslint. The logs however are showing helix_lsp::transport [ERROR] err: <- StreamClosed

willparsons avatar Jul 29 '22 13:07 willparsons

I think these are related: https://github.com/helix-editor/helix/issues/1396, https://github.com/helix-editor/helix/pull/2507

willparsons avatar Jul 30 '22 23:07 willparsons

Neovim is using https://github.com/hrsh7th/vscode-langservers-extracted for their eslint language server. I'm going to try that same binary in helix

willparsons avatar Jul 30 '22 23:07 willparsons

Hey I tried this approach with the multiple language servers branch and one roadblock that I had faced was that the vscode-langservers-extracted lsp required a property that wasn't provided by Helix.

helix_lsp::transport [ERROR] err <- "(node:13560) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'workingDirectory' of null"

space-shell avatar Jul 31 '22 15:07 space-shell

@space-shell I think you may want to mention that as a new issue?

jacksonludwig avatar Jul 31 '22 16:07 jacksonludwig

Does anyone know if its possible to use eslint just as the linter?

wparsonsheins-globality avatar Aug 24 '22 11:08 wparsonsheins-globality

@archseer there is also an eslint language server. It is quite common nowadays to use it along with tsserver, which is what vscode does.

It allows code actions to fix eslint issues. It even can act as a super fast code formatter by reading your prettier rules.

It is available on npm: https://github.com/hrsh7th/vscode-langservers-extracted

Hi @jacksonludwig, could you explain how to configure the eslint language server in the languages.toml file?

RilDev avatar Sep 15 '22 13:09 RilDev

@RilDev I am not sure, I can see there is an issue about it https://github.com/helix-editor/helix/issues/3520, I've not set it up myself with helix.

jacksonludwig avatar Sep 15 '22 22:09 jacksonludwig

Not a useful comment, but this is the only one thats preventing me from using this editor. Somehow I could not get prettier also working, but thats may be my fault.

pvamshi avatar Oct 15 '22 07:10 pvamshi

same, are there any updates or a release date for this feature?

Trying to have the same behavior as neovim and vscode for eslint vscode-eslint-language-server doesn't seem to work unless someone can point me in the right direction.

btctrl avatar Jan 31 '23 20:01 btctrl

https://github.com/helix-editor/helix/pull/2507 will make it happen. It's in the current milestone.

cd-a avatar Feb 01 '23 05:02 cd-a

Now that #2507 has been merged, does anyone have an example config of how to setup eslint?

amritk avatar Sep 07 '23 08:09 amritk

Alright I found a working config, just waiting for code actions on save to have it work on save

# Front-end
[[language]]
name = "typescript"
scope = "source.ts"
injection-regex = "(ts|typescript)"
language-servers = [{except-features = ["format"], name = "typescript-language-server"}, "tailwindcss-react", "eslint"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json", ""]
file-types = ["ts", "mts", "cts"]
formatter = { command = 'prettier', args = ["--stdin-filepath", "file.ts"] }
auto-format = true

[[language]]
language-servers = [{except-features = ["format"], name = "typescript-language-server"}, "tailwindcss-react", "eslint"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
name = "javascript"
scope = "source.js"
injection-regex = "(js|javascript)"
file-types = ["js", "mjs", "cjs"]
formatter = { command = 'prettier', args = ["--stdin-filepath", "file.js"] }
auto-format = true

[[language]]
language-servers = [{except-features = ["format"], name = "typescript-language-server"}, "tailwindcss-react", "eslint"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
name = "jsx"
scope = "source.jsx"
injection-regex = "jsx"
file-types = ["jsx"]
formatter = { command = 'prettier', args = ["--stdin-filepath", "file.jsx"] }
indent = { tab-width = 4, unit = "\t" }
auto-format = true

[[language]]
language-servers = [{except-features = ["format"], name = "typescript-language-server"}, "tailwindcss-react" , "eslint"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
name = "tsx"
scope = "source.tsx"
injection-regex = "(tsx)" # |typescript
file-types = ["tsx"]
formatter = { command = 'prettier', args = ["--stdin-filepath", "file.tsx"] }
auto-format = true

[[language]]
name = "html"
scope = "text.html.basic"
injection-regex = "html"
file-types = ["html"]
language-servers = ["tailwindcss-react","vscode-html-language-server"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
auto-format = true

[[language]]
name = "css"
scope = "source.css"
injection-regex = "css"
file-types = ["css"]
language-servers = ["tailwindcss-react", "vscode-css-language-server"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
auto-format = true

[language-server.tailwindcss-react]
language-id = "javascriptreact"
command = "hx-tw"
config = { }
args = ["--stdio"]
timeout = 3

[language-server.eslint]
args = ["--stdio"]
command = "vscode-eslint-language-server"

[language-server.eslint.config]
validate = "on"
experimental = { useFlatConfig = false }
rulesCustomizations = []
run = "onType"
problems = { shortenToSingleLine = false }
nodePath = ""

[language-server.eslint.config.codeAction]
[language-server.eslint.config.codeAction.disableRuleComment]
enable = true
location = "separateLine"

[language-server.eslint.config.codeAction.showDocumentation]
enable = true

[language-server.eslint.config.codeActionOnSave]
enable = true
mode = "fixAll"

[language-server.eslint.config.workingDirectory]
mode = "location"

[language-server.typescript-language-server]
args = ["--stdio"]
command = "typescript-language-server"

[language-server.typescript-language-server.config]
documentFormatting = false

amritk avatar Sep 07 '23 17:09 amritk

@amritk, helix has just been a splendid example of how to design a powerful editor like nvim but without nvim's notorious difficulty to configure, which lead to the creation of various nvim distributions (not that I don't like the configurability but only when I need to deviate from the OOB experience which should just work for any language supported that is installed). I just hope that helix won't have distributions created like this in the future.

I think that in order to achieve this, stuff like that configuration you pasted above, should be included by default in helix.

Thanks to your config, I got React/TS/ESLint+Prettier to work just as it does in VSCode. Here's my config. I think the number of deviations from the standard configs of these tools/LSPs should be kept to a minimum, so the standard behavior can become the baseline. For example even helix docs suggests we don't need to set any args for prettier: https://github.com/helix-editor/helix/wiki/External-formatter-configuration#prettier

[language-server.eslint]
args = ["--stdio"] # should come by def with helix
command = "vscode-eslint-language-server"

[language-server.eslint.config]
validate = "on" # I assume this enabled eslit to validate the file, which now shows me counts for errors, warnings, etc in helix
experimental = { useFlatConfig = false } # not sure why this is here
rulesCustomizations = []
run = "onType"
problems = { shortenToSingleLine = false }
nodePath = "" # seems redundant, why do we need to override this, should get detected autom.

[language-server.eslint.config.codeAction]
[language-server.eslint.config.codeAction.disableRuleComment]
enable = true
location = "separateLine"

[language-server.eslint.config.codeAction.showDocumentation]
enable = true # why?

[language-server.eslint.config.codeActionOnSave]
enable = true
mode = "fixAll"

[language-server.eslint.config.workingDirectory]
mode = "location" # do we need to override this?

[language-server.typescript-language-server.config]
documentFormatting = false # use eslint instead, do we have to override this ourselves? I think if eslint LSP is detected and enabled, this should be done automatically for us as generally everyone lets eslint take over linting+prettying, which uses prettier by default if detected by it

[[language]]
name = "typescript"
language-servers = [{ except-features = ["format"], name = "typescript-language-server" }, "eslint"] # shouldn't need to override this
roots = ["package-lock.json", "tsconfig.json", ".prettierrc.json"] # shouldn't need to override this
formatter = { command = "prettier" }
auto-format = true

[[language]]
name = "tsx"
language-servers = [{ except-features = ["format"], name = "typescript-language-server" }, "eslint"] # shouldn't need to override this
roots = ["package-lock.json", "tsconfig.json", ".prettierrc.json"] # shouldn't need to override this!
formatter = { command = "prettier" } # works without any args, the modifications end up in the buffer, unsaved
auto-format = true

brokenthorn avatar Jan 04 '24 12:01 brokenthorn

When i try to add eslint as language server it complains that it couldn't read the tsconfig.json file. It searched in the wrong folder.
My eslintConfig is part of the package.json.

N4tus avatar Apr 10 '24 21:04 N4tus