jose-elias-alvarez / null-ls.nvim

Use Neovim as a language server to inject LSP diagnostics, code actions, and more via Lua.
Other
3.62k stars 791 forks source link

Add support for HTMLHint diagnostics #299

Open theSafdarAwan opened 2 years ago

theSafdarAwan commented 2 years ago

Issues

Feature description

i tried to add a custom linter for html [htmlhint] i don't have deep understanding of the nvim so i read the wiki and then tried to add the html hint as a linter for html this is the table for htmlhint i don't know it attaches the htmlhint to the html files but does not gives me the dignostics https://github.com/imSafdarAwan/Dfiles/blob/19a6c7282a5f78cf0a3fa4d367c3127ef4327f85/nvim/.config/nvim/lua/lsp/null_ls.lua#L35

Help

Yes, but I don't know how to start. I would need guidance

Implementation help

just need to know what mistake i am making or maybe some additional resources i could read and learn about this and implement it [NOTE: i am trying to dig deep into the nvim i recently started learning lua and i would be happy if you recomend some resources for me to learn about these things]

jose-elias-alvarez commented 2 years ago

The issue is that your parser isn't correctly parsing the output from htmlhint. The default format isn't easy to parse, so I'd recommend using the JSON output format and parsing the output from there. This should get you started:

local htmlhint = helpers.make_builtin({
    method = null_ls.methods.DIAGNOSTICS,
    filetypes = { "html" },
    generator_opts = {
        command = "htmlhint",
        args = { "--format", "json" },
        to_stdin = true,
        from_stderr = true,
        format = "json",
        on_output = function(params)
            -- params.output contains the parsed JSON diagnostics
            print(vim.inspect(params))
        end,
    },
    factory = helpers.generator_factory,
})

Your on_output function should then return a table of diagnostics, as described here. We have a few other built-ins in the repository that can show you how to do this.

theSafdarAwan commented 2 years ago

The issue is that your parser isn't correctly parsing the output from htmlhint. The default format isn't easy to parse, so I'd recommend using the JSON output format and parsing the output from there. This should get you started:

local htmlhint = helpers.make_builtin({
    method = null_ls.methods.DIAGNOSTICS,
    filetypes = { "html" },
    generator_opts = {
        command = "htmlhint",
        args = { "--format", "json" },
        to_stdin = true,
        from_stderr = true,
        format = "json",
        on_output = function(params)
            -- params.output contains the parsed JSON diagnostics
            print(vim.inspect(params))
        end,
    },
    factory = helpers.generator_factory,
})

Your on_output function should then return a table of diagnostics, as described here. We have a few other built-ins in the repository that can show you how to do this.

so i have copied some of the thing's from the source code of the null ls as you said it should return a table of to from the json this is what i was doing and still doe's not work's can you poin't me at the documentation or something so i can uderstand how i can parse the json format to the nvim client this is what i have done https://github.com/imSafdarAwan/Dfiles/blob/234cf43976077af0579f810b0624ecda30e32dca/nvim/.config/nvim/lua/lsp/null_ls.lua#L65

jose-elias-alvarez commented 2 years ago

There's no standard output format – you can't just copy-paste what a different linter is using. You need to look at the actual format of the JSON output for your specific linter and figure out how each value corresponds to what null-ls needs:

local htmlhint = helpers.make_builtin({
    method = null_ls.methods.DIAGNOSTICS,
    filetypes = { "html" },
    generator_opts = {
        command = "htmlhint",
        args = { "--format", "json" },
        to_stdin = true,
        from_stderr = true,
        format = "json",
        on_output = function(params)
            local diagnostics = {}
            for _, diagnostic in ipairs(params.output[1].messages) do
                --[[ {
                  col = 1,
                  evidence = "<!--comment--><!DOCTYPE html>",
                  line = 1,
                  message = "Doctype must be declared first.",
                  raw = "<!--comment-->",
                  rule = {
                    description = "Doctype must be declared first.",
                    id = "doctype-first",
                    link = "https://github.com/thedaviddias/HTMLHint/wiki/doctype-first"
                  },
                  type = "error"
                } --]]
                print(vim.inspect(diagnostic))
            end
            return diagnostics
        end,
    },
    factory = helpers.generator_factory,
})
ebiscaia commented 1 year ago

Hi,

I would like to know if there is any chance of making it native as tidy seems to be lacking in some features.

Thanks,

Eddie

polyzen commented 1 year ago

An alternative: https://yeonjuan.github.io/html-eslint/

ebiscaia commented 1 year ago

Hi mate,

Unless I am missing anything this one has the same problem of HTMLHint as it isn't in NullLS list.

Thanks,

Eddie

polyzen commented 1 year ago
null_ls.builtins.code_actions.eslint.with({
  filetypes = { 'html' },
  prefer_local = 'node_modules/.bin',
  condition = function(utils)
    return utils.root_has_file({ 'node_modules' }
  end,
}),
null_ls.builtins.diagnostics.eslint.with({
  filetypes = { 'html' },
  prefer_local = 'node_modules/.bin',
  condition = function(utils)
    return utils.root_has_file({ 'node_modules' })
  end,
}),
ebiscaia commented 1 year ago

Hi mate,

Just in case, where is your eslint installed?

I installed mine with the plugins in /opt/eslint and added that to prefer_local and nothing.

cheers

polyzen commented 1 year ago
null_ls.builtins.code_actions.eslint.with({
  filetypes = { 'html' },
  prefer_local = 'node_modules/.bin',
  condition = function(utils)
    return utils.root_has_file({ 'node_modules' }
  end,
}),
null_ls.builtins.diagnostics.eslint.with({
  filetypes = { 'html' },
  prefer_local = 'node_modules/.bin',
  condition = function(utils)
    return utils.root_has_file({ 'node_modules' })
  end,
}),

Actually this can be simplified to:

null_ls.builtins.code_actions.eslint.with({
  filetypes = { 'html' },
  only_local = 'node_modules/.bin',
}),
null_ls.builtins.diagnostics.eslint.with({
  filetypes = { 'html' },
  only_local = 'node_modules/.bin',
}),
polyzen commented 1 year ago

Hi mate,

Just in case, where is your eslint installed?

I installed mine with the plugins in /opt/eslint and added that to prefer_local and nothing.

cheers

Installed local to the project, in ./node_modules/.

ebiscaia commented 1 year ago

Thanks, mate