aboutsummaryrefslogtreecommitdiff
path: root/SciTEStartup.lua
blob: 82a9467c8c8c401687c68e1191d14cdd1e8aec2e (plain)
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
-- Primitive syntax-aware spell checker for the SciTE editor based on aspell.
-- It only requires the aspell CLI tool to be installed, but perhaps it won't work on
-- Windows.
-- You can just copy this into SciTEStartup.lua.
--
-- TODO: Dictionaries should be configurable per file
-- TODO: Support named styles in aspell.styles.lexer?
--
-- The following should be copied into SciTEUser.properties and adapted:
--[[
aspell.enabled=1
# Comma-separated list of dictionaries
aspell.dicts=en_US
# Restrict spell checking to certain lexer styles
aspell.styles.lua=1,2,3

command.name.9.*=Manuall Spell Checking
command.mode.9.*=subsystem:lua,savebefore:no
command.9.*=aspell
command.name.10.*=Toggle Automatic Spell Checking
command.mode.10.*=subsystem:lua,savebefore:no
command.10.*=aspell_toggle
]]

function aspell_toggle()
	props['aspell.enabled'] = props['aspell.enabled'] == '1' and '0' or '1'
	if props['aspell.enabled'] == "1" then
		aspell()
	else
		editor.IndicatorCurrent = 2
		editor:IndicatorClearRange(0, editor.Length)
	end
end

function aspell()
	local styles = props['aspell.styles.'..editor.LexerLanguage]
	local styles_table = {}
	for style in styles:gmatch("%d+") do styles_table[tonumber(style)] = true end

	local in_name = os.tmpname()
	local in_file = io.open(in_name, 'w')
	in_file:write('^')

	-- NOTE: Unfortunately, SCI_GETSTYLEDTEXT (editor:GetStyledText()) is not exposed.
	for pos = 0, editor.Length-1 do
		local c = editor.CharAt[pos] & 0xFF

		if c == 10 then
			-- Each line is prefixed with ^ since ispell/aspell accepts special
			-- commands as well
			in_file:write('\n^')
		else
			local must_spellcheck = styles == "" or styles_table[editor.StyleAt[pos]]
			in_file:write(must_spellcheck and string.char(c) or ' ')
		end
	end

	in_file:close()

	editor.IndicatorCurrent = 2
	editor.IndicStyle[2] = INDIC_SQUIGGLEPIXMAP
	editor:IndicatorClearRange(0, editor.Length)

	local out = io.popen('aspell -d '..props['aspell.dicts']..
				   ' --dont-guess --dont-suggest --byte-offsets -a <'..in_name)

	local line = 0
	for cmd in out:lines() do
		if cmd == "" then -- no more commands on the current line
			line = line + 1
		elseif cmd:sub(1, 1) == "#" then -- word not found
			local word, offset = cmd:match("^. ([^ ]+) (%d+)$")
			editor:IndicatorFillRange(editor:PositionFromLine(line)+offset-1, #word)
		end
	end

	out:close()
	os.remove(in_name)
end

function OnOpen()
	if props['aspell.enabled'] == '0' then return end

	-- Make sure that everything is already styled as we spell check per style:
	editor:Colourise(0, -1)
	aspell()
end

function OnChar(new_chr)
	-- Called on every inserted character
	if props['aspell.enabled'] == '0' then return end

	local wordchars = editor.WordChars

	-- NOTE: new_chr is a string but not Unicode-aware.
	-- FIXME: Even better would be spell checking only chunks of recently styled text.
	if not wordchars:find(new_chr, 1, true) then aspell() end
end