Created
October 19, 2024 12:22
-
-
Save rhaberkorn/62996b0c3a9d618f389f5bdb81390e48 to your computer and use it in GitHub Desktop.
Primitive syntax-aware spell checker for the SciTE editor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- This is a spell checker 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment