# Alternate implementation for spell checker

**URL:** <https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781>\
**Category:** Plugins\
**Tags:** plugins\
**Created:** [November 7, 2019, 4:41pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781 "2019-11-07T16:41:43Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [November 7, 2019, 4:41pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/1 "2019-11-07T16:41:43Z")

</div>

Hi,

Frustrated by some limitations of the default spell plugin, I decided to try and rewrite it from scratch to make it more flexible and hackable - which involves writing as little KakScript as possible (for me at least)

# Features

- leverage existing lint.kak plugin for jumping to mistakes
- show a menu with suggestions
- **New** : add and remove kakoune selections to and from personal word list - this is what I missed the most when coming from vim
- **New** : use any backend supported by enchant, not just aspell

# Enough talk, show me the code!

There are two parts:

The first part is a [Python script](https://github.com/dmerejkowsky/kak-spell) that wraps enchant:

Note that the logic to display the kakoune completion menu is implemented there, where it is easy to test/debug 🙂

The second part is a rewrite from scratch of the spell.kak implementation. You can see the diff [on GitHub](https://github.com/dmerejkowsky/kakoune/commit/457b1aff6c3a11ebe9594f8d492ffe3c8a8c1689?diff=split)

I hope you’ll agree it’s easier to read, maintain and extend.

# Future work

Right now the plugin can only be used by patching the code of kakoune and installing a separate python project (and deal with pyenchant)

This not ideal, so if you like the idea of such a plugin and its implementation, feel free to tell me below and we can discuss easier ways to distribute the plugin - I kinda like the idea of just a Rust binary, _ala_ kak-slp.

Also, I’m pretty satisfied with the features so far, but let me know if you have requests that would be hard to implement in the original spell.kak plugin (besides checking several languages at once - this is sadly not supported by Enchant)

Cheers!

---

<div class="post-metadata">

**Author:** ![JJK96](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/jjk96/32/305_2.png) [@JJK96](https://discuss.kakoune.com/u/JJK96)\
**Post date:** [November 7, 2019, 8:51pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/2 "2019-11-07T20:51:55Z")

</div>

I will test with it soon, it sounds very promising!  
For distributing I suggest that you put it into a git repository so that it can be loaded by [plug.kak](https://github.com/andreyorst/plug.kak)

> The second part is a rewrite from scratch of the plug.kak implementation.

You mean of the spell.kak implementation?

---

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [November 7, 2019, 10:28pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/3 "2019-11-07T22:28:46Z")

</div>

> You mean of the spell.kak implementation?

Woops sorry 🙂 My mind was already thinking about distribution and `plug.kak` was typed …

---

<div class="post-metadata">

**Author:** ![duncan](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/duncan/32/95_2.png) [@duncan](https://discuss.kakoune.com/u/duncan)\
**Post date:** [January 4, 2020, 7:07pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/4 "2020-01-04T19:07:44Z")

</div>

I am going to give this a run, currently using [dictcomplete.kak](https://github.com/lenormf/kakoune-extra/blob/master/dictcomplete.kak). I’ll be back, bye.

---

<div class="post-metadata">

**Author:** ![duncan](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/duncan/32/95_2.png) [@duncan](https://discuss.kakoune.com/u/duncan)\
**Post date:** [January 19, 2020, 12:20am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/5 "2020-01-19T00:20:08Z")

</div>

A stumbling block for me is `lint-on-save` cannot find any reference to this command. Can you please explain its purpose, usage, or help me if I am doing something wrong. Thanks Dmere.

> <https://github.com/dmerejkowsky/kakoune/blob/master/rc/base/spell.kak#L19>

---

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [January 19, 2020, 10:36am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/6 "2020-01-19T10:36:27Z")

</div>

> A stumbling block for me is `lint-on-save`

Woops, sorry. This is a command that adds a hook to call `:lint` when the buffer is saved.

Here is its implementation:

```auto
define-command lint-on-save "hook buffer BufWritePre .* lint"

```

It lives in my kakrc config file and I forgot that kak-spell depended on it …

---

<div class="post-metadata">

**Author:** ![duncan](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/duncan/32/95_2.png) [@duncan](https://discuss.kakoune.com/u/duncan)\
**Post date:** [January 28, 2020, 8:36am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/7 "2020-01-28T08:36:48Z")

</div>

Thank you. I’ll be back with some feedback or more questions, probably both 😄

---

<div class="post-metadata">

**Author:** ![duncan](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/duncan/32/95_2.png) [@duncan](https://discuss.kakoune.com/u/duncan)\
**Post date:** [February 22, 2020, 3:39pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/8 "2020-02-22T15:39:54Z")

</div>

A little more hand-holding please, after viewing the pictures below to double-check the setup is correct. The problem is I get a _lint-output_ debug buffer with no corresponding errors, regardless of the buffers contents which I have just parsed with kak-spell.

Obviously, this is an incorrect setup issue on my behalf, is there a pitfall that I may be unaware of?

As always any help you can provide is appreciated.

> **Summary**
>
> ![enchant-kak](https://discuss.kakoune.com/uploads/default/original/1X/f37bdb3c6944032a7ea3b8e89bae1b2c8d55babf.png)

> **Summary**
>
> ![enchant-kak-file](https://discuss.kakoune.com/uploads/default/original/1X/e3ab2d7624c9686d6f99ae9ee71e1f60da05e694.png)

I have `$kak_opt_spell_lang` hard coded to `en-AU`.  
`aspell` is also installed on the machine.

---

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [February 22, 2020, 4:35pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/9 "2020-02-22T16:35:33Z")

</div>

You can try running `kak-spell` directly from the command line and see what happens:

```auto
kak-spell --lang en_AU check path/to/file

```

Fun fact: I’m also the maintainer of PyEnchant, and you may want to upgrade to the latest 3.0 release candidate:

```auto
python3 -m pip install enchant==3.0.0rc3

```

---

<div class="post-metadata">

**Author:** ![duncan](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/duncan/32/95_2.png) [@duncan](https://discuss.kakoune.com/u/duncan)\
**Post date:** [February 24, 2020, 7:26pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/10 "2020-02-24T19:26:49Z")

</div>

Thanks, I had to go with a work around as my last major use with python was 3 years ago.

I maintained the above `dmerejkowsky.kak` file and just replaced every occurrence of `kak-spell …` with:  
`python3 $kak_config/plugins/kak-spell/kak_spell/cli.py …`  
and updated the `cli.py` line 8 `from .checker import Checker` to `from checker import Checker` just removing the `.` seemed to do the trick.

Take a look at this [readme](https://bitbucket.org/KJ_Duncan/shellit.kak/src/master/README.md)’s Building, Installing sections and [graalvm](https://bitbucket.org/KJ_Duncan/shellit.kak/src/master/GRAALVM.md). If a user has limited or no experience with gradle, java, or graalvm it wouldn’t be problematic to use this repo.

I’m not saying this is what you _have too_ or _should do_, we’re all friends, so just some positive feedback on some teething pains I had to get going with `kak-spell`. It’s a good problem, as you have expanded my knowledge with `enchant` spell-checker.

Which I have still implemented incorrectly ☹. But it now works 🙂.

Thanks dmerejkowsky.

I worked out this coexistence with inbuilt `spell` which may help out:  
`define-command lint-on-save "hook buffer BufWritePre .*[.](md|markdown) lint"`  
I can now use your/my adapted `enchant-spell` and the default `spell` on the same buffer without `lintcmd` conflicts.

---

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [February 24, 2020, 7:53pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/11 "2020-02-24T19:53:29Z")

</div>

Yeah, I really should tackle the “future work” one day or another …

I guess I could _at least_ take the time to properly release the project on `pypi.org` so it gets easier to install - but to do _that_ I need to finish working on the 3.0 release of PyEnchant itself.

> [@duncan](#):
>
> It’s a good problem, as you have expanded my knowledge with `enchant` spell-checker.

Well, that’s a very nice way to put it. Thank you.

---

<div class="post-metadata">

**Author:** ![duncan](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/duncan/32/95_2.png) [@duncan](https://discuss.kakoune.com/u/duncan)\
**Post date:** [February 25, 2020, 2:33am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/12 "2020-02-25T02:33:44Z")

</div>

Cool, I did a little digging into [Poetry](https://pypi.org/project/poetry/) something I am defiantly going to look at in more depth. Thanks again.

---

<div class="post-metadata">

**Author:** ![JJK96](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/jjk96/32/305_2.png) [@JJK96](https://discuss.kakoune.com/u/JJK96)\
**Post date:** [February 27, 2020, 11:45am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/13 "2020-02-27T11:45:44Z")

</div>

I finally got around to testing this.  
I had to do a few extra steps to get it working.

1. Install the python module `path`.
2. Adapt the source code of `spell.kak` to make it up to date with the changes in `lint.kak`. And to actually call `python cli.py` instead of `kak-spell` which does not yet exist.

To make distribution a bit easier, [this folder](https://gofile.io/?c=6sXDht) can simply be put into your autoload directory to enable the plugin.

I added some configuration which makes it easier for me to use:

```auto
    set-option global spell_lang en
    declare-user-mode spell
    map global spell -docstring "Enable" e ': spell %opt{spell_lang}<ret>'
    map global spell -docstring "Lint" u ': lint-buffer<ret>'
    map global spell -docstring "Next" n ': lint-next-message<ret>'
    map global spell -docstring "Replace" r ': spell-replace<ret>'
    map global spell -docstring "Clear" c ': spell-clear<ret>'

```

Problems/suggestions:

`lint-next-message` does not jump to the correct column, which makes it harder to see which word is actually wrong, and you have to manually jump to it to replace it. I have not looked into it to check if this is a `lint.kak` or a `kak-spell` issue.

I would suggest that you make a separate git repository with as contents the folder I provided.  
It might also be a good idea to add a default `spell_lang` and declare a user mode as shown above.

---

<div class="post-metadata">

**Author:** ![Screwtapello](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/screwtapello/32/12_2.png) [@Screwtapello](https://discuss.kakoune.com/u/Screwtapello)\
**Post date:** [February 27, 2020, 12:33pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/14 "2020-02-27T12:33:41Z")

</div>

> [@JJK96](#):
>
> `lint-next-message` does not jump to the correct column, which makes it harder to see which word is actually wrong, and you have to manually jump to it to replace it.

Previously, `lint.kak` stored lint messages in a `range-specs` option, which included a line and column for both the start and end points… but it didn’t have end point information, so it set the end point to the same as the start point. And then it didn’t really use the column of the start-point either, it always displayed the lint message next to the cursor. So I simplified the whole thing to use a `line-specs` option instead, which only stores line numbers.

It’d be neat to generalise `lint.kak` to support all the common variants of the traditional Unix diagnostic format:

```
filename:line: message
filename:line:column: message
filename:line:column:line:column: message

```

…but that’s a job for a future contributor, I think.

---

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [February 28, 2020, 10:24am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/15 "2020-02-28T10:24:39Z")

</div>

> So I simplified the whole thing to use a `line-specs` option instead, which only stores line numbers.

I don’t follow. Did you change kak-sepll.kak or lint.kak ?

Should we fix the output of kak-spell to contain start and end columns ?

---

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [February 28, 2020, 10:30am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/16 "2020-02-28T10:30:47Z")

</div>

Anyway, I published `kak-spell` on [pypi.org](http://pypi.org), which makes its installation much easier, and adapted the README.

Thank you everyone for your kind words and suggestions.

Hopefully installation should be much more smooth now.

@JJK96 I think that mappings do not belong in the plugin itself so I just left them in the README

---

<div class="post-metadata">

**Author:** ![Screwtapello](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/screwtapello/32/12_2.png) [@Screwtapello](https://discuss.kakoune.com/u/Screwtapello)\
**Post date:** [February 28, 2020, 10:43am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/17 "2020-02-28T10:43:42Z")

</div>

> [@dmerejkowsky](#):
>
> Did you change kak-sepll.kak or lint.kak ?
> 
> Should we fix the output of kak-spell to contain start and end columns ?

I [rewrote large chunks of `lint.kak`](https://github.com/mawww/kakoune/pull/3347). The new version has mostly the same API, except that `lint-{next,previous}-error` has become `lint-{next,previous}-message`, and the `lint_errors` option (of type `range-specs`) has become the `lint_messages` option (of type `line-specs`).

If your plugin is just setting `lintcmd` and running `:lint` or `:lint-buffer`, you should be fine and shouldn’t need to change anything.

---

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [February 28, 2020, 10:45am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/18 "2020-02-28T10:45:08Z")

</div>

Cool 🙂

---

<div class="post-metadata">

**Author:** ![JJK96](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/jjk96/32/305_2.png) [@JJK96](https://discuss.kakoune.com/u/JJK96)\
**Post date:** [February 28, 2020, 12:07pm UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/19 "2020-02-28T12:07:43Z")

</div>

Nice that it is published in an easier way now!

I think the reference lint-on-save command should either be left out of the kak-spell.kak file or the implementation should be included, possibly with a setting so you can set it on or off in your configuration.

Currently the code depends on the lint-on-save command being defined, which is not a good idea IMO.

---

<div class="post-metadata">

**Author:** ![dmerejkowsky](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/dmerejkowsky/32/696_2.png) [@dmerejkowsky](https://discuss.kakoune.com/u/dmerejkowsky)\
**Post date:** [April 13, 2020, 11:44am UTC](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781/20 "2020-04-13T11:44:03Z")

</div>

So, it turns out that the latest changes in `lint.kak` broke my plugin. See this example:

```nohighlight
this is some text
there is two spellig errors herre

```

With the latest`lint.kak`, I get a line-spec on line 2, but what I need are two range specs to select `spellig` and `herre`

I’ve just published version 0.2.1. where I’ve rewritten the plugin to not depend on `lint.kak` at all.  
See [the changelog](https://github.com/dmerejkowsky/kak-spell/blob/master/CHANGELOG.md) for more details - I had to make a few breaking changes.

[Next page](https://discuss.kakoune.com/t/alternate-implementation-for-spell-checker/781.md?page=2)
