Skip to content

Instantly share code, notes, and snippets.

@lbiaggi
Last active October 20, 2023 19:27
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lbiaggi/a3eb761ac2fdbff774b29c88844355b8 to your computer and use it in GitHub Desktop.
Save lbiaggi/a3eb761ac2fdbff774b29c88844355b8 to your computer and use it in GitHub Desktop.
ltex-ls support WIP
--- BEFORE USING, change language entries to fit your needs.
local lspconfig = require'lspconfig'
local configs = require'lspconfig/configs'
local util = require 'lspconfig/util'
local Dictionary_file = {
["pt-BR"] = {vim.fn.getenv("NVIM_HOME") .. "spell/dictionary.txt"} -- there is another way to find ~/.config/nvim ?
}
local DisabledRules_file = {
["pt-BR"] = {vim.fn.getenv("NVIM_HOME") .. "spell/disable.txt"} -- there is another way to find ~/.config/nvim ?
}
local FalsePositives_file = {
["pt-BR"] = {vim.fn.getenv("NVIM_HOME") .. "spell/false.txt"} -- there is another way to find ~/.config/nvim ?
}
local function readFiles(files)
local dict = {}
for _,file in ipairs(files) do
local f = io.open(file, "r")
for l in f:lines() do
table.insert(dict, l)
end
end
return dict
end
local function findLtexLang()
local buf_clients = vim.lsp.buf_get_clients()
for _, client in ipairs(buf_clients) do
if client.name == "ltex" then
return client.config.settings.ltex.language
end
end
end
local function findLtexFiles(filetype, value)
local files = nil
if filetype == 'dictionary' then
files = Dictionary_file[value or findLtexLang()]
elseif filetype == 'disable' then
files = DisabledRules_file[value or findLtexLang()]
elseif filetype == 'falsePositive' then
files = FalsePositives_file[value or findLtexLang()]
end
if files then
return files
else
return nil
end
end
local function updateConfig(lang, configtype)
local buf_clients = vim.lsp.buf_get_clients()
local client = nil
for _, lsp in ipairs(buf_clients) do
if lsp.name == "ltex" then
client = lsp
end
end
if client then
if configtype == 'dictionary' then
if client.config.settings.ltex.dictionary then
client.config.settings.ltex.dictionary = {
[lang] = readFiles(Dictionary_file[lang])
};
return client.notify('workspace/didChangeConfiguration', client.config.settings)
else
return vim.notify("Error when reading dictionary config, check it")
end
elseif configtype == 'disable' then
if client.config.settings.ltex.disabledRules then
client.config.settings.ltex.disabledRules = {
[lang] = readFiles(DisabledRules_file[lang])
};
return client.notify('workspace/didChangeConfiguration', client.config.settings)
else
return vim.notify("Error when reading disabledRules config, check it")
end
elseif configtype == 'falsePositive' then
if client.config.settings.ltex.hiddenFalsePositives then
client.config.settings.ltex.hiddenFalsePositives = {
[lang] = readFiles(FalsePositives_file[lang])
};
return client.notify('workspace/didChangeConfiguration', client.config.settings)
else
return vim.notify("Error when reading hiddenFalsePositives config, check it")
end
end
else
return nil
end
end
local function addToFile(filetype, lang, file, value)
file = io.open(file[#file-0], "a+") -- add only to last file defined.
if file then
file:write(value .. "\n")
file:close()
else
return print("Failed insert %q", value)
end
if filetype == 'dictionary' then
return updateConfig(lang, "dictionary")
elseif filetype == 'disable' then
return updateConfig(lang, "disable")
elseif filetype == 'falsePositive' then
return updateConfig(lang, "disable")
end
end
local function addTo(filetype, lang, file, value)
local dict = readFiles(file)
for _, v in ipairs(dict) do
if v == value then
return nil
end
end
return addToFile(filetype, lang, file, value)
end
if not lspconfig.ltex then
configs.ltex = {
default_config = {
cmd = {"ltex-ls"};
filetypes = {'tex', 'bib', 'md'};
root_dir = function(filename)
return util.path.dirname(filename)
end;
settings = {
ltex = {
enabled= {"latex", "tex", "bib", "md"},
checkFrequency="save",
language="pt-BR",
diagnosticSeverity="information",
setenceCacheSize=5000,
additionalRules = {
enablePickyRules = true,
motherTongue= "pt-BR",
};
-- trace = { server = "verbose"};
-- ['ltex-ls'] = {
-- logLevel = "finest",
-- },
dictionary = {
["pt-BR"] = readFiles(Dictionary_file["pt-BR"] or {}),
};
disabledRules = {
["pt-BR"] = readFiles(DisabledRules_file["pt-BR"] or {}),
};
hiddenFalsePositives = {
["pt-BR"] = readFiles(FalsePositives_file["pt-BR"] or {}),
};
},
};
};
};
end
lspconfig.ltex.setup{}
lspconfig.ltex.dictionary_file = Dictionary_file
lspconfig.ltex.disabledrules_file = DisabledRules_file
lspconfig.ltex.falsepostivies_file = FalsePositives_file
-- https://github.com/neovim/nvim-lspconfig/issues/858 can't intercept,
-- override it then.
local orig_execute_command = vim.lsp.buf.execute_command
vim.lsp.buf.execute_command = function(command)
if command.command == '_ltex.addToDictionary' then
local arg = command.arguments[1].words -- can I really access like this?
for lang, words in pairs(arg) do
for _, word in ipairs(words) do
local filetype = "dictionary"
addTo(filetype,lang, findLtexFiles(filetype,lang), word)
end
end
elseif command.command == '_ltex.disableRules' then
local arg = command.arguments[1].ruleIds -- can I really access like this?
for lang, rules in pairs(arg) do
for _, rule in ipairs(rules) do
local filetype = "disable"
addTo(filetype,lang,findLtexFiles(filetype,lang), rule)
end
end
elseif command.command == '_ltex.hideFalsePositives' then
local arg = command.arguments[1].falsePositives -- can I really access like this?
for lang, rules in pairs(arg) do
for _, rule in ipairs(rules) do
local filetype = "falsePositive"
addTo(filetype,lang,findLtexFiles(filetype,lang), rule)
end
end
else
orig_execute_command(command)
end
end
@brymer-meneses
Copy link

brymer-meneses commented May 5, 2021

This is awesome!

However, for some reason the function readFiles doesn't seem to work in the latest nightly build for neovim.
But with a few modification I got it to a working state!

local function readFiles(files)
    local dict = {}
    for _,file in ipairs(files) do
        if not file then return nil end

        for line in io.lines(file) do
            table.insert(dict, line)
        end
    end
    return dict
end

BTW you should totally make a PR to nvim-lspconfig!

@VolkovIlia
Copy link

VolkovIlia commented Aug 13, 2021

This is awesome!

However, for some reason the function readFiles doesn't seem to work in the latest nightly build for neovim.
But with a few modification I got it to a working state!

local function readFiles(files)
    local dict = {}
    for _,file in ipairs(files) do
        if not file then return nil end

        for line in io.lines(file) do
            table.insert(dict, line)
        end
    end
    return dict
end

BTW you should totally make a PR to nvim-lspconfig!

Can you wright a few instructions how to use it without nvim-lspconfig?

@lbiaggi
Copy link
Author

lbiaggi commented Aug 13, 2021

This is awesome!

However, for some reason the function readFiles doesn't seem to work in the latest nightly build for neovim.
But with a few modification I got it to a working state!

local function readFiles(files)
    local dict = {}
    for _,file in ipairs(files) do
        if not file then return nil end

        for line in io.lines(file) do
            table.insert(dict, line)
        end
    end
    return dict
end

BTW you should totally make a PR to nvim-lspconfig!

There is a PR there, I'm waiting an interface (I want to avoid maintaining a whole plugin) where I don't need to override execute_command globally.

@lbiaggi
Copy link
Author

lbiaggi commented Aug 13, 2021

This is awesome!
However, for some reason the function readFiles doesn't seem to work in the latest nightly build for neovim.
But with a few modification I got it to a working state!

local function readFiles(files)
    local dict = {}
    for _,file in ipairs(files) do
        if not file then return nil end

        for line in io.lines(file) do
            table.insert(dict, line)
        end
    end
    return dict
end

BTW you should totally make a PR to nvim-lspconfig!

Can you wright a few instructions how to use it without nvim-lspconfig?

Sorry, but can't help you, this is made to work exclusively with nvim-lspconfig, what LSP client do you use?

@VolkovIlia
Copy link

VolkovIlia commented Aug 16, 2021

Sorry, did not find any instruction about your code in nvim-lspconfig page, thought your code is not for lsp-config. Please, share any instructions for integrating your code to lsp-config)))

@lbiaggi
Copy link
Author

lbiaggi commented Aug 16, 2021

Sure,

Enter or neovim home, something like below and download this gist, it is important to create the files where the actions will save exceptions and dict words!, remember to modify the gist to your language.

$ cd $NVIM_HOME
$ mkdir spells && touch spells/diciotionary.txt && touch spells/false.txt && touch spells/disable.txt
$ mkdir lua && cd lua
$ wget https://gist.github.com/lbiaggi/a3eb761ac2fdbff774b29c88844355b8/raw/332d30269e7f009e04e27ea58d1cd7c876af07a5/ltex.lua
$ sed -i s/pt-BR/'YOURLANG'/g ltex.lua

In your config.lua / init.vim load it after loading nvim-lspconfig...
require('ltex') or silent luafile ~/$NVIM_HOME/lua/ltex.lua

Please, remember to change $NVIM_HOME to your path, I define a global one in my shell startup, maybe you need to change it to fit your needs.

@brymer-meneses
Copy link

This is awesome!
However, for some reason the function readFiles doesn't seem to work in the latest nightly build for neovim.
But with a few modification I got it to a working state!

local function readFiles(files)
    local dict = {}
    for _,file in ipairs(files) do
        if not file then return nil end

        for line in io.lines(file) do
            table.insert(dict, line)
        end
    end
    return dict
end

BTW you should totally make a PR to nvim-lspconfig!

There is a PR there, I'm waiting an interface (I want to avoid maintaining a whole plugin) where I don't need to override execute_command globally.

Do you mind if I create a neovim plugin based on this gist?

@lbiaggi
Copy link
Author

lbiaggi commented Aug 20, 2021

Of course not; I am more than glad. I did this to learn the Lua basics, and probably some things could be better. I still lack about how to do a lot of things with neovim.

But I think you should use this one instead.

If I can help with anything, feel free to ping me.

@VolkovIlia
Copy link

VolkovIlia commented Aug 23, 2021

Sure,

Enter or neovim home, something like below and download this gist, it is important to create the files where the actions will save exceptions and dict words!, remember to modify the gist to your language.

$ cd $NVIM_HOME
$ mkdir spells && touch spells/diciotionary.txt && touch spells/false.txt && touch spells/disable.txt
$ mkdir lua && cd lua
$ wget https://gist.github.com/lbiaggi/a3eb761ac2fdbff774b29c88844355b8/raw/332d30269e7f009e04e27ea58d1cd7c876af07a5/ltex.lua
$ sed -i s/pt-BR/'YOURLANG'/g ltex.lua

In your config.lua / init.vim load it after loading nvim-lspconfig...
require('ltex') or silent luafile ~/$NVIM_HOME/lua/ltex.lua

Please, remember to change $NVIM_HOME to your path, I define a global one in my shell startup, maybe you need to change it to fit your needs.

Is it support multiple languages?

@VolkovIlia
Copy link

Sure,

Enter or neovim home, something like below and download this gist, it is important to create the files where the actions will save exceptions and dict words!, remember to modify the gist to your language.

$ cd $NVIM_HOME
$ mkdir spells && touch spells/diciotionary.txt && touch spells/false.txt && touch spells/disable.txt
$ mkdir lua && cd lua
$ wget https://gist.github.com/lbiaggi/a3eb761ac2fdbff774b29c88844355b8/raw/332d30269e7f009e04e27ea58d1cd7c876af07a5/ltex.lua
$ sed -i s/pt-BR/'YOURLANG'/g ltex.lua

In your config.lua / init.vim load it after loading nvim-lspconfig...
require('ltex') or silent luafile ~/$NVIM_HOME/lua/ltex.lua

Please, remember to change $NVIM_HOME to your path, I define a global one in my shell startup, maybe you need to change it to fit your needs.

Made every step but had en error Error detected while processing /home/user/.config/nvim/init.vim
E5108: Error executing lua /home/user/.config/nvim/lua/ltex.lua:21: attempt to index local 'f' (a ni l value)

What I did wrong? ltex-ls is executable and located in PATH...

@lbiaggi
Copy link
Author

lbiaggi commented Aug 23, 2021

Sure,
Enter or neovim home, something like below and download this gist, it is important to create the files where the actions will save exceptions and dict words!, remember to modify the gist to your language.

