diff options
| -rw-r--r-- | spellcheck.lua | 180 |
1 files changed, 113 insertions, 67 deletions
diff --git a/spellcheck.lua b/spellcheck.lua index 85d6ef9..4bb06e4 100644 --- a/spellcheck.lua +++ b/spellcheck.lua @@ -1,93 +1,122 @@ --- Copyright (c) 2017 Florian Fischer. All rights reserved. +-- Copyright (c) 2017-2019 Florian Fischer. All rights reserved. -- Use of this source code is governed by a MIT license found in the LICENSE file. -local module = {} -module.lang = os.getenv("LANG"):sub(0,5) or "en_US" --- TODO use more spellcheckers (aspell/hunspell) +local spellcheck = {} +spellcheck.lang = os.getenv("LANG"):sub(0,5) or "en_US" if os.execute("type enchant &>/dev/null") then - module.cmd = "enchant -d %s -a" + spellcheck.cmd = "enchant -d %s -a" + spellcheck.list_cmd = "enchant -l -d %s -a" +elseif os.execute("type enchant-2 &>/dev/null") then + spellcheck.cmd = "enchant-2 -d %s -a" + spellcheck.list_cmd = "enchant-2 -l -d %s -a" elseif os.execute("type aspell &>/dev/null") then - module.cmd = "aspell -l %s -a" + spellcheck.cmd = "aspell -l %s -a" + spellcheck.list_cmd = "aspell list -l %s -a" elseif os.execute("type hunspell &>/dev/null") then - module.cmd = "hunspell -d %s" + spellcheck.cmd = "hunspell -d %s" + spellcheck.list_cmd = "hunspell -l -d %s" else return nil end -function spellcheck(file, range) - local cmd = module.cmd:format(module.lang) - local ret, so, se = vis:pipe(file, range, cmd) +spellcheck.enabled = {} - if ret ~= 0 then - return ret, se +local ignored = {} + +local last_viewport, last_typos = nil, nil + +vis.events.subscribe(vis.events.WIN_HIGHLIGHT, function(win) + if not spellcheck.enabled[win] or not win:style_define(win.STYLE_INFO, "fore:red") then + return false end + local viewport = win.viewport + local viewport_text = win.file:content(viewport) - local word_corrections = so:gmatch("(.-)\n") - -- skip header line - word_corrections() - - local orig = file:content(range) - local new = orig:gsub("%S+", function(w) - local correction = word_corrections() - -- empty correction means a new line in range - if correction == "" then - correction = word_corrections() - end - if correction and correction ~= "*" then - -- get corrections - local orig, pos, sug = correction:match("& (%S+) %d+ (%d+): (.*)") - if not orig then - orig = correction:match("# (%S+).*") - vis:info("No correction availlable for " .. orig .. ".") - end - if orig ~= w then - orig = orig or "nil" - vis:message("Bad things happend!! Correction: " .. orig .. " is not for " .. w) - return w - end - -- select a correction - local cmd = 'printf "' .. sug:gsub(", ", "\\n") .. '\\n" | vis-menu' - local f = io.popen(cmd) - correction = f:read("*all") - -- trim correction - correction = correction:match("%S+") - f:close() - if correction then - return correction - end - end - end) + local typos = "" - if orig ~= new then - file:delete(range) - file:insert(range.start, new) + if last_viewport == viewport_text then + typos = last_typos + else + local cmd = spellcheck.list_cmd:format(spellcheck.lang) + local ret, so, se = vis:pipe(win.file, viewport, cmd) + if ret ~= 0 then + vis:message("calling " .. cmd .. " failed ("..se..")") + return false + end + typos = so end -end -vis:map(vis.modes.NORMAL, "<C-w>a", function(keys) - local win = vis.win - local file = win.file - ret, err = spellcheck(file, { start=0, finish=file.size }) - if ret then - vis:info(err) + local corrections_iter = typos:gmatch("(.-)\n") + -- skip header line + corrections_iter() + local index = 0 + for typo in corrections_iter do + if not ignored[typo] then + local start, finish = viewport_text:find(typo, index, true) + win:style(win.STYLE_INFO, viewport.start + start - 1, viewport.start + finish) + index = finish + end end - win:draw() + + last_viewport = viewport_text + last_typos = typos + return true +end) + +vis:map(vis.modes.NORMAL, "<C-w>e", function(keys) + spellcheck.enabled[vis.win] = true + return 0 +end, "Enable spellchecking in the current window") + +vis:map(vis.modes.NORMAL, "<C-w>d", function(keys) + spellcheck.enabled[vis.win] = nil + -- force new highlight + vis.win:draw() return 0 -end, "Spellcheck the whole file") +end, "Disable spellchecking in the current window") vis:map(vis.modes.NORMAL, "<C-w>w", function(keys) local win = vis.win local file = win.file - local pos = win.selection.pos if not pos then return end - local range = file:text_object_word(pos > 0 and pos-1 or pos); + local range = file:text_object_word(pos); if not range then return end if range.start == range.finish then return end - ret, err = spellcheck(file, range) - if ret then - vis:info(err) + local cmd = spellcheck.cmd:format(spellcheck.lang) + local ret, so, se = vis:pipe(win.file, range, cmd) + if ret ~= 0 then + vis:message("calling " .. cmd .. " failed ("..se..")") + return false + end + + local suggestions = nil + local answer_line = so:match(".-\n(.-)\n.*") + local first_char = answer_line:sub(0,1) + if first_char == "*" then + vis:info(file:content(range).." is correctly spelled") + return true + elseif first_char == "#" then + vis:info("No corrections available for "..file:content(range)) + return false + elseif first_char == "&" then + suggestions = answer_line:match("& %S+ %d+ %d+: (.*)") + else + vis:info("Unknown answer: "..answer_line) + return false + end + + -- select a correction + local cmd = 'printf "' .. suggestions:gsub(", ", "\\n") .. '\\n" | vis-menu' + local f = io.popen(cmd) + local correction = f:read("*all") + f:close() + -- trim correction + correction = correction:match("%S+") + if correction then + win.file:delete(range) + win.file:insert(range.start, correction) end win.selection.pos = pos @@ -95,12 +124,29 @@ vis:map(vis.modes.NORMAL, "<C-w>w", function(keys) win:draw() return 0 -end, "Spellcheck word") +end, "Correct missspelled word") + +vis:map(vis.modes.NORMAL, "<C-w>i", function(keys) + local win = vis.win + local file = win.file + local pos = win.selection.pos + if not pos then return end + local range = file:text_object_word(pos); + if not range then return end + if range.start == range.finish then return end + + ignored[file:content(range)] = true + + win:draw() + return 0 +end, "Ignore missspelled word") vis:option_register("spelllang", "string", function(value, toogle) - module.lang = value + spellcheck.lang = value vis:info("Spellchecking language is now "..value) + -- force new highlight + last_viewport = nil return true end, "The language used for spellchecking") -return module +return spellcheck |
