null-ls.nvim icon indicating copy to clipboard operation
null-ls.nvim copied to clipboard

feat: add cspell suggestions to code actions

Open yoo opened this issue 2 years ago • 7 comments

Add a new cspell code action builtin. When triggering code actions on a line with cspell diagnostic errors (misspelled words) show spelling suggestions in the code actions menu.

This is the followup to #909.

Example: The line dhis menue shows the code actions:

Fix dhis -> chis
Fix dhis -> dais
Fix dhis -> phis
Fix dhis -> this
Fix menue -> Benue
Fix menue -> mene
Fix menue -> menu
Fix menue -> menus
Fix menue -> venue

I'm not happy with the design yet. To generate the suggestions the command cspell sug --num-suggestions=4 dhis menue is run. Running the process takes some time and vim blocks while the command is running.

My preferred solution would be: Generate the suggestions while the cspell diagnostic builtin is run and the cspell code action builtin reads the suggestions from some sort of cache. But I have no idea how to communicate between the two builtins, any ideas?

yoo avatar Jun 13 '22 17:06 yoo

I like this idea. If we could generate diagnostics and suggestions together (and assuming it doesn't significantly add to the time it takes to run the command) we could actually store the suggestion data under the user_data key (see :h diagnostic-structure) and retrieve it by adapting the logic you're already using.

Since it looks like we'll have to depend on diagnostics in the first place, I think this would be the simplest way to handle it. This would require adapting the existing cspell source, and after playing around with it a bit, I wasn't able to get it to generate suggestions and diagnostics in a single command, but if you can figure it out, I think that would be the way to go.

jose-elias-alvarez avatar Jun 13 '22 21:06 jose-elias-alvarez

Spelling suggestions are now generated by the diagnostics cspell builtin. The code actions cspell builtin retrieves the suggestions from the user_data property of the diagnostic.

The next question is if the code action message format is fine Fix dhis -> this? And adding documentation.

When this PR is accepted I would close #909 and follow up cspell configuration and custom dictionaries in other PRs.

yoo avatar Jun 19 '22 13:06 yoo

I have changed the behavior a little bit. You need to be on the misspelled word to show the code action, and only the suggestion for the word under the cursor is displayed.

yoo avatar Jul 23 '22 20:07 yoo

@yoo I've been using your branch, so far so good. How hard would be to add an option to the suggestion like "Add word to cspell.json"? I would love to contribute.

Edit: I added the following to your snippet, it does the trick and appends the word to the .json file.

                -- add word to "words" in cspell.json
                table.insert(actions, {
                    title = "Add to cspell.json",
                    action = function()
                        local word = vim.api.nvim_buf_get_text(
                            diagnostic.bufnr,
                            diagnostic.lnum,
                            diagnostic.col,
                            diagnostic.end_lnum,
                            diagnostic.end_col,
                            {}
                        )[1]
                        local cspell_json = vim.fn.findfile("cspell.json", vim.fn.getcwd() .. ";")
                        if cspell_json == "" then
                            vim.notify("\ncspell.json not found", vim.log.levels.WARN)
                            return
                        end
                        local cspell = vim.fn.json_decode(vim.fn.readfile(cspell_json))
                        if not cspell.words then
                            cspell.words = {}
                        end
                        table.insert(cspell.words, word)
                        local json = vim.fn.json_encode(cspell)
                        vim.fn.writefile({ json }, cspell_json)

                        -- replace word in buffer to trigger cspell to update diagnostics
                        vim.api.nvim_buf_set_text(
                            diagnostic.bufnr,
                            diagnostic.lnum,
                            diagnostic.col,
                            diagnostic.end_lnum,
                            diagnostic.end_col,
                            { word }
                        )
                    end,
                })

marianozunino avatar Sep 11 '22 10:09 marianozunino

The suggestions are now only generated if the cspell code actions builtin is enabled. And added documentation.

yoo avatar Sep 11 '22 13:09 yoo

@marianozunino I would do this in a follow-up PR.

My thoughts: Set the path to the config.json as a config option. This way, the user can decide if they want a single global config file or lookup the current path.

yoo avatar Sep 11 '22 13:09 yoo

As for adding words, vscode extension also supports dictionaries

Example: 2022-09-11_14-53

flytaly avatar Sep 11 '22 13:09 flytaly

Are there any updates on this feature?

PumpedSardines avatar Oct 01 '22 15:10 PumpedSardines

I went ahead and moved the documentation to the source definition, and otherwise I think this is good to go. Thanks!

jose-elias-alvarez avatar Oct 04 '22 14:10 jose-elias-alvarez

Hurray, thanks a lot for this feature!

PumpedSardines avatar Oct 05 '22 07:10 PumpedSardines

@yoo I've been using your branch, so far so good. How hard would be to add an option to the suggestion like "Add word to cspell.json"? I would love to contribute.

Edit: I added the following to your snippet, it does the trick and appends the word to the .json file.

                -- add word to "words" in cspell.json
                table.insert(actions, {
                    title = "Add to cspell.json",
                    action = function()
                        local word = vim.api.nvim_buf_get_text(
                            diagnostic.bufnr,
                            diagnostic.lnum,
                            diagnostic.col,
                            diagnostic.end_lnum,
                            diagnostic.end_col,
                            {}
                        )[1]
                        local cspell_json = vim.fn.findfile("cspell.json", vim.fn.getcwd() .. ";")
                        if cspell_json == "" then
                            vim.notify("\ncspell.json not found", vim.log.levels.WARN)
                            return
                        end
                        local cspell = vim.fn.json_decode(vim.fn.readfile(cspell_json))
                        if not cspell.words then
                            cspell.words = {}
                        end
                        table.insert(cspell.words, word)
                        local json = vim.fn.json_encode(cspell)
                        vim.fn.writefile({ json }, cspell_json)

                        -- replace word in buffer to trigger cspell to update diagnostics
                        vim.api.nvim_buf_set_text(
                            diagnostic.bufnr,
                            diagnostic.lnum,
                            diagnostic.col,
                            diagnostic.end_lnum,
                            diagnostic.end_col,
                            { word }
                        )
                    end,
                })

@marianozunino @yoo was this feature officially implemented? — thanks for this (love cspell)

juanpprieto avatar Dec 19 '22 18:12 juanpprieto

@juanpprieto There is an open PR - see #1154.

jose-elias-alvarez avatar Dec 19 '22 18:12 jose-elias-alvarez