$ cd $NVIM_HOME
$ mkdir spells && touch spells/diciotionary.txt && touch spells/false.txt && touch spells/disable.txt
$ mkdir lua && cd lua
$ wget https://gist.github.com/lbiaggi/a3eb761ac2fdbff774b29c88844355b8/raw/332d30269e7f009e04e27ea58d1cd7c876af07a5/ltex.lua
$ sed -i s/pt-BR/'YOURLANG'/g ltex.lua

In your config.lua / init.vim load it after loading nvim-lspconfig...
require('ltex') or silent luafile ~/$NVIM_HOME/lua/ltex.lua
Please, remember to change $NVIM_HOME to your path, I define a global one in my shell startup, maybe you need to change it to fit your needs.

Is it support multiple languages?

yes, it supports, if you define them in the file I use normally with english / portuguese / french, remember to change language with will be checking, you have to generate a configuration changed request with LSP.

@lbiaggi
Copy link
Author

lbiaggi commented Aug 23, 2021

Sure,
Enter or neovim home, something like below and download this gist, it is important to create the files where the actions will save exceptions and dict words!, remember to modify the gist to your language.

$ cd $NVIM_HOME
$ mkdir spells && touch spells/diciotionary.txt && touch spells/false.txt && touch spells/disable.txt
$ mkdir lua && cd lua
$ wget https://gist.github.com/lbiaggi/a3eb761ac2fdbff774b29c88844355b8/raw/332d30269e7f009e04e27ea58d1cd7c876af07a5/ltex.lua
$ sed -i s/pt-BR/'YOURLANG'/g ltex.lua

In your config.lua / init.vim load it after loading nvim-lspconfig...
require('ltex') or silent luafile ~/$NVIM_HOME/lua/ltex.lua
Please, remember to change $NVIM_HOME to your path, I define a global one in my shell startup, maybe you need to change it to fit your needs.

Made every step but had en error Error detected while processing /home/user/.config/nvim/init.vim
E5108: Error executing lua /home/user/.config/nvim/lua/ltex.lua:21: attempt to index local 'f' (a ni l value)

What I did wrong? ltex-ls is executable and located in PATH...

I really don't know

@VolkovIlia
Copy link

Is your global $NVIM_HOME ="/home/user/.config/nvim" ?

@lbiaggi
Copy link
Author

lbiaggi commented Aug 25, 2021

No, but yours can be. I define it

@VolkovIlia
Copy link

VolkovIlia commented Aug 25, 2021

Ok :)

I used this file instead of yours from your guide and now nvim works without errors, but lsp-server still not starting. LspInfo says: filetype: No filetypes defined, please define filetypes in setup().
Where I should to define filetypes, can you share the example?

My init.vim code for your lsp is:

lua << EOF
require('ltex')
EOF

@lbiaggi
Copy link
Author

lbiaggi commented Aug 25, 2021

Ok :)

I used this file instead of yours from your guide and now nvim works without errors, but lsp-server still not starting. LspInfo says: filetype: No filetypes defined, please define filetypes in setup().
Where I should to define filetypes, can you share the example?

My init.vim cod for your lsp is:

lua << EOF
require('ltex')
EOF

the mentioned file is my PR which still a WIP
try this:

let g:tex_flavor = "latex"
silent! au FileType tex\
                silent luafile ~/.config/nvim/lua/ltex.lua

@MurdeRM3L0DY
Copy link

you can use vim.fn.stdpath "config" to get neovim's config directory

@lbiaggi
Copy link
Author

lbiaggi commented Nov 26, 2021 via email

@gzagatti
Copy link

I'm trying to disable a few rules in my config. Could you share what the content of spell/disable.txt looks like? I tried to create a file with the following content to disable English spelling:

MORFOLOGIK_RULE_EN

@gzagatti
Copy link

I got it working. The problem is on my side, as I forgot the settings key and was only using ltex.

@barreiroleo
Copy link

Hello there!
I've made a plugin to support code actions (and some extras) in neovim with native LSP.

Handle dictionaries, false positives, and hidden rules in external files like the vscode-ltex plugin. The files are compatible between these plugins (same naming and content).

In the repository I drop some demos: barreiroleo/ltex_extra.nvim. Better name suggestions are welcome.

Thanks in advance to the people who want to try it and give me their opinion. Thanks also @lbiaggi for some ideas that i took from you.

@aghriss
Copy link

aghriss commented Jul 20, 2023

A minimal script to implement _ltex.addToDictionary:
https://gist.github.com/aghriss/90206887fef301febe6d644272bba367

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment