aboutsummaryrefslogtreecommitdiffstats
path: root/spellcheck.lua
blob: 85d6ef9ad90cbe73e78d1e3188c33ef333805fa0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
-- Copyright (c) 2017 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)
if os.execute("type enchant &>/dev/null") then
	module.cmd = "enchant -d %s -a"
elseif os.execute("type aspell &>/dev/null") then
	module.cmd = "aspell -l %s -a"
elseif os.execute("type hunspell &>/dev/null") then
	module.cmd = "hunspell -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)

	if ret ~= 0 then
		return ret, se
	end

	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)

	if orig ~= new then
		file:delete(range)
		file:insert(range.start, new)
	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)
	end
	win:draw()
	return 0
end, "Spellcheck the whole file")

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);
	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)
	end

	win.selection.pos = pos

	win:draw()

	return 0
end, "Spellcheck word")

vis:option_register("spelllang", "string", function(value, toogle)
	module.lang = value
	vis:info("Spellchecking language is now "..value)
	return true
end, "The language used for spellchecking")

return module