aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fl.fischer@fau.de>2019-01-27 21:06:37 +0100
committerFlorian Fischer <florian.fl.fischer@fau.de>2019-01-28 04:42:21 +0100
commit9152bd54c6bcaa4afe4f29054c6ec13d7d9c6e82 (patch)
treea408609f928eaa3aa0d224d26d71d18da663c921
parentd80c1d111dbd9008f4ae230c7257faacf0eea220 (diff)
downloadvis-spellcheck-9152bd54c6bcaa4afe4f29054c6ec13d7d9c6e82.tar.gz
vis-spellcheck-9152bd54c6bcaa4afe4f29054c6ec13d7d9c6e82.zip
Redesign spellchecking
Highlightning of misspelled words is accomplished by changing their style to win.STYLE_INFO before each draw (this changes also the color of vis:info messages). To improve the performance only the visible viewport is checked without getting corrections. Misspelled words can be ignored till the editor exits.
-rw-r--r--spellcheck.lua180
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