diff options
author | rxi <rxi@users.noreply.github.com> | 2020-04-25 09:42:00 +0100 |
---|---|---|
committer | rxi <rxi@users.noreply.github.com> | 2020-04-25 09:42:00 +0100 |
commit | 1facb7486758d527bbcab2fc2828320e22b4730a (patch) | |
tree | 4d05ab4ccd698d1030e3dfbc6aaa5accf0da1b24 /plugins | |
parent | 676f04945010aeb2ae71325bf2d1d6f336a5e162 (diff) | |
download | lite-xl-plugins-1facb7486758d527bbcab2fc2828320e22b4730a.tar.gz lite-xl-plugins-1facb7486758d527bbcab2fc2828320e22b4730a.zip |
Updated spellcheck plugin
* Improved delayed-highlight of active word
* Added "replace" command
* Added "add-to-dictionary" command
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/spellcheck.lua | 119 |
1 files changed, 115 insertions, 4 deletions
diff --git a/plugins/spellcheck.lua b/plugins/spellcheck.lua index bb6f835..e532012 100644 --- a/plugins/spellcheck.lua +++ b/plugins/spellcheck.lua @@ -2,18 +2,22 @@ local core = require "core" local style = require "core.style" local config = require "core.config" local command = require "core.command" +local common = require "core.common" local DocView = require "core.docview" +local Doc = require "core.doc" config.spellcheck_files = { "%.txt$", "%.md$", "%.markdown$" } config.dictionary_file = "/usr/share/dict/words" +local last_input_time = 0 +local word_pattern = "%a+" local words core.add_thread(function() local t = {} local i = 0 for line in io.lines(config.dictionary_file) do - for word in line:gmatch("%a+") do + for word in line:gmatch(word_pattern) do t[word:lower()] = true end i = i + 1 @@ -32,6 +36,20 @@ local function matches_any(filename, ptns) end +local function active_word(doc, line, tail) + local l, c = doc:get_selection() + return l == line and c == tail and system.get_time() - last_input_time < 0.5 +end + + +local text_input = Doc.text_input + +function Doc:text_input(...) + text_input(self, ...) + last_input_time = system.get_time() +end + + local draw_line_text = DocView.draw_line_text function DocView:draw_line_text(idx, x, y) @@ -44,13 +62,12 @@ function DocView:draw_line_text(idx, x, y) local s, e = 0, 0 local text = self.doc.lines[idx] - local l, c = self.doc:get_selection() while true do - s, e = text:find("%a+", e + 1) + s, e = text:find(word_pattern, e + 1) if not s then break end local word = text:sub(s, e):lower() - if not words[word] and not (l == idx and c == e + 1) then + if not words[word] and not active_word(self.doc, idx, e + 1) then local color = style.spellcheck_error or style.syntax.keyword2 local x1 = x + self:get_col_x_offset(idx, s) local x2 = x + self:get_col_x_offset(idx, e + 1) @@ -60,3 +77,97 @@ function DocView:draw_line_text(idx, x, y) end end + +local function get_word_at_caret() + local doc = core.active_view.doc + local l, c = doc:get_selection() + local s, e = 0, 0 + local text = doc.lines[l] + while true do + s, e = text:find(word_pattern, e + 1) + if c >= s and c <= e + 1 then + return text:sub(s, e):lower(), s, e + end + end +end + + +local function compare_words(word1, word2) + local res = 0 + for i = 1, math.max(#word1, #word2) do + if word1:byte(i) ~= word2:byte(i) then + res = res + 1 + end + end + return res +end + + +command.add("core.docview", { + + ["spell-check:add-to-dictionary"] = function() + local word = get_word_at_caret() + if words[word] then + core.error("\"%s\" already exists in the dictionary", word) + return + end + if word then + local fp = assert(io.open(config.dictionary_file, "a")) + fp:write("\n" .. word .. "\n") + fp:close() + words[word] = true + core.log("Added \"%s\" to dictionary", word) + end + end, + + + ["spell-check:replace"] = function() + local word, s, e = get_word_at_caret() + + -- find suggestions + local suggestions = {} + local word_len = #word + for w in pairs(words) do + if math.abs(#w - word_len) <= 2 then + local diff = compare_words(word, w) + if diff < word_len * 0.5 then + table.insert(suggestions, { diff = diff, text = w }) + end + end + end + if #suggestions == 0 then + core.error("Could not find any suggestions for \"%s\"", word) + return + end + + -- sort suggestions table and convert to properly-capitalized text + table.sort(suggestions, function(a, b) return a.diff < b.diff end) + local doc = core.active_view.doc + local line = doc:get_selection() + local has_upper = doc.lines[line]:sub(s, s):match("[A-Z]") + for k, v in pairs(suggestions) do + if has_upper then + v.text = v.text:gsub("^.", string.upper) + end + suggestions[k] = v.text + end + + -- select word and init replacement selector + local label = string.format("Replace \"%s\" With", word) + doc:set_selection(line, s, line, e + 1) + core.command_view:enter(label, function(text, item) + text = item and item.text or text + doc:replace(function() return text end) + end, function(text) + local t = {} + for _, w in ipairs(suggestions) do + if w:lower():find(text:lower(), 1, true) then + table.insert(t, w) + end + end + return t + end) + end, + +}) + |